Ansible Galaxy – Testing Roles with Test Kitchen
Ansible is a provisioning tool to easily help you get your infrastructure
under control. One of the key elements in Ansible is a role. There are public
roles to get you started quickly with Ansible over at Ansible Galaxy. One
thing Ansible is sort of lacking is a strong testing approach for open source
roles.
Other technologies like Chef have this approach to test drive the code and tools that provision your infrastructure. Luckily there has been some work to extend some of those very tools to test your Ansible roles as well.
To get started we will need a handful of dependencies:
- A working Python install with Ansible installed
 
- A working Ruby install with bundler installed
 - Docker installed and running. Please see install instructions.
 - Some knowledge on Ansible itself and creating Galaxy roles.
 - Also some knowledge of Rspec and a Ruby dev environment
 
Adding needed gems
First we can start by initializing bundler for the role with bundler init.
Then we can add our dependencies to the Gemfile.
source 'https://rubygems.org'
group :test do
  gem 'kitchen-ansible'
  gem 'kitchen-docker'
  gem 'test-kitchen'
end
The dependencies here are adding Test Kitchen with the ansible and docker
hooks since by default this is used with Chef and Vagrant. Make sure to
install the dependencies afterwards with bundle install
Kitchen setup
Once kitchen dependencies are installed we can initialize the role for the Test
Kitchen with bundle exec kitchen init. This will create a .kitchen.yml file,
which we want to update to be the following:
---
driver:
  name: docker
platforms:
  - name: "ubuntu-14.04"
verifier:
  name: busser
  plugin:
    - Ansiblespec
suites:
  - name: default
    provisioner:
      name: ansible_playbook
      playbook: role.yml
      additional_copy_path:
        - "."
The gist of what this is doing is telling kitchen to use the docker driver,
with a platform of Ubuntu 14.04 LTS, a verifing step using the Ansiblespec plugin,
and a default test suite that will run a playbook named role.yml. The most
important thing at the moment is the additional_copy_path. At the moment testing
an Ansible Galaxy role doesn’t just work out of the box with kitchen-ansible.
By specifying the copy path to be the role directory you get it copied into the
provisioner which can then be ran as a normal role within a playbook.
Kitchen Ansible setup
Kitchen Ansible is where most of the magic happens to allow Test Kitchen to be used in place of Chef. See the repo for more information on setup, updates, and configuration. Start by making the needed test directories and files to run our default test suite. Your test directory structure should look like so:
test/
└── integration
    └── default
        └── ansiblespec
            ├── Gemfile
            └── config.yml
The config.yml file for the default suite should be filled out with this:
---
-
  playbook: role.yml
  inventory: hosts
  kitchen_path: "/tmp/kitchen"
  pattern: "spec"
  user: root
Where the role.yml is a playbook in your Galaxy role that includes itself with
variables and tasks.
---
- name: Test my role
  hosts: all
  sudo: yes
  roles:
    - ""
  vars_files:
    - "defaults/main.yml"
    - "vars/main.yml"
  tasks:
    - include: "tasks/main.yml"
  handlers:
    - include: "handlers/main.yml"
At time of writing this will break without the roles section!
Writing your specs
Since Test Kitchen uses Rspec we will need to set this up with a spec_helper
and our default_spec.rb for our default test suite in a spec directory:
spec
├── default_spec.rb
└── spec_helper.rb
Where a spec_helper.rb would look something like this, minus any SSH setup which
you can see more on at the kitchen-ansible repository.
require 'rubygems'
require 'bundler/setup'
require 'serverspec'
require 'pathname'
require 'net/ssh'
RSpec.configure do
  set :host, ENV['TARGET_HOST']
  set :request_pty, true
end
A contrived default_spec.rb might look something like so:
require_relative './spec_helper.rb'
describe 'my galaxy role' do
  describe group('baz') do
    it { should exist }
  end
  describe user('foobar') do
    it { should exist }
  end
  describe package('role-package') do
    it { should be_installed }
  end
  describe file('/etc/myapp/app.conf') do
    it { should be_file }
  end
  describe port(8000) do
    it { should be_listening }
  end
  describe process('myprocess') do
    it { should be_running }
  end
end
Running your role tests
With everything in place we have Test Kitchen set up to use our ansible role
to provision an Ubuntu machine within Docker and verify with our serverspec
test. Now we can run the tests with bundle exec kitchen test. This will
spin up a docker image with Ubuntu installed. Chef will be installed to use
this version of Ruby for any dependencies. Ansible will be installed and used
to provision the container with your role.yml playbook. Then rspec will be
ran to run the default test suite and your default_spec.rb file.
Some shortcomings
Currently you need to define an empty roles key in your playbook being ran.
Kitchen ansible was mainly built to run against an ansible project with multiple
roles rather than a Galaxy role. This may change in the future, making this process
easier.
The spec pattern is being used here to workaround a path issue with where
the verifier is looking for spec files. This means the spec files matching
spec/*_spec.rb will be executed for every test suite at the moment. It would
be nice to have a suite directory with spec files per suite, similar to a per
role suite in the normal testing pattern.
Using the additional_copy_path had to be used to get the galaxy role into
the container where provisioning needed to happen. Ideally there would be a nicer
way to say your role that is being tested is the current directory or is a galaxy
role to avoid this.
Kitchen Ansible love
Overall this is a great start to getting some test coverage for an ansible galaxy role. It helps shorten the gap to something like Chef that has a community that is focused on testing their open source contributions. This also helped me with a role where someone contributed changes to support a non-ubuntu platform. Now tests can be added for the new platform to ensure things don’t break for either when added in and going forward.
- ansible
 - ansible galaxy
 - ansible galaxy role testing
 - ansible test kitchen
 - devops
 - infrastructure as code