How to check if a directory exists in puppet - puppet

Trying to create an autostart directory on a rpi using puppet. It is supposed to mkdir only if the location doesn't exist.
Here is the current code:
exec { "mkdir_autostart":
command => "mkdir /home/pi/.config/autostart",
unless => "[ -d /home/pi/.config/autostart ]",
path => "/usr/local/bin/:/bin/",
}
Here is what I get:
err: Failed to apply catalog: Parameter unless failed on Exec[mkdir_autostart]:
'[ -d /home/pi/.config/autostart ]' is not qualified and no path was specified.
Please qualify the command or specify a path.
Also tried with onlyif statement, but that generated the same error. What am I doing wrong?
EDIT:
Added path (path => "/usr/local/bin/:/bin/",) and now get:
err: /Stage[main]/auto::Sign/Exec[mkdir_autostart]: Could not evaluate: Could not find command '['

You should use the "file" type:
file { "/home/pi/.config/autostart":
ensure => directory
}
But if for any reason, you want to keep your "exec" type, use test -d /home/pi/.config/autostart

Instead of using unless I'd suggest just adding a -p flag to mkdir:
exec { "mkdir_autostart":
command => "mkdir -p /home/pi/.config/autostart",
path => "/usr/local/bin/:/bin/"
}
Or better yet just use Puppet's file resource type as mentioned above by #sebastien.prudhomme.

Related

How to use multiple onlyif in Puppet Augeas resources?

