Set default param value based on another param

48 views
Skip to first unread message

Jody Des Roches

unread,
Oct 5, 2018, 11:20:51 AM10/5/18
to Puppet Users
I'd like to set default values for parameters that will be passed to epp templates.  However, the default value is based on another parameter.  I understand that variables are immutable but this is a parameter that shouldn't be touched unless it wasn't set.

Here is an example construct with a few of my syntax attempts.

class myClass (
String $base_dir,
Optional[String] $conf_dir,
) {
#Attempt 1: Failed
if $myClass::conf_dir == undef { $myClass::conf_dir = "$myClass::base_dir/conf" }

#Attempt 2: Failed
if !$myClass::conf_dir { $myClass::conf_dir = "$myClass::base_dir/conf" }

#Attempt 3: Failed
unless $myClass::conf_dir { $myClass::conf_dir = "$myClass::base_dir/conf" }
}

Dan White

unread,
Oct 6, 2018, 12:16:06 PM10/6/18
to Puppet Users Mailing List
You need to do like this:

class myClass (
String $base_dir,
Optional[String] $conf_dir,
) {
if $myClass::conf_dir == undef {
$myClass::actual_conf_dir = "$myClass::base_dir/conf”
} else {
$myClass::actual_conf_dir = $myClass::conf_dir
}

… and then use $myClass::actual_conf_dir in the template
> --
> 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/8e2db8c1-7353-4360-adc5-00713e1c0214%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Henrik Lindberg

unread,
Oct 7, 2018, 5:35:29 AM10/7/18
to puppet...@googlegroups.com
If you are on a reasonably modern Puppet version you should do it like this:

class myclass(
String $base_dir,
Optional[String] $conf_dir = "${base_dir}/conf"
) {
}

I tested it as well:

class myclass(
String $base_dir,
Optional[String] $conf_dir = "${base_dir}/conf"
) {
notice "base_dir = ${base_dir}, conf_dir = ${conf_dir}"
}
class { myclass: base_dir => 'yay' }

With the result:

Notice: Scope(Class[Myclass]): base_dir = yay, conf_dir = yay/conf

And when executed like this:

class myclass(
String $base_dir,
Optional[String] $conf_dir = "${base_dir}/conf"
) {
notice "base_dir = ${base_dir}, conf_dir = ${conf_dir}"
}
class { myclass: base_dir => 'yay', conf_dir => 'not yay' }

The result is:

Notice: Scope(Class[Myclass]): base_dir = yay, conf_dir = not_yay

Which I think is what you wanted.

If the logic you need for coming up with a default value is complex, it
can be written as a function to which you present the input as
arguments. The above could have been written:

function mymodule::conf_default(String $base) { "${base}/conf" }
class myclass(
String $base_dir,
Optional[String] $conf_dir = mymodule::conf_default($base_dir)
) {
}

Which for the case you showed is total overkill, but good to know if
you need something more complex in another place in your code.

Hope this helps.
Best,
- henrik
--

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

Jody Des Roches

unread,
Oct 7, 2018, 9:47:56 PM10/7/18
to puppet...@googlegroups.com
Thank you Dan and Henrik for taking the time to help.  
Henrik, your solution is what I am using in concert with common.yaml to add a default to the base_dir value.

Mahalo!
-Jody

Dan White

unread,
Oct 7, 2018, 9:59:26 PM10/7/18
to puppet...@googlegroups.com
I like Henrik’s solution better than mine.
I have been dealing with old versions of Puppet for too long.

Eirik Øverby

unread,
Oct 8, 2018, 2:44:36 AM10/8/18
to puppet...@googlegroups.com
Hi,

Sorry for hijacking this thread, but it caught my interest.

My scenario is that I'd like to re-use the title of an nginx server instance in, say, the log file for that server instance. However, since I don't want to touch the nginx module itself, it seems I have to wrap its server class in one of my own to allow setting this kind of defaults - but I have found no way to use $title in this way.

The best would be if I could do something like this - assuming nginx::server is a module class already defined:
nginx::server {
default:
$access_log => "${nginx::logdir}/${mytitle}.log",
...,
;
'my-fine-443-server':
listen_port => 443,
;
}

Here it would also be helpful if I could somehow re-use the default values in the individual instances too - I might not know what the default values are, but I would know what to do with them (append '.log' for instance, or set listen_port to the same value as ssl_port or vice versa).

Even being able to do the following would be better than what we're currently doing, which is repeating the fully-typed access log line (and all the other similar entries) for every instance:
nginx::server { 'my-fine-443-server':
$access_log => "${nginx::logdir}/${mytitle}.log",
listen_port => 443,
}

Not sure how I could use functions here either, as I want this to happen at instantiation time, not in the module itself.

Am I hoping for too much? Missed something?

/Eirik
> To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/ppcjse%24qmf%241%40blaine.gmane.org.

Henrik Lindberg

unread,
Oct 8, 2018, 11:05:29 AM10/8/18
to puppet...@googlegroups.com
On 2018-10-08 08:44, Eirik Øverby wrote:
> Hi,
>
> Sorry for hijacking this thread, but it caught my interest.
>
> My scenario is that I'd like to re-use the title of an nginx server instance in, say, the log file for that server instance. However, since I don't want to touch the nginx module itself, it seems I have to wrap its server class in one of my own to allow setting this kind of defaults - but I have found no way to use $title in this way.
>
> The best would be if I could do something like this - assuming nginx::server is a module class already defined:
> nginx::server {
> default:
> $access_log => "${nginx::logdir}/${mytitle}.log",
> ...,
> ;
> 'my-fine-443-server':
> listen_port => 443,
> ;
> }
>
> Here it would also be helpful if I could somehow re-use the default values in the individual instances too - I might not know what the default values are, but I would know what to do with them (append '.log' for instance, or set listen_port to the same value as ssl_port or vice versa).
>
> Even being able to do the following would be better than what we're currently doing, which is repeating the fully-typed access log line (and all the other similar entries) for every instance:
> nginx::server { 'my-fine-443-server':
> $access_log => "${nginx::logdir}/${mytitle}.log",
> listen_port => 443,
> }
>
> Not sure how I could use functions here either, as I want this to happen at instantiation time, not in the module itself.
>
> Am I hoping for too much? Missed something?
>

I have a bit of a hard time following this. You say assuming
"nginx::server" is a class, but then it looks like it is a resource
since it is instantiated with a title. Also don't understand what
$mytitle is - is that supposed to be $title ?

(so, having complained ;-) some more perhaps useful tips follows...)

