Image for post
Image for post

TestKitchen with Chef

How to Test and Configure a system using Chef

Test Kitchen is a remarkable tool that not only creates and provisions systems, but also tests them to verify that your scripts correctly configured the systems.

Previous Guide

In a previous guide, I demonstrated how to use Vagrant to bring up a system and provision it with Chef.

Prerequisites

This tutorial requires the following tools:

Previous Guides

I have written some previous guides that show how to get these tools for macOS, Windows, and Linux.

Installing using Ruby (Advanced)

You can install it manually using Ruby 2.5.1 or later. I highly recommend using a Ruby manager like rbenv or rvm. With Bundler, you can get recent Test Kitchen with this Gemfile:

source :rubygemsgem 'test-kitchen'
gem 'kitchen-vagrant'
gem 'kitchen-inspec'
gem 'inspec'
gem 'berkshelf'

Part I: Create Chef Cookbook

This is the same process as the Vagrant guide, which will install create a minimal Chef cookbook structure, modeled after the chef generate cookbook command in Chef 14.

Create Cookbook

PROJ_PATH=${HOME}/vagrant-chef
COOKBOOK_PATH=${PROJ_PATH}/cookbooks/hello_web
mkdir -p ${COOKBOOK_PATH}/{files/default,attributes,recipes}
cd ${COOKBOOK_PATH}##### Create Cookbook Attributes
cat <<-'ATTRIB' > attributes/default.rb
default['hello_web']['package'] = 'apache2'
default['hello_web']['service'] = 'apache2'
default['hello_web']['docroot'] = '/var/www/html'
ATTRIB
##### Create Cookbook Recipe
cat <<-'RECIPE' > recipes/default.rb
apt_update 'Update the apt cache daily' do
frequency 86_400
action :periodic
end
package node['hello_web']['package']cookbook_file "#{node['hello_web']['docroot']}/index.html" do
source 'index.html'
action :create
end
service node['hello_web']['service'] do
supports status: true, restart: true, reload: true
action %i(enable start)
end
RECIPE
##### Create Cookbook Metadata
cat <<-'METADATA' > metadata.rb
name 'hello_web'
version '0.0.1'
chef_version '>= 12.14' if respond_to?(:chef_version)
METADATA
##### Create Content
cat <<-'HTML' > files/default/index.html
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
HTML
.
├── attributes
│ └── default.rb
├── files
│ └── default
│ └── index.html
├── metadata.rb
└── recipes
└── default.rb

Part II: Configure Test Kitchen

In this part, we will configure our test structure and tests needed to verify the cookbook we created in the previous section.

Initial Test Structure

We can create the Test Kitchen structure within our cookbook with the following below:

PROJ_PATH=${HOME}/vagrant-chef
COOKBOOK_PATH=${PROJ_PATH}/cookbooks/hello_web
SERVERSPEC_PATH=${COOKBOOK_PATH}/test/integration/default/serverspec
cd ${COOKBOOK_PATH}mkdir -p ${SERVERSPEC_PATH}
touch .kitchen.yml \
${SERVERSPEC_PATH}/{default_spec.rb,spec_helper.rb}
.
├── .kitchen.yml
├── attributes
│ └── default.rb
├── files
│ └── default
│ └── index.html
├── metadata.rb
├── recipes
│ └── default.rb
└── test
└── integration
└── default
└── serverspec
├── default_spec.rb
└── spec_helper.rb

Configure Test Harness

Now it is time configure Test Kitchen to use Chef and run a cookbook on Ubuntu platform.

---
driver:
name: vagrant
provisioner:
name: chef_zero
always_update_cookbooks: true
platforms:
- name: ubuntu-16.04
suites:
- name: default
run_list:
- recipe[hello_web::default]

Create A Test

Let’s update our default spec test default_spec.rb:

require 'spec_helper'describe port(80) do
it { should be_listening }
end
require 'serverspec'set :backend, :exec
No backend type is specified. Fall back to :exec type.

Part III: Testing a Single Platform

Creating Systems

To get started, we can create the Ubuntu system:

kitchen create

Check Working System

To verify things are working, run:

kitchen exec ubuntu -c 'lsb_release -a'
-----> Execute command on default-ubuntu-1604.
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.4 LTS
Release: 16.04
Codename: xenial

Configure the System

Now with at least one working system, let’s download chef client and configure it with:

kitchen converge

Test the System

Now we can run the tests:

