You want to validate configuration files you are managing
class valid_config {
file { '/etc/sudoers':
ensure => 'present',
content => "root ALL=(ALL) ALL",
validate_cmd => '/sbin/visudo -cf %',
}
}
# Notice: /Stage[main]/Main/Node[default]/File[/etc/sudoers]/ensure:
# defined content as '{md5}a8f1c89c9a38b550bbb244c4e5053935'
Puppet is a faithful tool that ensures all the file
resources you tell
it to manage are deployed. Unfortunately, by default, it's not very
insightful one so if the provided file is invalid it will happily roll
it to all the nodes, leaving a trail of failures in its wake. Luckily
there's an attribute you can specify on your file
resources, called
validate_cmd
, that can run a validation command against your files and
will cause puppet to skip the resource, leaving the current one in
place, and raise an error if the new file is invalid.
class invalid_sudo {
file { '/etc/sudoers2':
ensure => 'present',
content => "root ALL=(ALL) ALL this should fail now",
validate_cmd => '/sbin/visudo -cf %',
}
}
Error: Execution of '/sbin/visudo -cf /etc/sudoers220171116-27989-25hozb'
returned 1: /etc/sudoers220176-289-ozb: syntax error near line 1
parse error in /etc/sudoers220176-289-ozb: near line 1
-root ALL=(ALL) ALL
+root ALL=(ALL) ALL this should fail now
Error: /Stage[main]/Main/Node[default]/File[/etc/sudoers]/content: failed:
Execution of '/sbin/visudo -cf /etc/sudoers220176-289-ozb returned 1:
/etc/sudoers220171116-27989-25hozb: syntax error near line 1
parse error in /etc/sudoers220171116-27989-25hozb near line 1
If the validation command contains a literal %
you can specify a
second attribute to the resource, validate_replacement
, and its value
will be replaced in the command line instead. Here's an example of this
in action:
class replaced_literal {
file { '/etc/sudoers':
ensure => 'present',
content => "root ALL=(ALL) ALL",
validate_cmd => '/sbin/visudo -cf file_from_puppet',
validate_replacement => 'file_from_puppet',
}
}
It's worth noting that stdlib
contains a function called
validate_cmd
which can be useful in certain circumstances but often
does not work in the way people expect. The file resource validate_cmd
we detail here is executed on each client and so has all of its
environment available. The stdlib
function based version runs on the server,
as all functions do, and so gets all its values from there.
The last thing to consider is the validate command itself. You need to ensure,
preferably in your puppet code, that any resources it needs, and how it gets
installed, happen before the file
resource is reached. In our case we need the
sudo
package to exist (which provides the visudo command) but if you're
validating XML, JSON or similar then you are responsible for ensuring the tools
you need are managed.