If you’ve been here previously, you may know about the sudo cake I had baked and the reason I had it baked. Current events make me want to point out again how important it is to validate files you push out to machines with Ansible. Case in point is a shop which brought down a group of DNS servers by pushing out a broken configuration file.

Consider this Ansible playbook, and in particular, the template action:

---
- hosts: bindservers
  user: root
  vars:
  - checkconf: /usr/sbin/named-checkconf
  tasks:
  - name: Install and validate named.conf
    action: template src=named.conf.j2 dest=/etc/named.conf validate='{{ checkconf }} %s'

The validate option (also available for the copy command) specifies a validation command which will be run when Ansible creates (i.e. copies) the template to the target machine, but before that is moved into it’s final _dest_ination. If this command fails (a single %s is replaced by the filename) the whole task fails, which is good: the _dest_ination file is not modified. Here’s an example of the task failing:

TASK: [Install and validate named.conf] ***************************************
failed: [ns03] => {"failed": true}
msg: failed to validate: rc:1 error:

FATAL: all hosts have already failed -- aborting

and here is the task passing validation:

TASK: [Install and validate named.conf] ***************************************
changed: [ns03]

In this particular example I’m lucky because the BIND nameserver package actually has a program which can perform a validation check on its own configuration. (Just as sudo can with its visudo program, as I learned the hard way …) If that weren’t possible, I might want to create some script which does it for me and install that as an early Ansible task.

Here’s another template task with which I’ve deployed a syslog-ng configuration; it also validates the templated configuration file before installing it at its final destination.

- name: Install syslog-ng.conf from template
  action: template >
     src=syslog-ng.conf.in
     dest=/etc/syslog-ng/syslog-ng.conf
     owner=root
     group=root
     mode=644
     backup=yes
     validate="/sbin/syslog-ng -F -s -f %s"
     notify: restart syslog

This is just a friendly reminder.