Mike Conigliaro

Using Puppet's Exec Resource to Run Commands Manually

The title of this post may seem confusing. The whole point of Puppet is to promote efficiency by eliminating manual administrative tasks, so why would anyone want to use Puppet to do things manually? Well, one simple example is when you want to install software from source, or from a binary package that is not supported by the package type. Your first instinct may be to use exec to do something like this:

exec { "install-foo":
    command => "curl -s -o /tmp/foo.run http://example.com/foo.run \
                && chmod o+x /tmp/foo.run \
                && /tmp/foo.run ",
    creates => "/usr/local/bin/foo",
}

This is pretty straightforward. The “command” parameter downloads and installs the package, while the “creates” parameter tells Puppet not to execute the command again as long as “/usr/local/bin/foo” exists. This keeps Puppet from unnecessarily downloading and reinstalling the program over and over again, but what happens when there’s a new version of foo.run? How does puppet know when it’s time to upgrade?

There may be better ways of doing this, but here’s a simple approach that has worked well for me:

$serial = "2009092501"
$serialfile = "/var/log/puppet/foo.serial"
exec { "install-foo":
    command => "curl -s -o /tmp/foo.run http://example.com/foo.run \
                && chmod o+x /tmp/foo.run \
                && /tmp/foo.run \
                && echo \"$serial\" > \"$serialfile\"",",
    unless  => "test \"`cat $serialfile 2>/dev/null`\" = \"$serial\"",
}

Notice that after running the command, I echo the value of $serial into the file at $serialfile. Then I use the “unless” parameter to check if the contents of $serialfile equals the value stored in $serial. If the values match, the command will not be executed. But now when I want to upgrade the foo package, all I need to do is update the value of $serial.

blog comments powered by Disqus