Search code examples
listarraylistindexingpuppet

How to update values dynamically for the individual match sections within sshd config file using puppet


i am able to update the value to the sections "User foo" and "Host *.example.net" by passing the index. If i pass index 1 or 2 the respective value is getting updated.

my code:

$sections = ['Host *.example.net', 'User foo']

$sections.each |String $section| {
  sshd_config_match { "${section}":
    ensure => present,
  }
}

$settings = [['User foo', 'X11Forwarding yes', 'banner none'],['Host *.example.net', 'X11Forwarding no', 'banner none']]
$settings.each |Array $setting| {
  $setting_array = split($setting[1],/ /)
  sshd_config { "${setting_array[0]} ${setting[0]}":
    ensure    => present,
    key       => "${setting_array[0]}",
    condition => "${setting[0]}",
    value     => "${setting_array[1]}",
  }
}

current result:

 Match Host *.example.net
      # Created by Puppet
      X11Forwarding no
     
    Match User foo
      # Created by Puppet
      X11Forwarding yes

Expected results:

Match Host *.example.net
  # Created by Puppet
  X11Forwarding no
  Banner none
Match User foo
  # Created by Puppet
  X11Forwarding yes
  Banner none

i am able to update only one value mentioned in the index but am looking a way to update more or all the values mentioned in the list.


Solution

  • It's not clear what module is providing your sshd_config_match and sshd_config resource types, nor, therefore, exactly what they do. Nevertheless, if we consider this code ...

    $settings = [['User foo', 'X11Forwarding yes', 'banner none'],['Host *.example.net', 'X11Forwarding no', 'banner none']]
    $settings.each |Array $setting| {
      $setting_array = split($setting[1],/ /)
      sshd_config { "${setting_array[0]} ${setting[0]}":
        ensure    => present,
        key       => "${setting_array[0]}",
        condition => "${setting[0]}",
        value     => "${setting_array[1]}",
      }
    }
    

    ... we can see that each element of $settings is a three-element array, of which the each call accesses only those at indexes 0 and 1. That seems to match up with the result you see, which does not contain anything corresponding to the data from the elements at index 2.

    You could iterate over the inner $setting elements, starting at index 1, instead of considering that element only, but I would suggest instead restructuring the data more naturally, and writing code suited to the restructured data. You have data of mixed significance in your arrays, and you are needlessly jamming keys and values together such that you need to spend effort to break them back apart. Structuring the data as a hash of hashes instead of an array of arrays could be a good start:

    $settings = {
      'User foo'           => { 'X11Forwarding' => 'yes', 'banner' => 'none'},
      'Host *.example.net' => { 'X11Forwarding' => 'no',  'banner' => 'none'},
    }
    

    Not only does that give you much enhanced readability (mostly from formatting), but it also affords much greater usability. To wit, although I'm guessing a bit here, you should be able to do something similar to the following:

    $settings.each |String $condition, Hash $properties| {
      $properties.each |String $key, String $value| {
        sshd_config { "${condition} ${key}":
          ensure    => 'present',
          condition => $condition,
          key       => $key,
          value     => $value,
        }
      }
    }
    

    Again, greater readability, this time largely from a helpful choice of names, and along with it greater clarity that something like this is in fact the right structure for the code (supposing that I have correctly inferred enough about the types you are using).