Integration Testing Ansible Playbooks with Travis CI and Docker

The process behind performing integration tests on Ansible playbooks is almost exactly the same as the one used to test individual roles. In fact, this tutorial is based on a modified version of Continuous Testing of Ansible Roles with Docker and Travis CI by Ignacio Sánchez Ginés. This tutorial is a demonstration of how I set up continuous integration testing of the WordPress playbook I wrote to deploy this website.

First of all, you will need to create an Ansible inventory file with localhost as a host in your desired host group. As a group variable, you will need to specify the name of the local user and that the connection is local.
See: Working with Inventory

For example, you should have something like this in your hosts file.
[wordpress]
localhost

[wordpress:vars]
ansible_connection=local
ansible_user=root

Now that you have a hosts file, you will COPY it into your Dockerfile. You will obviously want to install ansible, sudo, any other dependencies you may need using a RUN command. If you need to install an Ansible Galaxy role, you can do so with a RUN command after Ansible has been installed.
See: Dockerfile reference and Best practices for writing Dockerfiles

Installing Ansible Galaxy Roles:
# Install Dependencies from Ansible Galaxy
RUN ansible-galaxy install geerlingguy.repo-epel
RUN ansible-galaxy install geerlingguy.repo-remi

This is the CentOS 7 Dockerfile I use to CI test my WordPress playbook.

If you wish to use Ubuntu or Fedora, you can find similar systemd and init based images in Ignacio’s GitHub repository.

Now you need to create a .travis.yml configuration file. Below, you can find the one I use to test my WordPress playbook. I run a syntax check before I try running the actual playbook. Also, if your playbook contains secret variables such as passwords or API keys, I recommend encrypting them using Ansible Vault, and keeping them in a directory that is outside of your repository. You can create a “dummy” secrets file for testing purposes.
See: How To Use Vault to Protect Sensitive Ansible Data on Ubuntu 16.04

If you would like to keep your Dockerfiles in a sub directory, you can specify the location using the --file flag, and replace the ., which specifies the directory you are currently in, with the name of the sub directory you want.

For example, if you want to store your Dockerfiles in the ./travis sub directory, you build command would look something like this.
- 'sudo docker build --no-cache --rm --file=travis/Dockerfile.${distribution}-${version} --tag=${distribution}-${version}:ansible travis'

If you have variables you would like to test different values for, you can use sed to change them.
See: Sed – An Introduction and Tutorial by Bruce Barnett

For example:
- '/bin/sed -e "s/resty_install_from_source: true/resty_install_from_source: false/" -i defaults/main.yml'

After you change the variables, you will obviously need to run another series of tests. Below is the CI test configuration I am using for my OpenResty role.

Finally, you will need to enable Travis CI on your repository, which you can reference the Travis CI getting started for instructions.

If you prefer a video tutorial on how to set up Travis CI, here is a decent one.

Regular Expressions and In-Place Slice Manipulation in Go

Regular expressions are very useful for parsing strings. If you need to replace a substring or split up an array, you should consider using regular expressions. I will admit that I am not an expert in regards to using them, however, I will not dismiss their usefulness. You may find the RexEgg.com Regex Cheat Sheet very useful.

In Go, the regexp package includes many useful functions that utilize regular expressions.

Here is a simple CLI program that calculates the sum of the integer values in a string. It splits the string into a slice and then sums up all of the integer values in the slice. In this application, the string is split up using the regular expression [^0-9]+. The ^ indicates that that we do not want to match on a character that is an integer within the range of [0-9]. While the + “greedy” quantifier indicates that we want to match when there are one or more characters. In this example, we are simply delimiting the string based on non-digit values such as letters and other special characters.

One important thing to note about func (*Regexp) Split is that it creates an empty element in the slice if it starts splitting the string at the first or last element. In this example, this is handled by catching the error that is thrown when strconv.Atoi(intSlice[i]) fails to convert a string to an integer value at a given index. After an error is thrown, the bad index which is delete in place by taking the valid indexes up to the bad index and then appending the indexes that follow it. This is implemented with intSlice = append(intSlice[:i], intSlice[i:]...). After you remove the element, the length of the slice needs to be decremented.

SEE: SliceTricks

USAGE:
go run .\stringSum.go st1ngW1thIn7s

Screenshot:

Golang String Sum Windows
Golang String Sum Windows