Automated Ansible Testing with Molecule
2017-09-30
Infrastructure testing provides some challenges just because of the mere fact you are building machines and not just compiling code. To test Ansible, I used to run Ansible with --syntax-check--syntax-check and --list-tasks--list-tasks. For roles I would run local tests with Vagrant using the tests/ directory in the role. The tests had Ansible test itself with the uri module or other checks. This is ok for simple checks but can be cumbersome and time consuming as it doesn’t catch everything.
Molecule has made this very simple. Install Molecule with pip install molecule. Create your role with molecule init --role-name role --driver-name drivermolecule init --role-name role --driver-name driver. The current drivers are Docker, OpenStack, Vagrant, EC2, GCE, LXC, LXD, and a few others with Docker being the default. It’s not absolutely required to build the role with molecule init but it adds the molecule dir with default testing and the .yamllint file.
Rather than rewrite their documentation, I’ll just go through what I have set up to test my roles. Currently I’m using the Vagrant driver with a CentOS 7 box ( I don’t do much with non RHEL distros) and the libvirt provider for Vagrant. So here’s what my molecule/molecule.yml file looks like:
---dependency: name: galaxydriver: name: vagrant provider: name: libvirtlint: name: yamllintplatforms: - name: bind box: centos/7provisioner: name: ansible lint: name: ansible-lintscenario: name: defaultverifier: name: testinfra options: sudo: True lint: name: flake8
---dependency: name: galaxydriver: name: vagrant provider: name: libvirtlint: name: yamllintplatforms: - name: bind box: centos/7provisioner: name: ansible lint: name: ansible-lintscenario: name: defaultverifier: name: testinfra options: sudo: True lint: name: flake8
Molecule also uses testinfra to run automated tests against the Vagrant box. Here’s a simple example to check a firewalld role:
import osimport testinfra.utils.ansible_runnertestinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')def test_firewall_installed(host): package = host.package("firewalld") assert package.is_installeddef test_firewall_service(host): service = host.service("firewalld") assert service.is_running assert service.is_enableddef test_firewall_config(host): config = host.file("/etc/firewalld/zones/public.xml") assert config.exists assert config.contains('<service name="http"/>') assert config.contains('<service name="https"/>') assert config.contains('<service name="ssh"/>')
import osimport testinfra.utils.ansible_runnertestinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')def test_firewall_installed(host): package = host.package("firewalld") assert package.is_installeddef test_firewall_service(host): service = host.service("firewalld") assert service.is_running assert service.is_enableddef test_firewall_config(host): config = host.file("/etc/firewalld/zones/public.xml") assert config.exists assert config.contains('<service name="http"/>') assert config.contains('<service name="https"/>') assert config.contains('<service name="ssh"/>')
Testinfra will check that the package firewalld is installed, the service is running and enabled, and that the /etc/firewalld/zones/public.xml/etc/firewalld/zones/public.xml file contains the services defined.
To start your molecule testing you can run molecule test.
Here is a video running this setup against a firewalld role