Testing Ansible roles for CentOS8 with Molecule and Vagrant

Since RHEL8/CentOS8 came out, I’ve been working on updating all my Ansible roles at work and at home to function run on the new OS. It can be a bit of a headache, since certain long-time features (NTP, for example) have disappeared and replaced with other things (Chrony).

However, the bigger headache turned out to be running Molecule tests on the roles. At home, I had been running Molecule 2.12.1, which is pretty old, along with Ansible 2.7.5, and those versions really don’t seem to get along with CentOS 8. They really really didn’t like if I tried to use Vagrant for testing, either. Some roles I was able to test with Docker, but it seemed kludgey, and some roles (anything that interacts with systemd, for example) just don’t work in a Docker container.

It took some trial and error, but I found a configuration that seems to do the job. I do my testing on a CentOS7 server (until I get my roles fixed I don’t plan to deploy CentOS 8 anywhere). I upgraded Molecule, Ansible, and Vagrant accordingly:

  • molecule==2.22
  • ansible==2.9.13 (selected automatically when I specified Molecule 2.22)
  • python-vagrant==0.5.15 (latest)
  • Vagrant 2.2.10

I know that Molecule 3.0x is available, but apparently it’s not really ready for primetime yet; the Vagrant provider doesn’t work at all with it.

Some gotchas:

  1. Molecule 2.22 requires python3, so you’ll need to install it via yum, dnf, or apt. I found that whatever active release of the “python36” and “python36-devel” packages available for CentOS work fine.
  2. Vagrant 2.2.10 requires the “fuse” and “fuse-libs” packages, at least on CentOS.
  3. You may have to update the molecule setup in your role with a “molecule init”. I ended up having to completely rebuild the molecule directory to get it to work with python3 and molecule 2.22, though I probably only really needed to create a new vagrant scenario and get rid of the old one. Run “molecule init –help” to get more information about this.
  4. I highly, highly recommend running the tests within a python virtual environment. This ensures that you have a “clean” setup every time you run the test, particularly if you’re automating it.

I have to admit: I was not very familiar with virtual environments prior to setting this up. (My python fu in general is pretty lacking, honestly.) It turned out to be fairly simple, though; to construct a virtual environment for python3, make sure that the “venv” package is installed:

pip3 install venv

And then create the virtual environment:

python3 -m venv my_venv

You can replace “my_venv” with whatever string you like; python will create a subdirectory wherever you are with that name. Then you activate it:

. my_venv/bin/activate

Now you have a completely clean python3 environment into which you can install the molecule, ansible, etc. packages. I put the list of packages and the versions I want into a pip-requirements.txt file that looks like this:

molecule==2.22
python-vagrant==0.5.15

Then it’s a matter of running the install:

pip install -r test/pip-requirements.txt

Doing this for every automated test does add some processing time, but it’s the best way to ensure that you have a completely clean python3 environment with the packages you want, along with their dependencies, and nothing that you don’t need.

If you’re running automated tests in Jenkins, there is a handy plugin named “Pyenv Pipeline” that allows you to wrap your stages and commands inside a “withPythonEnv” block like this:

      withPythonEnv('/usr/bin/python3') {
        stage ("Set up virtual environment") {
          sh 'pip install -r test/pip-requirements.txt'
        }
        stage ("Install vault password file") {
          withCredentials([string(credentialsId: 'ansiblevaultpass', variable: 'vault_pass')]) {
            sh "echo ${vault_pass} > test/.vault_pass"
            sh "chmod 0400 test/.vault_pass"
          }
        }
        stage ("Executing Molecule Lint") {
          sh 'molecule --debug lint'
        }
<snip>

Something else to remember is that the molecule linting features will look at the virtual environment directory unless told otherwise, so whatever you name your local directory needs to be ignored, as well as the one that’s created by the Jenkins plugin. Make sure they’re listed in the “ignore” block in the .yamllint file in the root directory:

---
# Based on ansible-lint config
extends: default

ignore: |
  .pyenv-python/
  molecule_venv/
  .pyenv-usr-bin-python3/

Python3 and python2 use different directories in the Jenkins plugin; .pyenv-python is for python2, and .pyenv-usr-bin-python3 is (obviously) for python3. “molecule_venv” is the one I created for local testing.

I found that git automatically ignored virtual environment directories. I’m not entirely clear on how it knew to do that, but i did not have to specifically exclude any of those directories in .gitignore.

Happy testing!