I am trying to use an Puppet Augeas resource to update the /etc/fstab file. The change should add a mount option, but ONLY if (a) the option is not already there, and (b) the filesystem is present in fstab.
To do this, I am trying to use an array of onlyif tests, as below:
augeas { "fstab-${fsname}-${setting}":
context => '/files',
lens => 'Fstab.lns',
incl => '/etc/fstab',
onlyif => [
"values etc/fstab/*[file='${fsname}']/opt not_include ${setting}",
"match etc/fstab/*[file='${fsname}'] size > 0",
],
changes => [
"insert opt after etc/fstab/*[file='${fsname}']/opt[last()]",
"set etc/fstab/*[file='${fsname}']/opt[last()] ${setting}"
]
}
If the filesystem exists, the this resource will correctly add the option if it does not exist, and will make no change if the option does exist.
However, if the filesystem does not exist in fstab, then I get an error, as it tries to apply the changes anyway which of course fail as there is no match for the insert.
It appears that the changes are being run even though the match size is returning 0. I can verify that by using augtool:
augtool> ls /files/etc/fstab/*[file='/var/tmp']
augtool> ls /files/etc/fstab/*[file='/tmp']
spec = /dev/mapper/vg_OS-lv_tmp
file = /tmp
vfstype = xfs
opt[1] = defaults
opt[2] = noexec
dump = 0
passno = 0
augtool>
Puppet debug logs do not appear to show the onlyif tests being run at all, but also do not show any syntax errors:
Debug: Augeas[fstab-/var/tmp-noexec](provider=augeas): Opening augeas with root /, lens path /opt/puppetlabs/puppet/cache/lib/augeas/lenses, flags 64
Debug: Augeas[fstab-/var/tmp-noexec](provider=augeas): Augeas version 1.12.0 is installed
Debug: Augeas[fstab-/var/tmp-noexec](provider=augeas): Will attempt to save and only run if files changed
Debug: Augeas[fstab-/var/tmp-noexec](provider=augeas): sending command 'insert' with params ["opt", "after", "/files/etc/fstab/*[file='/var/tmp']/opt[last()]"]
Debug: Augeas[fstab-/var/tmp-noexec](provider=augeas): Closed the augeas connection
Error: /Stage[main]/Smx_os_hardening::Filesystem/Augeas[fstab-/var/tmp-noexec]: Could not evaluate: Error sending command 'insert' with params ["opt", "after", "/files/etc/fstab/*[file='/var/tmp']/opt[last()]"]/Error sending command 'insert' with params ["opt", "after", "/files/etc/fstab/*[file='/var/tmp']/opt[last()]"]
The Puppet documentation appears to indicate that the onlyif can be a single test or an array; and, if an array, the tests must ALL be true (IE, use AND rather than OR). This does not appear to match the current behaviour, though.
[update] Note that, when using onlyif with the Exec resource type, multiple tests do work as expected. I am beginning to think that maybe the Augeas resource does not support an array for onlyif
Does anyone have any insight on what I may be doing wrong here?
Puppet server is v6.18 and so is the agent.

Puppet: 'creates' does not create a new file

I would like to run a command, only if a file does not exist.
This is what I tried:
exec { 'test':
command => '/usr/bin/echo Test',
creates => '/etc/test/test-init'
}
But unfortunately this file is not being created. The puppet agent works without throwing an error.
The creates parameter of an Exec does not cause Puppet to create the designated file. Rather it instructs Puppet to use the existence of that file to determine whether the command should be run, on the supposition that the command will create it when it runs.
That's often used with commands that naturally create a file or directory, but you can do it synthetically, too. For example:
exec { 'test':
command => '/usr/bin/echo Test && touch /etc/test/test-init',
creates => '/etc/test/test-init',
provider => 'shell'
}

Copying a file only once in puppet

I am new to puppet, I am trying to copy a file to remote server for installation of a package, This file would get deleted a few minutes after installation. Is there a way to copy this file only once.? like the example below.
class absent_file {
file { '/tmp/hello-file':
ensure => 'present',
replace => 'no',
content => "From Puppet\n",
mode => '0644',
once => true
}
}
So, I have figured out how to do it. Instead of using the file module, I ended up using command and touching another which would not get deleted along with installation process. The key can be deleted but the somefile.txt would be still present and the process would become idempotent.
exec {'add key':
command => "echo 'SharedKeyfile' > /key/location && touch /key/location/somefile.txt'",
onlyif => "test ! -f /key/location/somefile.txt",
}

Chmod directory from other module by puppet

I'm using a 3rd part puppet module which I wish not to change (Tomcat). It creates a directory with mode=644, which I wish to change to 664 (recursively).
When I'm trying this, puppet is unhappy since this resource is already defined in the other module.
file { '/var/lib/tomcat' :
ensure => directory,
mode => 0664,
recurse => true,
}
Any ideas how can I go around this?
You can use the collector syntax to override some attributes for a resource that has already been declared.
File<| title == '/var/lib/tomcat' |> {
mode => '0664'
}
Use this sparingly. Incompatible overrides will still clash, and your manifests become difficult to debug.
The safest approach is to make the attribute a module parameter (by sending an appropriate patch upstream).
You should use the 'exec' resource type.
exec {"chmod -R 664 /var/lib/tomcat":
path => "/bin",
command => "chmod -R 664 .",
cwd => "/var/lib/tomcat"
}
It's the only workaround i found to avoid duplicate resource name
in bash you can use
cd /var/lib
chmod -R 664 Tomcat

Reading from file /etc/resolv.conf and populating in named.conf.options

I'm using puppet to generate my named.conf.options file, in order to do this I'd like it to use the forwarders defined in /etc/resolv.conf. What's the best way of doing this, I've been doing it like this (where named.conf.options.erb contains ) - but this runs constantly.
file { '/etc/bind/named.conf.options':
ensure => present,
content => template('my_template_location/named.conf.options.erb'),
replace => true,
}
->
exec { "add_nameserver":
command => '/bin/sed -i "s/<name_server>/$(grep nameserver/etc/resolv.conf | tr -d [a-z])/g" /etc/bind/named.conf.options',
}
An exec will always run unless it has something to limit it. There are a number of parameters you can set.
In your case, it sounds like you want the exec to run only when your file changes. You might want to use the refreshonly parameter on your exec.
First, change the require arrow to a notify arrow, from -> to ~>. This will cause puppet to refresh the exec whenever the file changes.
Second, add refreshonly => true to your exec. This will cause the exec to only run when it is refreshed by some other resource.
You'll end up with the following:
file { '/etc/bind/named.conf.options':
ensure => present,
content => template('my_template_location/named.conf.options.erb'),
replace => true,
}
~>
exec { "add_nameserver":
command => '/bin/sed -i "s/<name_server>/$(grep nameserver/etc/resolv.conf | tr -d [a-z])/g" /etc/bind/named.conf.options',
refreshonly => true,
}
You can check out some of the other ways to limit an exec on the Puppet Type Reference Page.
You can not get desired state this way because you are modifying the same resource (file /etc/bind/named.conf.options) with two different declarations.
Normally you have to avoid exec resources in Puppet because is difficult to keep state and idempotence while executing "old-school" commands.
So, the best way to get your desired behaviour is to create a custom fact [1] that exposes your nameservers to any resource and then include it in your ERB template.
Facter.add(:nameservers_array) do
setcode do
nameservers = Facter::Core::Execution.exec('grep nameserver/etc/resolv.conf | tr -d [a-z]')
nameservers_array = nameservers.split(" ")
nameservers_array
end
end
You have another example here: https://www.jethrocarr.com/2013/11/05/exposing-name-servers-with-puppet-facts/
[1] https://docs.puppetlabs.com/facter/latest/fact_overview.html

Resources