0
votes

I created a configuration in Puppet for Nagios agent (NRPE). Now, I'm trying to set different file sources depending on the existence of dirs. First, I check if a specific directory exists and then set specific file content. My current config files look like:

class nagios_client::file_nagios-check-Linux-stats {

        include nagios_client::check_location_lib-nagios

        file { '/usr/lib/nagios/plugins/check_linux_stats.pl':
        ensure  => file,
        owner   => root,
        group   => root,
        mode    => 755,
        content => template("nagios_client/check_linux_stats.pl.erb"),
        require => Exec["check_usr-lib_exists"],
        }
        file { '/usr/lib64/nagios/plugins/check_linux_stats.pl':
        ensure  => file,
        owner   => root,
        group   => root,
        mode    => 755,
        content => template("nagios_client/check_linux_stats.pl.erb"),
        require => Exec["check_usr-lib64_exists"],
        }
        file { '/usr/lib32/nagios/plugins/check_linux_stats.pl':
        ensure  => file,
        owner   => root,
        group   => root,
        mode    => 755,
        content => template("nagios_client/check_linux_stats.pl.erb"),
        require => Exec["check_usr-lib32_exists"],
        }
    }

This works fine, but I have a problem with this:

class nagios_client::file_nrpe-cfg {

    #    include nagios_client::check_location_lib-nagios

        file { '/etc/nagios/nrpe.cfg.def':
            path    => '/etc/nagios/nrpe.cfg',
            ensure  => file,
            owner   => root,
            group   => root,
            mode    => 644,
            content => template("nagios_client/nrpe-cfg.erb"),
            require => Exec["check_usr-lib_exists"],
        }

        file { '/etc/nagios/nrpe.cfg.32':
            path    => '/etc/nagios/nrpe.cfg',
            ensure  => file,
            owner   => root,
            group   => root,
            mode    => 644,
            content => template("nagios_client/nrpe-cfg-32.erb"),
            require => Exec["check_usr-lib32_exists"],
        }

        file { '/etc/nagios/nrpe.cfg.64':
            path    => '/etc/nagios/nrpe.cfg',
            ensure  => file,
            owner   => root,
            group   => root,
            mode    => 644,
            content => template("nagios_client/nrpe-cfg-64.erb"),
            require => Exec["check_usr-lib64_exists"],
        }
    }

It looks like require => Exec[...] is ignored.

My check definition:

class nagios_client::check_location_lib-nagios {

    exec { 'check_usr-lib_exists':
    command => '/bin/true',
        onlyif  => '/usr/bin/test -d /usr/lib/nagios/plugins',
    }
    exec { 'check_usr-lib32_exists':
        command => '/bin/true',
        onlyif  => '/usr/bin/test -d /usr/lib32/nagios/plugins',
        }
    exec { 'check_usr-lib64_exists':
        command => '/bin/true',
        onlyif  => '/usr/bin/test -d /usr/lib64/nagios/plugins',
    }
}

I'm using Puppet 3.8.7. How to do it in the right way?

1

1 Answers

0
votes

The problem with what you have is that you are using require, which only makes sure that the specified resource (in this case each exec) executes before the file resource. The behavior you want corresponds more closely to notify relationships (which create a refresh event), however, file resources do not care about refresh events. You can read more about refresh relationships here: https://puppet.com/docs/puppet/latest/lang_relationships.html#refreshing-and-notification.

There are 2 possible ways I can think of fixing this. The first one would be to use an exec statement to manage the file, instead of a file resource. This is definitely not optimal, since you lose all of the parameters from the file resource (I definitely do not recommend this approach, but you could).

The other way would be to create a custom ruby fact to check if the files exist. The fact would look something like this:

Facter.add('nagios_directories') do
  confine kernel: 'Linux'

  setcode do
    paths_to_check = [
      '/usr/lib/nagios/plugins',
      '/usr/lib32/nagios/plugins',
      '/usr/lib64/nagios/plugins',
    ]
    paths_to_check.select { |d| File.directory?(d) }
  end
end

This fact would check all the directories listed in the paths_to_check array, and return an array containing the directories that do exist. If none of the directories exist, it would return an empty array.

Once you have that fact set up, you can then rewrite your code like this:

class nagios_client::file_nrpe-cfg {
  if (member($fact['nagios_directories'], '/usr/lib/nagios/plugins')) {
    file { '/etc/nagios/nrpe.cfg.def':
              path    => '/etc/nagios/nrpe.cfg',
              ensure  => file,
              owner   => root,
              group   => root,
              mode    => 644,
              content => template("nagios_client/nrpe-cfg.erb"),
    }
  }

  if (member($fact['nagios_directories'], '/usr/lib32/nagios/plugins')) {
    file { '/etc/nagios/nrpe.cfg.32':
              path    => '/etc/nagios/nrpe.cfg',
              ensure  => file,
              owner   => root,
              group   => root,
              mode    => 644,
              content => template("nagios_client/nrpe-cfg-32.erb"),
    }
  }

  if (member($fact['nagios_directories'], '/usr/lib64/nagios/plugins')) {
    file { '/etc/nagios/nrpe.cfg.64':
      path    => '/etc/nagios/nrpe.cfg',
      ensure  => file,
      owner   => root,
      group   => root,
      mode    => 644,
      content => template("nagios_client/nrpe-cfg-64.erb"),
    }
  }
}

Here is some additional documentation for custom facts: https://puppet.com/docs/facter/3.9/fact_overview.html.

Lastly, if you are using Puppet 6 (currently the latest release), you can write a custom Ruby function and make use of the new deferred type. This type allows you to execute functions on the agent during catalog run time (before this release, all Puppet functions where executed on the Puppet Master at compile time), which means you can use a function to check if a file exists. I have not had a chance to try this feature, but you can view the documentation here: https://puppet.com/docs/puppet/6.0/integrating_secrets_and_retrieving_agent-side_data.html.