Passing undef as argument to classes & defines overrides default parameter

69 views
Skip to first unread message

Cristian Falcas

unread,
Jul 16, 2014, 3:33:42 PM7/16/14
to puppet...@googlegroups.com
Hello,

Does anybody know if the issue from
I'm having the same problem with puppet 3.6.2

Best regards,
Cristian Falcas

jcbollinger

unread,
Jul 17, 2014, 11:39:56 AM7/17/14
to puppet...@googlegroups.com


On Wednesday, July 16, 2014 2:33:42 PM UTC-5, Cristian Falcas wrote:
Hello,

Does anybody know if the issue from


The issue tracker says it was.  I haven't heard any other commentary or questions suggesting otherwise.

 
I'm having the same problem with puppet 3.6.2


Perhaps there was a regression, but are you certain the behavior you see is the same as that described in redmine issue 16221?  Can you provide example code?


John
 

Cristian Falcas

unread,
Jul 17, 2014, 2:27:03 PM7/17/14
to puppet...@googlegroups.com
Hi,

I have a "postfix" class with this init:

class postfix (
  $ensure             = 'latest',
  $email_user         = undef,
  $email_pass         = undef,
  $smtp_endpoint      = "smtp.${::domain}",
  $smtp_endpoint_port = '25',
  $from_domain        = $::domain,
  $from_user          = 'donotreply',
  $debug              = false) {
  anchor { 'postfix::begin': }
  anchor { 'postfix::end': }

  include postfix::install
  include postfix::config
  include postfix::service

  Anchor['postfix::begin'] ->
  Class['postfix::install'] ->
  Class['postfix::config'] ~>
  Class['postfix::service'] ->
  Anchor['postfix::end']
}


And I call it from an other module like this:

  class { 'postfix':
    email_user         => hiera('email_user', undef),
    email_pass         => hiera('email_pass', undef),
    smtp_endpoint      => hiera('email_smtp_endpoint', undef),
    smtp_endpoint_port => hiera('smtp_endpoint_port', undef),
    from_domain        => hiera('email_from_domain', undef),
    from_user          => hiera('email_from_user', undef),
  }

All parameters that not found in hiera are not initialized with the default values. In the template I use for the config I get only empty values.

Best regards,
Cristian Falcas





--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/1bf9c11b-0403-427a-8cb3-79cf5d6c2907%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

jcbollinger

unread,
Jul 18, 2014, 12:33:05 PM7/18/14
to puppet...@googlegroups.com


That does look a lot like issue 16221, but I'm uncertain whether it's really the same because classes are special, and the way their parameters are bound to them is especially special.  I don't know whether what you are doing should be expected to work or not.

With that said, you seem to be going to a lot of extra effort here.  Automated data binding will do exactly what you appear to want if you change the hiera keys to suit.  Then you can just do

include 'postfix'

, which is better form for most purposes than the resource-like syntax (see the best practices commentary at http://docs.puppetlabs.com/puppet/3/reference/lang_classes.html#include-like-vs-resource-like).  For that to work, the keys must have form <qualified::class::name>::<param_name>, so "postfix::email_user" for example.


John

Cristian Falcas

unread,
Jul 20, 2014, 9:01:39 PM7/20/14
to puppet...@googlegroups.com
Hi,

I have an other question then. I can't manage to use the json backend to do automated data binding (it's working if i choose the yaml backend). I keep all my data in json, only because I like it more then yaml. Should I be able to use the json backend for this also?

Best regards,
Cristian Falcas



--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.

Henrik Lindberg

unread,
Jul 20, 2014, 10:21:30 PM7/20/14
to puppet...@googlegroups.com
This is caused by the undef given to hiera (as the default value) is
transformed to an empty string. This value is then passed on as the
value of the parameter, and the parameter is bound to empty string,
since it is only exactly undef that selects the default over the given
value. The transformation to empty string is dictated by the 3x function
API. (The 4x function API in Puppet 4.0 does not do this).

Thus, for now, you have to do the transformation back to undef yourself.
There is no easy way to do this in the puppet language with the 3x
(current) parser - especially not if an empty string is to be considered
a valid value (i.e. it is difficult to differentiate between the two).
(Or, do what jcbollinger suggests).

If empty strings are not valid and it is ok to always treat them as
undef, then you can write a ruby function that translates the value to
undef (or write a ruby function that calls hiera and modifies the return
value - this to avoid having to wrap each call to hiera in your puppet
logic).

e.g. something like this

Puppet::Parser::Functions::newfunction(
:fix_undef, :type => :rvalue, :arity => 1,
:doc => "transforms '' to undef") do |args|

case args[0]
when ''
nil
else
args[0]
end
end

Then use it like this:

class { 'postfix':
email_user => fix_undef(hiera('email_user', undef)),
email_pass => fix_undef(hiera('email_pass', undef)),
smtp_endpoint => fix_undef(hiera('email_smtp_endpoint', undef)),
smtp_endpoint_port => fix_undef(hiera('smtp_endpoint_port', undef)),
from_domain => fix_undef(hiera('email_from_domain', undef)),
from_user => fix_undef(hiera('email_from_user', undef)),
}

If you want to wrap the hiera function, do this:

