Posted on by & filed under infrastructure, IT, testing.

One of the first things we noticed working with Chef was that, despite myriad uses and usage patterns, out of the box it involves a significant amount of administrative overhead, assuming users will maintain local cookbook inventories with knife and manually manage dependencies.

When working with new software, particularly tools that manage infrastructure, we see that in order to get the most significant leverage and benefits, we have to use early implementations that can sometimes feel more like art than engineering.  This has certainly been the case with using Chef for configuration management and automation, as we’ve transitioned from bespoke scripts and systems to official solutions as they materialize.

Scott Pustay and I previously described aspects of our “legacy” CI setup in other blog posts, and I want to offer a quick update about how we are integrating emerging Chef workflow technology at Safari Books Online.

In our new infrastructure update, we will be using test-kitchen to launch and drive our LXCs, alongside Berkshelf to manage cookbooks and their dependencies, running our minitest spec tests against a chef-zero faux server. In our case, we’re doing this on an Ubuntu 12.04 vmware guest, and we’re using the standard lxc package.  You will need ruby and rubygems on your ubuntu workstation, which we did with rvm (via Fletcher’s rvm cookbook).

When you have your Ubuntu box up and running, you should clone your chef-repo directory and cd into cookbooks inside it.  In the cookbooks directory, git clone any of your unique local cookbooks, but you don’t need to download external ones anymore; Berkshelf will resolve those.  But first, we need to install the gems you need, which I do by making a Gemfile like this:

With the Gemfile in place, you can bundle install to install these gems.

Following the installation of gems, you’ll want to generate a .kitchen.yml file, in order to get your tests going on the right nodes with the right provisioners and whatever.  In our case, we want to use LXC because they’re super fast and Just Work on virtualized nodes, which is essential for our use case.  The default .kitchen.yml will download remote LXCs and install the chef omnibus installer, but that is better for illustration than production purposes; we made an LXC template called ubuntu_1204 (lxc-create -t ubuntu -n ubuntu_1204) and then customized it, simply by installing basic packages (ie chef 11, telnet, make, g++), configuring sudoers to give ubuntu nopasswd root access (only for testing!) and then doing lxc-stop for it.

Since we installed the kitchen-lxc driver, made our own LXC, and intend to use the chef-zero provisioner, we can just create our own .kitchen.yml, which is a bit different from the default:

Let me break it down, stanza by stanza:

This tells test-kitchen to use the LXC driver, to not install chef via the omnibus (since we already installed it on our LXC template), and to use the chef_zero provisioner (which just became available in a pretty recent (Aug 2013) test-kitchen gem.

We only have one platform at this point, Ubuntu 12, and it uses our ubuntu_1204 LXC template that we made earlier with lxc-create.  On the LXC template, we configured sudoers to give ubuntu nopass sudo access because otherwise our LXC will hang, waiting for a password.

Here we define test suites.  For this example, we’re using the test suites, but our usage pattern deviates slightly from the test-kitchen documentation inasmuch as the test-kitchen uses the suite name in order to invoke a particular “busser” to run a particular type of test.  However, at the moment, the minitest busser does not support minitest spec tests, and so to use the test suite as invoked by test-kitchen.  Instead, we continue to rely on the minitest-handler cookbook to run the tests we’ve already written, and which live in the files/default/tests/minitest/ directory, as *_test.rb.  Our run list includes the minitest-handler cookbook to handle the minitest spec tests we wrote, and the our sbo_cookbook_with_tests cookbook, which contains minitest spec tests.  In our example, sbo_cookbook_with_tests contains tests that require the loading of data bag data, based on cookbook_param_1.  With test-kitchen as it comes out of the box, we have only a chef-solo provisioner and so cannot pass tests that require a Chef Server.  We were mid-integrating chef-solo search when fnichol recommended Chef Zero and showed me where its provisioner had just been integrated into test-kitchen.

Chef Zero is basically a faux Chef Server that runs in memory and can be used to supply data bag data for testing purposes.  To get it up and running, you need the chef-zero gem that we included in your Gemfile and you need .json representations of your data bag data.  Given that we fill our data bags from files, this was very simple for us, and we were able to simply copy chef-repo/data_bags into our cookbooks directory (where our .kitchen.yml lives and where we’ll put our Berksfile in a minute).  You can also do this with nodes and roles, but for our purposes of getting a simple demo, we will just pass in node data via the attributes block in .kitchen.yml (above).

At this point, we have all the testing components in place, but we haven’t configured Berkshelf yet.  You initialize a Berkshelf by doing berks init, but that will cause some file conflicts with our Gemfile and .kitchen.yml, so let’s just create a filed called Berksfile (case-sensitive!), in which we include the following:

Now you can bundle exec kitchen test and launch tests on LXCs on your local workstation.  You still need to configure Berkshelf to communicate with your actual Chef Server or broader continuous delivery/integration/deployment environment, but at this point, you can kitchen test and see a chef-client run that starts a clone of the LXC you created, watch it download some gems, including chef_zero, launch the Chef Zero faux server, load your minitest spec tests and run them against your data bag data, as loaded from its corresponding .json file in chef-zero, and then either pass and destroy the LXC or fail and leave it up for you to use via lxc-console.

Tags: chef, configuration management, devops, integration testing, TDD,


  1.  Continuing on Continuous Integration | Safari Flow Blog
  2.  Practical Philosophy in Chef Land | Safari Flow Blog