0

In a puppet class how should I test if a variable has been set in a node? I use a VM name (like server1) and a domain name (like example.org) where users can reach the page. "example.org" won't be conveyed via a fact, so I need to pass it via a class parameter. I came up with this way to define the variable in a node block and use it in my test class for my settings.

node "VM1" {
  class { 'test':
    domainname => "example.org",
  }

[...]

class test ($domainname) {
  ini_setting {
    'set_property':
      ensure  => present,
      path    => '/tmp/test.ini',
      section => 'main',
      setting => 'url',
      value   => "https://$domainname";
  }

[...]

But now I want to add a condition that if $domainname isn't set then the $hostname fact should be used in its place.

ini_setting {
    'set_property':
    ensure  => present,
    path    => '/tmp/test.ini',
    section => 'main',
    setting => 'url',
    if $domainname !~ $hostname {
      value   => "https://$domainname";
    } else {
      value   => "https://$hostname";
    }

But now I get an error like this every time:

Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Syntax error at 'domainname'

What should I do instead?

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
B3nny
  • 3
  • 1
  • 4
  • You cannot put `if` style conditional code within a resource. I believe you can put selectors inside a resource attribute value, but it is discouraged. Regardless, you seem like you really want a selector: https://puppet.com/docs/puppet/5.5/lang_conditional.html#selectors. – Matthew Schuchard Sep 12 '18 at 13:03

1 Answers1

1

The error message is explaining to you that if statements cannot appear inside resource declarations. There is, however, a different conditional form, called a "selector" that can appear inside resource declarations. It is Puppet's analog of the ternary ?: operator that appears in several languages.

Stylistically, though, it is usually better form to keep resource declarations as simple as possible. To that end, you should probably set a variable, conditionally, outside the resource declaration, and then use its value inside. Using your own conditional, that might look like this:

  if $domainname !~ $hostname {
    $url_value = "https://$domainname";
  } else {
    $url_value = "https://$hostname";
  }

  ini_setting {
    'set_property':
      ensure  => present,
      path    => '/tmp/test.ini',
      section => 'main',
      setting => 'url',
      value   => $url_value;
  }

Additionally, however, I note that your particular condition, repeated above, is highly suspect. In recent Puppet (version 4 and above), you should be using Puppet data types to both declare your class parameters and check them. In particular, if it is permissible to declare class test without providing a $domainname parameter, then you would declare that class like so:

# Using the Puppet v4+ type system
class test(
  Optional[String] $domainname = undef
) {
  # ...

, and would test whether a value was provided for $domainname like so:

  if $domainname =~ Undef {
    # ...
  }

You cannot use the type system in earlier Puppet, but there you can rely on undefined variables to expand to nothing when you interpolate them:

# Using the Puppet v3- behavior
class test(
  $domainname = undef
) {
  # ...

  if "$domainname" == "" {
    # ...
  }

  # ...
}
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thanks that help me a lot. If i have a mixed infrastructure with Puppet 3 and Puppet 4 should I use the last example or should I check the Puppet version and use for Puppet 4 $domainname =~ Undef and for Puppet 3 $domainname = undef ...? – B3nny Sep 13 '18 at 09:44
  • @B3nny, if your using a master / agent setup, then the master is where this matters. The master should not be older than its client agents, so the approach using the type system should be fine. If you are using `puppet apply` then the version using the type system will not work for the v3 machines, but I *think* the latter approach will work for v4 machines. – John Bollinger Sep 13 '18 at 13:56
  • Is it also possible to use the $url_value in a template file like https://<% @url_value %>. If I do this the variables is empty. – B3nny Sep 13 '18 at 14:15
  • Yes, @B3nny, it should be possible to use the variable in a template. If this is not working for you then I would need to see the details in order to offer any insight. That would best be done by posing a new, separate question containing a [mcve]. – John Bollinger Sep 13 '18 at 14:20