Puppet::Parser::Functions::newfunction(
:my_hiera, :type => :rvalue, :arity => -2,
:doc => "transforms '' to undef") do |args|

case function_hiera(args)
when ''
nil
else
args[0]
end
end

And use like this:

email_user => my_hiera('email_user', undef),

And you can continue to elaborate on this implementation so you do not
have to pass undef (i.e. an empty string) and instead supply this value
inside your my_hiera. You can then use another magic value as the
"undef" default that you translate in your function. If you try to give
hiera a default that is truly undefined (i.e. nil), then it will think
it did not find anything and raise an error.

You are probably better off doing what jcbollinger suggested.

- henrik
--

Visit my Blog "Puppet on the Edge"
http://puppet-on-the-edge.blogspot.se/

Atom Powers

unread,
Jul 21, 2014, 1:00:35 AM7/21/14
to puppet...@googlegroups.com

I think you should be able to send json to the yaml backend and it will work. I did some testing with hiera and had no problem with pure yaml, pure json, or a mix of the two.

jcbollinger

unread,
Jul 21, 2014, 9:00:53 AM7/21/14
to puppet...@googlegroups.com


On Monday, July 21, 2014 12:00:35 AM UTC-5, Atom Powers wrote:

I think you should be able to send json to the yaml backend and it will work. I did some testing with hiera and had no problem with pure yaml, pure json, or a mix of the two.


Yes, JSON is more or less a subset of YAML.  I don't recall at the moment what prevents JSON from being a complete subset, the kinds of JSON structures you're likely to want to use for your external data should all be fine.


John



David Schmitt

unread,
Jul 21, 2014, 10:39:39 AM7/21/14
to puppet...@googlegroups.com
JSON can only do simple values (string, number), lists and hashes. YAML
can additionally reference entities across the document (creating loops)
and do all sorts of other nasty things that rubyists found funny to put
into a serialization format.


Regards, David
--
* Always looking for people I can help with awesome projects *
G+: https://plus.google.com/+DavidSchmitt
Blog: http://club.black.co.at/log/
LinkedIn: http://at.linkedin.com/in/davidschmitt

jcbollinger

unread,
Jul 22, 2014, 9:00:52 AM7/22/14
to puppet...@googlegroups.com


On Monday, July 21, 2014 9:39:39 AM UTC-5, David Schmitt wrote:
On 2014-07-21 15:00, jcbollinger wrote:
>
>
> On Monday, July 21, 2014 12:00:35 AM UTC-5, Atom Powers wrote:
>
>     I think you should be able to send json to the yaml backend and it
>     will work. I did some testing with hiera and had no problem with
>     pure yaml, pure json, or a mix of the two.
>
>
> Yes, JSON is more or less a subset of YAML.  I don't recall at the
> moment what prevents JSON from being a complete subset, the kinds of
> JSON structures you're likely to want to use for your external data
> should all be fine.

JSON can only do simple values (string, number), lists and hashes. YAML
can additionally reference entities across the document (creating loops)
and do all sorts of other nasty things that rubyists found funny to put
into a serialization format.



Yes, but that's beside the point.  The question is not what YAML can do that JSON can't, but rather what JSON can do that YAML can't.  YAML 1.2 is intended to be a superset of JSON, but (I had remembered reading) doesn't succeed 100% in that.  It turns out that the difference I was thinking of is that the JSON specs don't actually require mapping keys to be unique (JSON only suggests that keys be unique), whereas YAML does require unique keys (http://yaml.org/spec/1.2/spec.html#id2759572).  In practice, that may be a distinction without a difference.


John

Cristian Falcas

unread,
Jul 23, 2014, 8:32:15 AM7/23/14
to puppet...@googlegroups.com
Hello all,

Regarding my question with automated data binding. Here is how we set this via the yaml backend:

collectd::plugins::write_riemann::riemann_protocol: UDP

We tried to use this with the json backend, but this never gets populated in the class:

{"collectd":
 {"plugins":
  {"write_riemann":{"riemann_protocol": "UDP"}
}}}

Is the format we try to use wrong?

Best regards,
Cristian Falcas




--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.

jcbollinger

unread,
Jul 23, 2014, 4:59:57 PM7/23/14
to puppet...@googlegroups.com


On Wednesday, July 23, 2014 7:32:15 AM UTC-5, Cristian Falcas wrote:
Hello all,

Regarding my question with automated data binding. Here is how we set this via the yaml backend:

collectd::plugins::write_riemann::riemann_protocol: UDP

We tried to use this with the json backend, but this never gets populated in the class:

{"collectd":
 {"plugins":
  {"write_riemann":{"riemann_protocol": "UDP"}
}}}

Is the format we try to use wrong?


Yes.

The '::' in the YAML version are not special to YAML.  In particular, they have no implication of nesting; they are just ordinary characters in that context, so the YAML form expresses a key "collectd::plugins::write_riemann::riemann_protocol" with associated value "UDP", the pair belonging to a (possibly-undelimited) top-level mapping.  The JSON you present is altogether different.

This should work, I think:

"collectd::plugins::write_riemann::riemann_protocol": "UDP"


John

Cristian Falcas

unread,
Jul 25, 2014, 6:02:29 AM7/25/14
to puppet...@googlegroups.com
thank you



--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages