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
- 4GB+ RAM (8GB+ Recommended)
- Ruby 1.9.3+
- Git
- Chef 11+
- VirtualBox 4.3+
- Vagrant 1.4+
###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.