If you configure defaults for what you are wrapping via hiera, you can
lookup the defaults in your wrapper.

If you want to assign multiple things at once. Here is an example:

class original($foo, $bar, $etc) { }
class { 'original':
foo => 10,
bar => 20,
etc => 30,
}
// multi-assign from declared class, assigns all variables on the left
// from the class - variables must exist in the class or an error is
// raised
[$foo, $bar, $etc] = Class['original']
notice "${foo}, ${bar}, ${etc}"


There are tickets with a feature request to be able to say things like
"my class takes the exact same parameters as some other class". We do
not have an idea for what that would look like at this point. There is a
Like[T] data type in the process of being added, but it would need to
(very tediously) be repeated for every parameter. New syntax in the
language would be needed to support this a better way (i.e. very long
fuse on that...)

Best advice; be explicit about defaults, and get them via hiera and use APL.

Hope something of this is of value.

Best,
- henrik

Eirik Øverby

unread,
Oct 10, 2018, 11:15:40 AM10/10/18
to puppet...@googlegroups.com
On 8 Oct 2018, at 17:05, Henrik Lindberg <henrik....@puppet.com> wrote:
>
> On 2018-10-08 08:44, Eirik Øverby wrote:
>> Hi,
>> Sorry for hijacking this thread, but it caught my interest.
>> My scenario is that I'd like to re-use the title of an nginx server instance in, say, the log file for that server instance. However, since I don't want to touch the nginx module itself, it seems I have to wrap its server class in one of my own to allow setting this kind of defaults - but I have found no way to use $title in this way.
>> The best would be if I could do something like this - assuming nginx::server is a module class already defined:
>> nginx::server {
>> default:
>> $access_log => "${nginx::logdir}/${mytitle}.log",
>> ...,
>> ;
>> 'my-fine-443-server':
>> listen_port => 443,
>> ;
>> }
>> Here it would also be helpful if I could somehow re-use the default values in the individual instances too - I might not know what the default values are, but I would know what to do with them (append '.log' for instance, or set listen_port to the same value as ssl_port or vice versa).
>> Even being able to do the following would be better than what we're currently doing, which is repeating the fully-typed access log line (and all the other similar entries) for every instance:
>> nginx::server { 'my-fine-443-server':
>> $access_log => "${nginx::logdir}/${mytitle}.log",
>> listen_port => 443,
>> }
>> Not sure how I could use functions here either, as I want this to happen at instantiation time, not in the module itself.
>> Am I hoping for too much? Missed something?
>
> I have a bit of a hard time following this. You say assuming "nginx::server" is a class, but then it looks like it is a resource since it is instantiated with a title. Also don't understand what $mytitle is - is that supposed to be $title ?

Clearly I got up too early this morning. Of course nginx::server is a resource, and I want to instantiate a whole bunch of them. And what I mean with $mytitle is exactly that - the $title of the instantiated resource. So in this case I would like to say that the log file name is a product of the instantiated resource's title, which means I can create a lot of them following "my-fine-443-server", and they'd all have log file names based on the resource title. In this case, my-fine-443-server would have (in our world) /var/log/nginx/my-fine-443-server.access.log. A "my-less-fine-8443-server" instance would then get /var/log/nginx/my-less-fine-8443-server.access.log, and so on and so forth.

Taking this example a bit further (correcting for some syntax errors in my original sample above):

nginx::server {
default:
access_log => "${nginx::logdir}/${title}.log",
ssl_port => $listen_port,
...,
;
'my-fine-443-server':
listen_port => 443,
;
}

$title would normally refer to the class in which I create these resources, so that variable is useless. Similarly, the $listen_port in the default: section is not yet specified - but I'd prefer not to have to type it for each instance since it's just the nginx module that for some reason requires me to specify both - but they'll always be the same value.

We use hiera for a lot of our defaults, but these are context-specific defaults that cannot be set in hiera - and strictly I mostly want them for style and reduced duplication of code (with associated risks of mistakes when creating dozens of server or location resources).

.........

> Best advice; be explicit about defaults, and get them via hiera and use APL.

We're using hiera a *lot*. I guess part of the problem is that our environment(s) isn't (aren't) as homogenous as we would like (to think they are)..

Thanks for your attempts to understand me :)

/Eirik

comport3

unread,
Oct 11, 2018, 1:34:10 PM10/11/18
to Puppet Users
Hi Eirik,

I think I understand what you want to do - set some sensible defaults, and just get the most specific or unique parameters from Hiera.

This article by RIP helped me a lot to understand how to do that: https://www.devco.net/archives/2015/12/16/iterating-in-puppet.php ' wildcard and defaults'.

I use this in a Profile class to do exactly what you want to do.

Reply all
Reply to author
Forward
0 new messages