How to program puppet to extract tarball only if its different - puppet

I want to use puppet to do this :
First puppet run, extract contents of tarball (which is stored on some server)
Subsequent puppet runs, extract contents of the tarball only if the tarball is different from the earlier run
Any suggestions on how to do this in Puppet ? I am struggling with how to use the "onlyif" clause in Puppet to achieve this.

You could do this in just one puppet run with something like:
$filename = 'somefile'
$path = '/somepath'
file { 'filename':
ensure => file,
source => 'file:/<SOMEPATH>/<SOMEFILE>',
path => "${path}/${filename}",
notify => Exec['extract tar'],
}
exec { 'extract tar':
refreshonly => true,
command => "tar --overwrite -xf ${filename}",
path => '/bin',
cwd => $path,
}
But I think using puppet/archive module would be a cleaner solution.

Related

Manage multiple files permissions using puppet

How do I set file permission from list of file names from cat command?
For example, below command returns 3 file names:
$ cat /tmp/test | grep file
/etc/systemd/file_1.log
/etc/systemd/file_2.log
/etc/systemd/file_3.log
How do I use puppet to run the command, get the file names and then loop the 3 file names and set permission accordingly?
The files are resources and if you want to manage a resource you have to know it's there so dynamically created log files are not easy. If you know the file names already then you can use something like this and pass an array into the file resource.
file { ['/etc/systemd/file_1.log',
'/etc/systemd/file_1.log',
'/etc/systemd/file_1.log'] :
ensure => 'file',
mode => '0644',
owner => 'root',
group => 'root',
}
An other method might be to use an exec
exec { 'chmod 644 /etc/systemd/file_*.log':
path => ['/usr/bin', '/usr/sbin',],
}
But you really need something like an onlyif or unless or this is going to execute every 30 minutes and that breaks the idempotent rule we try and apply with Puppet code where things only change if they need correcting. So you're going to need a command line that'll test the permissions and return a boolean to the onlyif.
There are more details here https://puppet.com/docs/puppet/5.5/types/exec.html
A alternative (and the way I'd do it) would be to expose the contents of that file via an external fact which passes the list of files to Puppet to use in the catalog compilation. An external fact can be a bash script so I'd create a file called /etc/facter/facts.d/logfiles.sh, obviously I'd deploy this using Puppet.
#!/usr/bin/env bash
logfiles=($(grep file /tmp/test))
echo "logfiles=${logfiles[*]}"
Then in my Puppet code I'd have something like this;
$logfiles.each |String $logfile| {
file { $logfile :
ensure => 'file',
mode => '0644',
owner => 'root',
group => 'root',
}
}
So when the Puppet run happens the list of log files will be returned to Puppet via the facts and then each file listed is defined as a resource with the correct permissions.
How do I set file permission from list of file names from cat command?
There are two main alternatives, but I observe first that your example is of the output from grep, not cat, and that the cat in that example is superfluous. Nevertheless, those details don't change the big picture -- substantially the same approaches are applicable for data output by any command.
It would be more idiomatic to write a custom fact that captures the filenames (as of the time of each catalog request), and use that information to create the appropriate File resources.
Custom facts are not that hard, but the full details are more than would be appropriate for an SO answer. Supposing that you have a fact $facts['systemd_logs'] whose value is an array of the absolute filenames, you can compactly express the whole group of wanted File resources like so:
file { $facts['systemd_logs']:
mode => '0644',
}
(or whatever mode it is that you want).
It would be quicker (and dirtier) to use an Exec resource to run an appropriate command:
exec { 'ensure correct file permissions':
command => 'chmod 0644 $(/bin/grep file /tmp/test)',
onlyif => '/bin/grep -q file /tmp/test',
provider => 'shell',
}

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",
}

How to check if a directory exists in 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.

how to remove all /etc/*.txt files with puppet

this puppet manifest will remove the file /etc/file.txt if it exists:
file { "/etc/file.txt":
ensure => absent,
}
how to tell puppet to remove all files /etc/*.txt?
according to the reference, it seems that puppet file does not allow wildcards.
https://puppet.com/docs/puppet/latest/types/file.html
ps: I am aware that I could execute a script from puppet, but I would prefer another more elegant way.
There's a built-in type for this called 'tidy', which allows you to specify a file glob pattern of files to remove.
Check it out at https://puppet.com/docs/puppet/latest/types/tidy.html.
You can use a glob pattern with tidy: https://puppet.com/docs/puppet/latest/types/tidy.html
So this would be your solution:
tidy { "delete-txt-files-in-etc":
path => "/etc",
recurse => true,
matches => [ '*.txt' ],
rmdirs => false,
}

Resources