Puppet : file resource only if file exists - puppet

What I want to do is quite simple :
1.
Copy /source/file to /target/file. I achieve this using the following:
file { 'my_file_copy':
ensure => file,
source => 'file:/source/file',
path => "/target/file",
}
2.
However, if file /source/file does not exist, I do NOT want it to perform this task.
I am really struggling with this logic. I attempted the solution below but it throws exceptions during puppet run.
puppet: if one file exists then copy another file over
Is there a better way of achieving this task ?
Ideally, I would like to only use "file" and avoid using "exec". But at this point I would settle for a solution !

Because Puppet is a declarative language where only the end-state is declared, imperative logic such as what you've described - if A, do X - is often hard to express.
Personally, I would try to simply avoid this requirement of having file B copied if and only if file A exists. Often there's a better way.
If the requirement needs to stay, however, then use of Exec here sounds like a pretty good option to me.
exec { 'my_file_copy':
command => 'cp /source/file /target/file',
onlyif => 'test -e /source/file',
creates => '/target/file',
path => '/bin',
}

You could use this logic:
$file = "/source/file"
exec { "chk_${file}_exist":
command => "true",
path => ["/usr/bin","/usr/sbin", "/bin"],
onlyif => "test -f ${file}"
}
file {"/target/file":
ensure => file,
source => 'file:/source/file',
owner => 'root',
group => 'root',
mode => '0750',
require => Exec["chk_${file}_exist"],
}

Related

Puppet tries to rename sites-avaialbe folder

I am running Puppet on staging server, for some reasons puppet starts trying removing sites-available folder and I have no idea why. Any hint will be helpful.
Error: Could not set 'file' on ensure: Is a directory # rb_file_s_rename - (/etc/nginx/sites-available20180808-12536-11p54v, /etc/nginx/sites-available) at 12:/etc/puppet/modules/nginx/manifests/vhost.pp
Error: Could not set 'file' on ensure: Is a directory # rb_file_s_rename - (/etc/nginx/sites-available20180808-12536-11p54v, /etc/nginx/sites-available) at 12:/etc/puppet/modules/nginx/manifests/vhost.pp
Code:
define nginx::vhost($docroot, $port = 80, $template = 'nginx/vhost_php.erb', $allow = [], $deny = [], $aliases = [])
{
include nginx
file { "/etc/nginx/sites-available/${name}":
owner => 'root',
group => 'root',
mode => 644,
content => template($template),
require => Package['nginx'],
notify => Service['nginx'],
}
file { "/etc/nginx/sites-enabled/${name}":
ensure => 'link',
target => "/etc/nginx/sites-available/${name}",
require => File["/etc/nginx/sites-available/${name}"],
notify => Service['nginx'],
}
}
As #MattSchuchard remarked in comments, the error messages show that Puppet thinks you've asked it to convert a directory into a file. Furthermore, it appears to be associating that action with the first File resource in your manifest, which declares
file { "/etc/nginx/sites-available/${name}":
# ...
}
You will note that that resource appears to be trying to manage a file inside the directory, rather than the directory itself, but that discrepancy would be resolved if the automagic $name variable happened to take an empty string as its value. That's what I presume is happening.
You don't show the relevant declaration(s) of the nginx::vhost resources, but I think you'll find that the problem is there. The (slightly) broader context of those error messages would probably confirm this diagnosis: it normally contains a path-like specification of the resource in which the error occurred, and that would include the relevant resource title.

How to change the contents of a file by using Puppet?

I have a html file and I want to use Puppet to replace that file with an empty file with the same filename. I am wondering if it is possible for Puppet to delete the whole contents of a file?
E.g. Is this a correct way to delete a line in Puppet?
file_line { 'delete a line':
ensure => absent,
path => /tmp/test,
line => '\ '
match => '^(?:.*)'
}
If you know there is a file /path/to/file.html and you want to ensure that that file exists and is empty, it's easy:
file { '/path/to/file.html':
ensure => file,
content => '',
}
If you want to ensure that a line in that file is removed using file_line, you have two ways of doing this when ensure => absent is set.
One is to set match => ... and match_for_absence => true,
as in the following example:
file_line { 'bashrc_proxy':
ensure => absent,
path => '/etc/bashrc',
match => '^export\ HTTP_PROXY\=',
match_for_absence => true,
}
In this code example match will look for a line beginning with export
followed by HTTP_PROXY and delete it. If multiple lines match, an
error will be raised unless the multiple => true parameter is set.
Note that the line => ... parameter would be accepted but ignored in
the above example.
The second way of using ensure => absent is to specify a line => ...,
and no match:
file_line { 'bashrc_proxy':
ensure => absent,
path => '/etc/bashrc',
line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128',
}
Note that when ensuring lines are absent this way, the default behavior
this time is to always remove all lines matching, and this behavior
can't be disabled.
See also in the code here and here and in the unit tests.
I have also raised a pull request to add these examples of file_line into the official docs here, as this was not adequately documented before.
Thanks for the question.

How to Refer create_resource in puppet like we do for File[""], Service[""], Package[""], etc

