Search code examples
puppetpuppetlabs-apache

Elide Puppet parameters based on conditional


I have the following resource declared in a Puppet define. There are some parameters beginning with auth_* that control authentication. I'd like to be able to pass that block of parameters, or not pass them, based on the value of a boolean variable i.e. $use_authentication.

It seems that an if statement won't work here, and I don't think that a "selector" will do so either. Felix Frank had a really useful answer in the very closely related question "conditional within define in puppet", but I don't think that strategy will work here, because the parameters that need to be elided are nested two layers deep.

apache::vhost { "$name-non-ssl":
    servername => $vhost_name,
    docroot => $document_root,
    port => 80,

    access_log_file => 'access.log',
    access_log_format => 'vhost_common',
    error_log_file => 'error.log',

    directories => [
         {path => $document_root,
          auth_type => 'Basic',
          auth_name => "$name",
          auth_user_file => '/somefile.pwd',
          auth_require => 'valid-user',
          rewrites => [
              {
                  comment => "rule1",
                  rewrite_base => "/",
                  rewrite_rule => ['^index\.html$ - [L]']
              },
              {
                  comment => "rule2",
                  rewrite_cond => ['%{REQUEST_FILENAME} !-f', '%{REQUEST_FILENAME} !-d'],
                  rewrite_rule => ['. /index.html [L]']
              }
          ]}
    ],
}

The following gives a syntax error: Syntax error at 'if'; expected '}'

apache::vhost { "$name-non-ssl":
    ... same as previous ...
    directories => [
         {path => $document_root,

          if $use_authentication {
              auth_type => 'Basic',
              auth_name => "$name",
              auth_user_file => '/somefile.pwd',
              auth_require => 'valid-user',
          }

          rewrites => [
              ...same as before...
          ]}
    ],
}

Solution

  • This is tough to handle because you want to dynamically fill in some key/value pairs in a hash that is an element of an array which is a parameter value.

    Option 1: Build the hash outside of the resource declaration

    $auth_settings = {
         auth_type => 'Basic',
         auth_name => "$name",
         auth_user_file => '/somefile.pwd',
         auth_require => 'valid-user',
    }
    $base_dir1 = {path => $document_root,
          rewrites => [
              {
                  comment => "rule1",
                  rewrite_base => "/",
                  rewrite_rule => ['^index\.html$ - [L]']
              },
              {
                  comment => "rule2",
                  rewrite_cond => ['%{REQUEST_FILENAME} !-f', '%{REQUEST_FILENAME} !-d'],
                  rewrite_rule => ['. /index.html [L]']
              }
          ]
    }
    if $use_authentication {
        $real_dir1 = merge($base_dir1, $auth_settings)
    }
    else {
        $real_dir1 = $base_dir1
    }
    
    apache::vhost { "$name-non-ssl":
        servername => $vhost_name,
        docroot => $document_root,
        port => 80,
        access_log_file => 'access.log',
        access_log_format => 'vhost_common',
        error_log_file => 'error.log',
        directories => [ $real_dir1 ],
    }
    

    Granted, it goes a little wild with the variables.

    Option 2: Create a custom function

    Write a function that takes what is $base_dir1 above and the boolean value for $use_authentication, and returns the merged hash if appropriate.

    apache::vhost { "$name-non-ssl":
        servername => $vhost_name,
        docroot => $document_root,
        port => 80,
    
        access_log_file => 'access.log',
        access_log_format => 'vhost_common',
        error_log_file => 'error.log',
    
        directories => [ add_auth($use_authentication, { ... }) ],
    }
    

    Option 3: Inline that

    You can nonchalantly do the merge right in the resource declaration. Use a selector to decide what to merge. Readability is out the window with this one.

    apache::vhost { "$name-non-ssl":
        servername => $vhost_name,
        docroot => $document_root,
        port => 80,
    
        access_log_file => 'access.log',
        access_log_format => 'vhost_common',
        error_log_file => 'error.log',
    
        directories => [ merge({path => $document_root,
          rewrites => [
              {
                  comment => "rule1",
                  rewrite_base => "/",
                  rewrite_rule => ['^index\.html$ - [L]']
              },
              {
                  comment => "rule2",
                  rewrite_cond => ['%{REQUEST_FILENAME} !-f', '%{REQUEST_FILENAME} !-d'],
                  rewrite_rule => ['. /index.html [L]']
              }
          ]
        }, $use_authentication ? {
             true => {
                 auth_type => 'Basic',
                 auth_name => "$name",
                 auth_user_file => '/somefile.pwd',
                 auth_require => 'valid-user',
             },
             default => {}
           }
         )
       ],
    }
    

    I didn't bother testing this monster. Not even sure the braces line up.

    You might get away with a compromise between (1) and (3), but please lean towards the former.