Automating Cookbook Testing with Test-Kitchen, Berkshelf, Vagrant and Guard

One of the most challenging aspects of Chef cookbook testing for newbies is setting up a rapid local testing & development environment. There are a plethora of options depending on your situation, but most frequently it boils down to “internal” vs. “external” testing options. While the hosted services are a boon for those of us doing this on the cheap, there is a large contingent of cookbook developers that remain trapped behind corporate firewalls and intellectual property policies.

This post will cover the initial setup & configuration of the tools we’ll be using in our environment.

###Pre-Requisites

###Step 1: Install Bundler and Berkshelf gems

There are two gems we need to have installed prior to starting any work, Bundler and Berkshelf. We could skip Berkshelf and let Bundler manage it, but since we are creating new cookbooks using the berks cookbook command later, let’s just make sure it’s installed ahead of time.

$~/chef-repo: gem install berkshelf
Successfully installed berkshelf-2.0.10
1 gem installed

$~/chef-repo: gem install bundler
Successfully installed bundler-1.3.5
1 gem installed

###Step 2: Create your cookbook We could start off by simply creating a new cookbook the Chef way, however that only generates a solitary cookbook and doesn’t handle any dependency resolutions if you decide to leverage any external cookbooks. In our case, we are going to use Berkshelf to manage our cookbook dependencies and create our cookbooks.

For this example we are going to create a cookbook to install and configure the Strider CD server application.

$~/chef-repo/cookbooks: berks cookbook strider-cd
      create  strider-cd/files/default
      create  strider-cd/templates/default
      create  strider-cd/attributes
      create  strider-cd/definitions
      create  strider-cd/libraries
      create  strider-cd/providers
      create  strider-cd/recipes
      create  strider-cd/resources
      create  strider-cd/recipes/default.rb
      create  strider-cd/metadata.rb
      create  strider-cd/LICENSE
      create  strider-cd/README.md
      create  strider-cd/Berksfile
      create  strider-cd/Thorfile
      create  strider-cd/chefignore
      create  strider-cd/.gitignore
         run  git init from "./strider-cd"
      create  strider-cd/Gemfile
      create  .kitchen.yml
      append  Thorfile
      create  test/integration/default
      append  .gitignore
      append  .gitignore
      append  Gemfile
      append  Gemfile