I have a puppet file with an exec resource and create_resources function. I want create_resources to be executed right after the exec resource. How do I do this?
Similar to referencing File['name'], I tried Create_Resources[....] with notify, but it is not working.
notify => Create_Resources[domain_ip_map, $data, $baseconfigdir].
init.pp
exec { 'purge-config-files':
before => [File["${config_file_service}"], File["${config_file_host}"]],
command => "/bin/rm -f ${baseconfigdir}/*",
#notify => Create_Resources[domain_ip_map, $data, $baseconfigdir],
}
create_resources(domain_ip_map, $data)
For the dependency metaparameters require, before, subscribe, and notify, the attributes must be resource types. Specifying notify => Create_Resources[domain_ip_map, $data, $baseconfigdir], means you are attempting to specify the output of the create_resources function as the resources. That is not going to be an acceptable type for that parameter.
There are two different ways to go about this. You can either add a notify or a subscribe.
With the subscribe, you would need to add:
subscribe => Exec['purge-config-files'],
everywhere necessary into the $data hash that contains your domain_ip_map resources' parameters and attributes.
With the notify, you would need to assemble the array of resource titles like the following (assuming using stdlib):
$domain_ip_map_titles = keys($data)
and then put that in your exec resource instead like this:
exec { 'purge-config-files':
before => [File["${config_file_service}"], File["${config_file_host}"]],
command => "/bin/rm -f ${baseconfigdir}/*",
notify => Domain_ip_map[$domain_ip_map_titles],
}
create_resources(domain_ip_map, $data)
Either of those will work for your situation.

Puppet; Call another .pp

So I am using the https://forge.puppetlabs.com/pdxcat/nrpe module to try to figure out automation of NRPE across hosts.
One of the available usages is
nrpe::command {
'check_users':
ensure => present,
command => 'check_users -w 5 -c 10';
}
Is there anyway to make a "group" of these commands and have them called on specific nodes?
For example:
you have 5 different nrpe:command each defining a different check, and then call those specific checks?
I am basically trying to figure out if I could group certain checks/commands together instead of setting up a ton of text in the main sites.pp file. This would also allow for customized templates/configurations across numerous nodes.
Thanks!
EDIT:
This is the command and what it's supposed to do when called on with the 'check_users' portion. If I could have a class with a set of "nrpe:command" and just call on that class THROUGH the module, it should work. Sorry, though. Still new at puppet. Thanks again.
define nrpe::command (
$command,
$ensure = present,
$include_dir = $nrpe::params::nrpe_include_dir,
$libdir = $nrpe::params::libdir,
$package_name = $nrpe::params::nrpe_packages,
$service_name = $nrpe::params::nrpe_service,
$file_group = $nrpe::params::nrpe_files_group,
) {
file { "${include_dir}/${title}.cfg":
ensure => $ensure,
content => template('nrpe/command.cfg.erb'),
owner => root,
group => $file_group,
mode => '0644',
require => Package[$package_name],
notify => Service[$service_name],
}
}
What version are you talking about? In puppet latest versions, inheritance is deprecated, then you shouldn't use it.
The easiest way would be to use "baselines".
Assuming you are using a manifests directory (manifest = $confdir/manifests inside your puppet.conf), simply create a $confdir/manifests/minimal.pp (or $confdir/manifests/nrpe_config.pp or whatever class name you want to use) with the content below:
class minimal {
nrpe::command { 'check_users':
ensure => present,
command => 'check_users -w 5 -c 10',
}
}
Then just call this class inside your node definitions (let's say in $confdir/manifests/my_node.pp) :
node 'my_node.foo.bar' {
include minimal
}

Instantiating a class for each item in an array

Puppet Version: 3.2.4 (Puppet Enterprise 3.0.1)
In order to better support nagios cfg_dir and cfg_file directives in the config file, I've created the following class(es), one for each option:
# Class to add a cfg_dir to the nagios configuration file
class nagios::server::cfg_dir (
$config_dir,
$nagios_user,
$nagios_group,
$nagios_config_file = '/etc/nagios3/nagios.cfg',
)
{
# Build the config dir
file {$config_dir:
ensure => directory,
owner => $nagios_user,
group => $nagios_group,
mode => '0750',
}
# Append cfg_dir=$config_dir path to nagios.cfg file
augeas { "cfg_dir=$config_dir in $nagios_config_file":
incl => "$nagios_config_file",
lens => 'NagiosCfg.lns',
changes => "set cfg_dir/[last()+1] ${config_dir}",
require => File[$nagios_config_file],
}
}
Trying to use this construct inside nagios::server, I have this:
# Set up config directories
each($cfg_dir) |$x| {
class { 'nagios::server::cfg_dir':
config_dir => $x,
nagios_user => $nagios_user,
nagios_group => $nagios_group,
nagios_config_file => $nagios_config_file,
}
}
Which should, in theory, execute the class instantiation for each path passed in to the nagios::server class like so:
class{'::nagios::server': cfg_dir => ['/etc/nagios.d','/etc/nagios/objects'] }
However, I run into this issue:
Error: Could not match |$x| at /tmp/vagrant-puppet-1/modules-2/nagios/manifests/server.pp:181 on node localhost.localdomain
Can someone provide a working example of each in use? Am I expecting too much from this built-in puppet function?
Aside from a few of the code grammar issues above, I've found that this construct is only evaluated in the future parser:
puppet apply --parser=future --modulepath ...
http://docs.puppetlabs.com/puppet/latest/reference/experiments_lambdas.html
Still getting past other dependency issues. What pattern would I use to support this with the current parser instead of future? A custom function?
The answer to my follow-up question is to use defined types:
http://docs.puppetlabs.com/learning/definedtypes.html
Simply changing the above code from a class to a define and assign $config_dir the value from $target,
define nagios::server::cfg_dir (
$config_dir = $target,
$nagios_user,
$nagios_group,
$nagios_config_file = '/etc/nagios3/nagios.cfg',
){...
you can use constructs such as:
nagios::server::cfg_dir { '/etc/nagios.d/', '/etc/nagios/objects':
nagios_user => 'nagios',
nagios_group => 'nagios'
}
This solves the issue for me.

Resources