published on 14 May 2012

Wouldn't it be nice if you never made a mistake or a typo again? Okay, that's a slightly misleading offer. How about just never committing such gaffes in with your code? "How?" I hear you cry. With the illustrious Tim Sharpe's puppet-lint and some version control derring-do!

Following on from Adrien's wonderful post on syntax checking and writing tests, you have a way of checking the syntax and style guide from the command line. Using this approach, even on a mature (like a fine wine) Puppet code base, you can move towards having beautiful, aligned, ordered manifests—the type of manifests you'd be happy taking home to meet the family.

Puppet-lint takes the Puppet Labs Style Guide and places it nicely in a command line tool. Think of it as a programmatic PEP-8 for those from a Pythonic world. Now, where this comes in handy is when you're using revision control (which is all the time, obviously!), because you can tie the two together. Yes, every time you try and commit your code to your RCS, it checks the files you're committing, and makes sure you haven't used a tab where there should be a space.

In Puppet Labs' kickass Operations department, we're ever so slightly keen on Git, not least due to the wonderful GitHub. RCSHub just doesn't cut it for us these days.

With Git, as with many an RCS, you're free to define hooks to do weird and wondrous things upon certain actions. This chapter on git hooks from Customizing Git explains them in detail. If you’re using Subversion, then this pre-commit documentation suggests what you can do on the server side to accomplish the same thing.

For this, the pre-commit hook is the one we want to utilise. I first make a bash script to get a list of the files that change in the commit. Then, the hook script goes through them one at a time, seeing if they're Puppet manifests by name, and running puppet-lint on them as it goes. If any of the manifests fail linting, it exits there and then I may go fix them at my leisure!

#!/bin/bash
# Requires bash, as it uses the [[ ]] syntax.
#
# If it's puppet code, lint it up.

# I we don't have puppet-lint, so just exit and leave them be.
which puppet-lint >/dev/null 2>&1 || exit

# Variables goes hither
declare -a FILES
IFS="
"
FILES=$(git diff --cached --name-only --diff-filter=ACM )

for file in ${FILES[@]}
do
  if [[ $file =~ \.*.pp$ ]]
  then
    puppet-lint --with-filename "$file"
    RC=$?
    if [ $RC -ne 0 ]
    then
      exit $RC
    fi
  fi
done

exit 0

I save that file to .git/hooks/pre-commit in my repository, give it a light sprinkling of 'chmod +x', a dash of 'gem install puppet-lint' and I am ready to roll.

Exhibit A, the Larch

So let's see this bad-boy in use, I hear you cry! Let's take a manifest that breaks all of the rules, and see what happens...

node 'hubert.humphrey.edu' {
	
	user{ "mhunter":
	   managehome => true,
	   home => "/home/mhunter",
	   comment => 'Mark Hunter',
	   ensure => 'present'
   }

}
[enlil:puppetlabs-modules]% git commit hubert.pp
hubert.pp - WARNING: double quoted string containing no variables on line 3
hubert.pp - WARNING: double quoted string containing no variables on line 5
hubert.pp - WARNING: => on line isn't properly aligned for resource on line 5
hubert.pp - WARNING: => on line isn't properly aligned for resource on line 6
hubert.pp - WARNING: => on line isn't properly aligned for resource on line 7
hubert.pp - ERROR: two-space soft tabs not used on line 4
hubert.pp - ERROR: two-space soft tabs not used on line 5
hubert.pp - ERROR: two-space soft tabs not used on line 6
hubert.pp - ERROR: two-space soft tabs not used on line 7
hubert.pp - ERROR: two-space soft tabs not used on line 8
hubert.pp - ERROR: trailing whitespace found on line 2
hubert.pp - WARNING: ensure found on line but it's not the first attribute on line 7

Woah, that's a lot of errors. By default, puppet-lint will let warnings through, but stop dead on errors, and we got them all! I'll tidy this manifest up...

node 'hubert.humphrey.edu' {

  user{ 'mhunter':
    ensure     => present,
    managehome => true,
    home       => '/home/mhunter',
    comment    => 'Mark Hunter',
  }

}

Much more readable, and now when I try and commit it, I get:

[enlil:puppetlabs-modules]% git commit hubert.pp
[master 6020331] Add in a new pupil to the school!
 1 file changed, 10 insertions(+)
 create mode 100644 hubert.pp
 

Clean, and the best part is I don't have to alter my workflow, I can just carry on editing with Vim, commit my work as normal, and just be kindly reminded when a manifest has things that need tidying up.

Learn More

Share via:
Posted in:

Add new comment

The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.