In the DevOps lifecycle, configuration management has always been an integral part of maintaining the desired system state. Many common tools such as Chef, Puppet, Ansible, SaltStack were used for configuration management. But before the configuration can be used in production, it has to be tested because different systems behave differently with the same configuration. So we have to be aware that our desired configuration state goes through every test scenario before it is applied to production. This is where Molecule comes into play.
Molecule has been specially developed for testing Ansible Reels under various operating systems. It uses the Ansible Playbook to determine which Ansible role to test. Molecule uses Serverspec, Testinfra and Goss as Verifier backend. To learn more about Molecule, click here. Molecule supports multiple backends such as Vagrant, Docker and OpenStack. With Molecule you can use Serverspec (Like Test Kitchen) but also ‘Testinfra’. Like Serverspec, Testinfra is a tool for writing unit tests, but it is written in Python.
To get started with Molecule just install it as python library, along with docker:
pip install ansible molecule docker
Voilà, it’s installed. With the installation of Molecule Testinfra is installed. For reference I use my docker-hardening role in the further steps. If you want to create a new Ansible role from scratch Molecule can help you here:
molecule init --driver docker --role role_name
In both examples the source code already contains a folder called molecule. All tests and docker configurations can be found here. The Molecule configuration is located in the molecule/default/molecule.ymlfile file:
The interesting part is that we use for this example docker as backend driver and also linting our YAML files with yamllint. To configure docker Molecule will generate an Docker image with the help of a template and start it:
- name: instance
The important thing here is the privileged and capabilities part: To use a systemd unit in Docker you need this. Therefore, we need to adjust the docker configuration to run the system in docker containers. This configuration consists of approving the container core to:
- allow application access to the calling system process (security_opts)
- making the container similar to the host (privileged)
- configuring the Selinux container (capabilities), and writing the container to host memory.
Remember that these docking images may only be used in test environments and not in production.
If you run
molecule test, Molecule normally runs in the following sequence:
Molecule will run a number of tests, either the default values like linting, idempotence etc., all of which are configurable under the configuration file molecule.yml for each scenario.
After completion of the tests, the Molecule destroys the container named instance-to-test-ansible, as described in the configuration.
It’s quite handy, but in case of debugging failing tests it may be annoying to create the setup again. So in this case you can use
molecule test --destroy=never, which leads to skipping the last destroy step.
When it comes to the structure of different Molecule “playbooks” I recommend the following structure:
- create is for docker driver already covered by creating a docker instance
- prepare should be used for basic setup, e.g preparing the docker instance with certain packages. That’s the reason I mostly name this file also
- converge should mostly just call the appropriate playbook, so it’s a good idea to call it
- destroy should be used to clean up certain stuff, like a tear down script
import testinfra.utils.ansible_runner testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') def test_docker(host):
daemon = host.service("docker")
It provides access to the provisioned Ansible machine and allows the verification of the automation scripts, e.g. check if daemon is running on a certain network interface.
I hope you like this little introduction into testing Ansible playbooks with Molecule. You can also use Molecule to engineer your playbooks in TDD-style…