Using a Pre-Commit Hook to Check Puppet Syntax


The whole idea of Puppet is to put your machine configuration scripts in a versioned repository. This is good because I've found that a syntax error on a manifest not even used by the current machine will stop the puppet updates from running. One error anywhere kills the whole thing everywhere. So, being able to back out of a change is good.

We can go one better however and keep people from checking in files that aren't syntactically correct using the pre-commit hook in SVN. If you don't use SVN, your repository probably has something similar.

I followed these instructions for the hook and these instructions for installing it.

I ran into a problem however. The pre-commit script wasn't reporting an error condition correctly. I'm not sure what was wrong. Running the puppet command on the command line and then checking $? gave a "1", but inside the script it wasn't working that way. So, I punted and wrote the error output to a file and checked whether or not the file existed and then just cat'd that out to standard err. Messy, but it worked and I need to go home. Here's the file as modified by me:

#!/bin/bash
# SVN pre-commit hook to check Puppet syntax for .pp files
PATH="/usr/bin:/bin"
REPOS="$1"
TXN="$2"
tmpfile=`mktemp`
errfile=`mktemp`
export HOME=/
SVNLOOK=/usr/bin/svnlook
$SVNLOOK changed -t "$TXN" "$REPOS" | awk '{print $2}' \\
   | grep '\\.pp$' | while read line
do
  $SVNLOOK cat -t "$TXN" "$REPOS" "$line" > $tmpfile
  if [ $? -ne 0 ]
  then
    echo "Warning: Failed to checkout $line" >&2
  fi
  /usr/bin/puppet --color=false --confdir=/tmp \\
     --vardir=/tmp --parseonly --ignoreimport $tmpfile \\
     >$errfile 2>/dev/null
  if [  -s $errfile ]
  then
    echo "Puppet syntax error in $line." >&2
    cat $errfile >&2
    exit 2
  fi
done
res=$?
rm -f $tmpfile
rm -f $errfile
if [ $res -ne 0 ]
then
  exit $res
fi

Note: you may need to combine lines separated by "\\\\" into a single line.

This works great. Syntax errors are caught before they make it into the repository. I'm still looking for a good way to thoroughly test puppet scripts before they get into the production servers. If you have any best practices in that area, I'd love to hear about them.