You must run `bundle install' to fetch any new gems.
      create  strider-cd/Vagrantfile

Whoa! That’s a bunch of files that just got created. We’ll cover most of these throughout the post, however for now let’s focus on the Gemfile so we can get our Ruby dependencies setup properly.

###Step 3: Configure your Gemfile & install your gems The first thing you will want to do is configure your Gemfile to install the gems we’ll be using for our testing environment. The Gemfile simply defines the gems and (optionally) specific versions that should be used for Bundler commands.

~/chef-repo/cookbooks/strider-cd/Gemfile

source 'https://rubygems.org'

gem 'berkshelf'

group :development do
  gem 'test-kitchen'
  gem 'kitchen-vagrant'
  gem 'guard'
  gem 'guard-kitchen'
end

Once you have your Gemfile updated and saved, you can install the gems declared above.

$~/chef-repo/cookbooks/strider-cd: bundle install
Fetching gem metadata from https://rubygems.org/.......
Resolving dependencies...
Installing i18n (0.6.9)
Installing multi_json (1.8.2)
...
Installing test-kitchen (1.1.1)
Installing kitchen-vagrant (0.14.0)
Using bundler (1.3.5)
Your bundle is complete!
It was installed into ./vendor/bundle

Great! You now have a local vendored installation of the gems we’ll be using to drive our development environment.

###Step 4: Execute a Test Run with Test-Kitchen Test-Kitchen is a testing harness used for quickly creating, configuring, testing and destroying virtual machines. The recent 1.0.0 release brought forth a pretty great Getting Started guide that you should definitely check out if you’ve never used Test-Kitchen before.

By default, Berkshelf creates a file in the root of our cookbook directory structure with some directives for testing on Ubuntu 12.04 and CentOS 6.4. Since we are just getting started, let’s modify the .kitchen.yml file to just run on CentOS 6.4 until we have a working cookbook. We can come back to add cross-platform support later on.

~/chef-repo/cookbooks/strider-cd/.kitchen.yml

---
driver:
  name: vagrant

provisioner:
  name: chef_solo

platforms:
  - name: centos-6.4

suites:
  - name: default
    run_list:
      - recipe[strider-cd::default]
    attributes:

Now that we have all of the components installed and configured, let’s go ahead and prepare our testing environments by executing bundle exec kitchen test. Even though we haven’t written any code yet, we should be able to verify that our local VMs are being created and managed by Test-Kitchen.

$~/chef-repo/cookbooks/strider-cd: bundle exec kitchen test
-----> Starting Kitchen (v1.1.1)
-----> Cleaning up any prior instances of <default-centos-64>
-----> Destroying <default-centos-64>...
       Finished destroying <default-centos-64> (0m0.00s).
-----> Testing <default-centos-64>
-----> Creating <default-centos-64>...
       Bringing machine 'default' up with 'virtualbox' provider...
       [default] Importing base box 'opscode-centos-6.4'...
...
       Finished converging <default-centos-64> (0m50.11s).
-----> Setting up <default-centos-64>...
       Finished setting up <default-centos-64> (0m0.00s).
-----> Verifying <default-centos-64>...
       Finished verifying <default-centos-64> (0m0.00s).
-----> Destroying <default-centos-64>...
       [default] Forcing shutdown of VM...
       [default] Destroying VM and associated drives...
       Vagrant instance <default-centos-64> destroyed.
       Finished destroying <default-centos-64> (0m7.59s).
       Finished testing <default-centos-64> (1m43.98s).
-----> Kitchen is finished. (1m44.27s)

###Step 5: Configure Guard to automatically test cookbooks Those of you eagle-eyed readers out there may have noticed that we included two gems in our Gemfile that we haven’t covered yet, guard and guard-kitchen. These two gems are the key to our automatic testing environment setup.

The first gem is for Guard, which monitors file system modifications and then takes actions based on what’s defined in your Guardfile. The second gem is a plugin for Guard that auto-generates Test-Kitchen matchers for your Guardfile. Let’s go ahead and initialize our cookbook with Guard support.

$~/chef-repo/cookbooks/strider-cd: bundle exec guard init
21:52:14 - INFO - Writing new Guardfile to /Users/micgo/chef-repo/cookbooks/strider-cd/Guardfile
21:52:14 - INFO - kitchen guard added to Guardfile, feel free to edit it

Now that we have generated our Guardfile, let’s take a quick peak. We won’t need to change anything however, as the guard-kitchen plugin has handled the regex matching for us automatically!

~/chef-repo/cookbooks/strider-cd/Guardfile

# A sample Guardfile
# More info at https://github.com/guard/guard#readme

guard 'kitchen' do
  watch(%r{test/.+})
  watch(%r{^recipes/(.+)\.rb$})
  watch(%r{^attributes/(.+)\.rb$})
  watch(%r{^files/(.+)})
  watch(%r{^templates/(.+)})
  watch(%r{^providers/(.+)\.rb})
  watch(%r{^resources/(.+)\.rb})
end

You should now have all of the components necessary to test your cookbooks automatically whenever you save changes or create a new file. You can start Guard up to watch your strider-cd cookbook now.

$~/chef-repo/cookbooks/strider-cd: bundle exec guard start
21:56:51 - INFO - Guard is using TerminalTitle to send notifications.
21:56:51 - INFO - Guard::Kitchen is starting
-----> Starting Kitchen (v1.1.1)
-----> Creating <default-centos-64>...
       Bringing machine 'default' up with 'virtualbox' provider...
       [default] Importing base box 'opscode-centos-6.4'...
...
       Vagrant instance <default-centos-64> created.
       Finished creating <default-centos-64> (0m43.50s).
-----> Kitchen is finished. (0m43.80s)

21:57:36 - INFO - Guard is now watching at '/Users/micgo/chef-repo/cookbooks/strider-cd'
[1] guard(main)>

Guard is now watching for changes in your ~/chef-repo/cookbooks/strider-cd directory structure and will execute a kitchen verify every time it detects a modification.

In the next post, we’ll configure Foodcritic with Guard to continue our automated test-driven development process.


This blog is the first post in a series covering automated cookbook development for Chef. You can find links to all current posts below.

  1. Automating Cookbook Testing with Test-Kitchen, Berkshelf, Vagrant and Guard
  2. Check Yo Self Before You Wreck Yo Self with Foodcritic & Guard
  3. Continuous ChefSpec Validation with Guard
  4. Serverspec, Guard and Test Kitchen: Testing Servers Like a Boss
comments powered by Disqus