Testing Ansible roles
Tags: ansible, rspec, serverspec, kitchen
Published: 2019-08-08 12:47:33

---
title: Testing Ansible roles
published: true
tags: ansible,rspec,serverspec,kitchen
canonical_url: https://www.zufallsheld.de/2016/01/05/testing-ansible-roles/
---

We - at the [dev-sec.io](http://dev-sec.io/)-team - create Ansible (and Puppet and Chef) roles that harden the security of our Linux-servers. They are meant to be used in production so we try to provide these roles to several different operating systems, including Debian, Ubuntu, RedHat and its derivates.

Manually testing the roles on many different systems is a very time-consuming task: You’ll have to set up a virtual machine, update it, install Ansible, run the playbook, fix an error, rinse and repeat. If you want to do this on many different operating systems, doing it manually is impossible.

## The tools

To automate the testing, we use a multitude of programs that together perform all the above-mentioned tasks and in a fraction of time!

- [test-kitchen](https://github.com/test-kitchen/test-kitchen) -\> Test Kitchen is a test harness tool to execute your configured code on one or more platforms in isolation.
- [vagrant](https://www.vagrantup.com/) -\> Create and configure lightweight, reproducible, and portable development environments.
- [VirtualBox](https://www.virtualbox.org/) -\> VirtualBox is a powerful x86 and AMD64/Intel64 virtualization product for enterprise as well as home use.
- [serverspec](http://serverspec.org/) -\> RSpec tests for your servers configured by CFEngine, Puppet, Ansible, Itamae or anything else.
- [kitchen-ansible](https://github.com/neillturner/kitchen-ansible) -\> Ansible Provisioner for Test Kitchen
- [kitchen-vagrant](https://github.com/test-kitchen/kitchen-vagrant) -\> Vagrant driver for Kitchen
- [git](https://www.git-scm.com/) -\> a fast, scalable, distributed revision control system

To help automate testing roles I created this blog-post and the [ansible-test-framework](https://github.com/rndmh3ro/ansible-test-framework). This framework provides the necessary files and configurations to easily set up your testing environment. It is also set up to easily test your roles with travis.

## The workflow

The stages of the testing-workflow are the following:

- Create - create defined instances with Vagrant and VirtualBox
- Converge - install Ansible and run your playbook on the instances
- Setup - install the testing utility and runner on the instances
- Verify - run the tests you created on the instances
- Destroy - destroy the instances

![ansible_test_framework_diagram](https://www.zufallsheld.de/images/ansible_test_framework_diagram.png)

## Setup

You’ll need to locally install Git, Ruby, VirtualBox and Vagrant first, all other necessary components will be installed along the way.

After installing them, create a directory for your role you want to test (called `ansible_role` in the following example).

**The name directory and the name of the role have to be the same!**

Then git-clone the testing-framework into your newly created directory and change into it. Then delete the `.git`-directory, so you can later upload your role to Github!

```
# basic setup
mkdir ansible_role
git clone --depth=1 https://github.com/rndmh3ro/ansible-test-framework ansible_role/
cd ansible_role/
rm -fr .git
```

The next step is to create an empty role with _ansible-galaxy_. Run this command inside your role-directory and replace _ansible\_role_ with the name you gave the directory.

```
# create empty ansible role
ansible-galaxy init -p ../ --force ansible_role
```

The _force_-option is used here because the directory is not empty as you already cloned the test-framework into it.

Now test-kitchen, serverspec, the provisioner, driver and all its dependencies have to be installed. Fortunately, this can all be done with [bundler](http://bundler.io/), a gem dependency handler for ruby:

```
# Install software and dependencies
gem install bundler
bundle install
```

The first command installs bundler. The second command uses the _Gemfile_ present in the directory and installs all packages and its dependencies.

Now’s the time to customize your testing-setup. You’ll have to replace the default name _ansible-test-framework_ with the name of your role (in my case _ansible\_role_) in two places, the `default.yml` and the `.kitchen.yml`. In _kitchen.yml_ the replacement should be in the _roles\_path_. In _default.yml_ its the first item after _roles_.

You can also use this _sed_-command to replace the occurrences. Simply replace _ansible\_role_ in the command with the name of your role.

```
# replace ansible-test-framework with your role-name in:
sed -i 's/ansible-test-framework/ansible_role/g' default.yml .kitchen.yml
```

## Write the role and tests

Write your ansible role now! That’s not part of the guide.

Writing tests for your role is also not a part of this guide, but this framework provides the necessary configuration to start writing serverspec-tests: There’s already a file called _test\_spec.rb_ where you can write your tests in and the spec\_helper is configured for serverspec.

For more help writing tests and using serverspec, read the docs: - http://kitchen.ci/docs/getting-started/writing-server-test - https://github.com/neillturner/kitchen-ansible#test-kitchen-serverspec

## Testing

When you’re done writing your role and tests you can start testing! There are different testing methods. You can test single machines, a set of machines or all at once. See the following examples or take a look at the test-kitchen [docs](http://kitchen.ci/docs/getting-started/getting-help).

```
# fast test on one machine
bundle exec kitchen test ansible-latest-ubuntu-1404

# test on all machines in parallel
bundle exec kitchen test -c

# test all ubuntu machines
bundle exec kitchen test ubuntu
```

While developing roles it can be cumbersome to always destroy and recreate the machines if a test or the role fails at some point. To circumvent this, you can create and then converge the machine. If the role fails during converging, you can simply run the converge again:

```
# for development
bundle exec kitchen create ansible-latest-ubuntu-1404
bundle exec kitchen converge ansible-latest-ubuntu-1404

# ... run fails, change role, converge again

bundle exec kitchen converge ansible-latest-ubuntu-1404
```

If your role takes a long time to run and you want to debug a specific task, you can run the converge with the help of an environment variable like this:

```
ANSIBLE_EXTRA_FLAGS='--start-at-task="ansible_role | name of last working instruction"' bundle exec kitchen converge
```

Replace _ansible\_role | name of last working instruction_ with the name of the task you want to start at, so you can skip others.

Similarly if you want to skip certain tasks, you can use the environment variable like this:

```
ANSIBLE_EXTRA_FLAGS='--skip-tags=beginning' bundle exec kitchen converge
```

### Travis tests

The framework also supports testing with Travis-CI by default. All you have to do is enable your repository in Travis and all pushes to the repository will be tested with Travis. Be aware though that Travis tests on Ubuntu, so write your role accordingly!