kitchen verify
-----> Starting Kitchen (v1.22.0)
-----> Verifying <default-ubuntu-1604>...
Preparing files for transfer
-----> Busser installation detected (busser)
-----> Busser plugin detected: busser-serverspec
Removing /tmp/verifier/suites/serverspec
Transferring files to <default-ubuntu-1604>
-----> Running serverspec test suite
/opt/chef/embedded/bin/ruby -I/tmp/verifier/suites/serverspec -I/tmp/verifier/gems/gems/rspec-support-3.8.0/lib:/tmp/verifier/gems/gems/rspec-core-3.8.0/lib /opt/chef/embedded/bin/rspec --pattern /tmp/verifier/suites/serverspec/\*\*/\*_spec.rb --color --format documentation --default-path /tmp/verifier/suites/serverspec
Port "80"
should be listening
Finished in 0.1038 seconds (files took 0.29169 seconds to load)
1 example, 0 failures
Finished verifying <default-ubuntu-1604> (0m1.47s).
-----> Kitchen is finished. (0m1.90s)

Part IV: Testing Multiple Platforms

Now let’s have some fun and add more platforms besides just Ubuntu. We can throw in CentOS and FreeBSD.

Adding Platforms

Update Test Kitchen configuration (.kitchen.yml) to the following:

---
driver:
name: vagrant
provisioner:
name: chef_zero
always_update_cookbooks: true
platforms:
- name: ubuntu-16.04
- name: centos-7
- name: freebsd-11.2
suites:
- name: default
run_list:
- recipe[hello_web::default]
kitchen create
kitchen converge
FATAL: Chef::Exceptions::Package: yum_package[apache2] (hello_web::default line 6) had an error: Chef::Exceptions::Package: No candidate version available for apache2FATAL: Mixlib::ShellOut::ShellCommandFailed: freebsd_package[apache2] (hello_web::default line 6) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '69'

Overriding Attributes

Update the Test Kitchen configuration (.kitchen.yml) to look like the following:

---
driver:
name: vagrant
provisioner:
name: chef_zero
always_update_cookbooks: true
platforms:
- name: ubuntu-16.04
- name: centos-7
attributes:
hello_web:
package: httpd
service: httpd
docroot: /var/www/html
- name: freebsd-11.2
attributes:
hello_web:
package: apache24
service: apache24
docroot: /usr/local/www/apache24/data/
suites:
- name: default
run_list:
- recipe[hello_web::default]

Test Multiple Platforms

Run kitchen verify to see the results. On all systems, we should see this flash by for each platform:

Port "80"
should be listening

Part V: Busser vs. InSpec

In Test Kitchen, the default verifier uses Busser. Specifically, Test Kitchen will attempt to install a Busser runner plug-in gem based on the directory path name. So if you have test/integration/$SUITE/$VERIFIER, Test Kitchen will do a gem install busser-$VERIFIER, where $VERIFIER is the test tool like testinfra, goss, pester, bats, or serverspec.

verifier:
name: inspec
PROJ_PATH=${HOME}/vagrant-chef
COOKBOOK_PATH=${PROJ_PATH}/cookbooks/hello_web
INSPEC_PATH=${COOKBOOK_PATH}/test/integration/default/
cd ${COOKBOOK_PATH}cat <<-'INSPEC' > ${INSPEC_PATH}/default_test.rb
describe port(80) do
it { should be_listening }
end
INSPEC
---
driver:
name: vagrant
provisioner:
name: chef_zero
always_update_cookbooks: true
verifier:
name: inspec
platforms:
- name: ubuntu-16.04
- name: centos-7
attributes:
hello_web:
package: httpd
service: httpd
docroot: /var/www/html
- name: freebsd-11.2
attributes:
hello_web:
package: apache24
service: apache24
docroot: /usr/local/www/apache24/data/
suites:
- name: default
run_list:
- recipe[hello_web::default]
kitchen verify
Port 80
✔ should be listening
Port 80
↺ The `port` resource is not supported on your OS yet.

Additional Busser Notes

I wanted to document Busser because there was not much in the way of documentation, and there are quite a few Busser plug-ins out there now. Currently though, in the Chef community, InSpec is the preferred verifier and not without good reasons.

Conclusion

I hope this was both useful and fun. The take aways from this are:

  • Override default attributes with alternative attributes per platform.
  • Verification on using ServerSpec with default Busser or the InSpec verifier.
  • Some differences and trade-offs between Busser plug-ins and direct Kitchen verifier plug-ins.

Written by

Linux NinjaPants Automation Engineering Mutant — exploring DevOps, Kubernetes, CNI, IAC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store