Checking puppet-generated exim config before deploying

I use Puppet to generate /etc/exim4.conf and I want to make sure that the configuration is valid before I install the file on production systems.

I've considered—

  • using a git hook to call exim4 -bV -C filename... but this won't work because I use an ERB template to generate the file, so the end result isn't actually generated until the Puppet agent runs. I already have a git hook to test ERB syntax.

  • letting the init script check the config file... but this isn't good enough because, while the script will refuse to reload Exim if the configuration is invalid, the file will have already been installed and direct calls to Exim (to send mail from applications, for example) will fail.

Ideally what I want is some kind of Puppet directive that looks like

file { '/etc/exim4/exim4.conf':
    content => template("exim/etc/exim4/exim4.conf.erb"),
    notify => Service[exim4],
    but_before_we_install_check_syntax_with => '/usr/bin/exim4 -bV -C',
}

How can I check the syntax of the config file after it's been generated by Puppet but before it gets installed?

I'm using Exim 4.80 and Puppet 2.7.26 on Debian Wheezy systems.


Solution 1:

It sounds like you are describing the validate_cmd parameter exactly. From the Puppet type reference for file:

A command for validating the file’s syntax before replacing it. If Puppet would need to rewrite a file due to new source or content, it will check the new content’s validity first. If validation fails, the file resource will fail.

This command must have a fully qualified path, and should contain a percent (%) token where it would expect an input file. It must exit 0 if the syntax is correct, and non-zero otherwise. The command will be run on the target system while applying the catalog, not on the puppet master.

In your example, I think you would do this:

file { '/etc/exim4/exim4.conf':
    content      => template("exim/etc/exim4/exim4.conf.erb"),
    notify       => Service[exim4],
    validate_cmd => '/usr/bin/exim4 -bV -C %',
}

Solution 2:

You could test the resulting configuration by using a git hook to fire up a virtual machine / container (Docker would be ideal for this) and apply the manifest in that environment.

If you're doing this regularly you might consider implementing a CI system (like Jenkins) which you push your changes to, have the CI run a suite of tests and on success push the changes to production.