Univers Libre

Using molecule with GitLab CI

Written on 21 April 2019, 01:40 CEST
Tags: ansible, sysadmin, tech.

This article follows this one where I talk about verifying and testing your Ansible roles with molecule.

As I wrote in this first article, I also configured GitLab CI to automatically run molecule tests after each push to the repository. A good documentation to start with is the official GitLab CI/CD documentation.

Here is our .gitlab-ci.yml (latest version) used on our ansible repository hosting all our roles:

---
image: quay.io/ansible/molecule:latest
services:
  - docker:dind

stages:
  - tests

before_script:
  - docker -v
  - python -V
  - ansible --version
  - molecule --version

molecule-role-common:
  stage: tests
  tags:
    - docker
  variables:
    DOCKER_HOST: "tcp://docker:2375"
    PY_COLORS: 1
  script:
    - cd roles/common/
    - molecule test
  only:
    changes:
      - roles/common/**/*

molecule-role-monitoring-tools:
  stage: tests
  tags:
    - docker
  variables:
    DOCKER_HOST: "tcp://docker:2375"
    PY_COLORS: 1
  script:
    - cd roles/monitoring-tools/
    - molecule test
  only:
    changes:
      - roles/monitoring-tools/**/*
[…]

Our repository is hosted on gitlab.com and even if we can connect our own GitLab Runners to gitlab.com instance, we decided to use the provided gitlab.com's shared runners to get started quickly.

Those use Docker to run the jobs. So we instantiate the official molecule image (from Red Hat's registry):

image: quay.io/ansible/molecule:latest

And since molecule also needs to spawn Docker containers, we need to start another container: docker:dind (Docker in Docker). This is done with:

services:
  - docker:dind

And by exporting the DOCKER_HOST variable to the jobs, so that molecule will be able to connect to the Docker daemon to manage its containers:

variables:
  DOCKER_HOST: "tcp://docker:2375"

Then we define one stage, called tests:

stages:
  - tests

Each jobs related to this stage will have the stage: tests key in their definition.

The before_script block is here for debugging purpose (if the molecule tests succeed locally bt fail on the runners, it may be because the tests are run with a different version of molecule).

Last, we define as many jobs as we have roles to test with molecule. Here, tags is important since it is used by GitLab CI to select the runner the job will be executed on. We need a runner with Docker, thus:

tags:
  - docker

With script keyword we specify each command the runner should run. Pretty self-explanatory:

script:
  - cd roles/monitoring-tools/
  - molecule test

And only adds kind of a condition to the job. We don't want to run all jobs if, for instance, someone updates the README file. The job should run only if a commit introduces a change to a file in the role itself. So we restrict the execution to a change under the role's hierarchy only with:

only:
  changes:
    - roles/monitoring-tools/**/*

For instance, this pipeline, triggered by the commit afe5929c, has spawned only one job, the molecule-role-firewall test, since only the firewall role was modified. Whereas this commit (which impacted multiple roles) triggered 7 jobs (and yes, one has failed).

If a job fails, the commiter will receive a notification by e-mail with the commit and job ID. We can check the job's output on GitLab, to see why it has failed.

As an ending note, to test your .gitlab-ci.yml without pushing, you can install the gitlab-runner package and run it on your repository (you still need to commit your changes since `gitlab-runner will checkout the repository):

$ gitlab-runner exec docker <your job name>