ericsysmin's DevOps Blog

Ansible Collections: Testing only what’s changed

Ansible Collections: Testing only what’s changed

Previously

When testing roles before GitHub Actions, it was assumed that you’d only have one repository for each role. But with the addition of collections, that is no longer the case. Your collection can now have multiple roles, modules, and often you do not need to test everything when a role or a set of modules has changed.

Using GitHub Actions, there’s a way to do this.

Now with GitHub Actions

Using GitHub Actions and workflow, we can configure what actions will trigger a test (workflow) run. In my example, which I do use on all of my collections, I set only on Pull Request and Push will the tests be triggered.

So if you notice in the example, configured my test to run on both push and pull_request. Unfortunately, GitHub Actions doesn’t support anchors yet so I couldn’t use them.

Why did I choose those paths?

'roles/zabbix_agent/**'  – sets GitHub actions to watch all the files underneath the role zabbix_agent

'molecule/zabbix_agent/**'  – watches all the files part of the molecule testing for zabbix_agent

'.github/workflows/zabbix_agent.yml'  – the file that runs the GitHub Action workflow itself

The code here helps ensure that only when a file used for testing or executing this role is modified will it run and ensures that you don’t waste a lot of testing time on GitHub Actions so other tests can run on other repositories. You can find more options here https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#on

Continue reading...
Using a Dockerfile Repo for Molecule Dockerfiles

Using a Dockerfile Repo for Molecule Dockerfiles

I’d like to share with you another design in testing your Ansible collections, modules, playbooks, and roles. Molecule used to include a file name Dockerfile.j2. This template, in the past, created your docker container on execution. It’s since moved away from that and now only uses the base image you provide it via molecule.yml. In some cases, you need more than what the base image offers, and you may not want to create docker images and upload them to Docker Hub, or Quay.io. I wanted a solution and test that didn’t require people to download my docker images from Docker Hub.

Dockerfile.j2 with lots of Jinja

I prefer building my images using Dockerfile each time I test. It’s relatively quick and ensures that my host is testing against the latest packages that are installed by the Dockerfile.

However, I have lots of roles, and this means each role had at least one Dockerfile, and the Dockerfiles were precisely the same. A simple change to one Dockerfile usually said I needed to update all of the others. What if I need systemd installed? SystemD is different on many operating systems, different files needed, as well as various install commands. Well, I initially started building a more complicated Dockerfile.j2,which used the platform values from Molecule. But then after adding CentOS, Debian, Ubuntu, Fedora, and many of their different versions, it got complicated.

It was overly complicated, and I was losing track of the if/then statements, “Which OS should run which commands?” and many other questions. I gave up. It’s not maintainable. Especially when there have been PR’s adding support for SUSE, and ArchLinux, so now I need to add those to my tests. Three words. OUT OF HAND. So I had to change how I tested. I’m not going to duplicate a Dockerfile that’s this complicated, 10+ times per collection. Maybe I can do file links? That worked, but then I had to manage the same files in each of my Roles/Collections. Again, not scalable. I wanted something easy to do and easy to maintain and add new OS support when needed. Then a couple of things hit me.

  • Molecule Uses Ansible (obviously)
  • Ansible has Lookup Filters

URL Lookup for Dockerfile.j2

What if I could do a URL lookup against a GitHub repository that allows me to manage the same Dockerfiles for SystemD and Ansible dependencies on all of my roles. So, I deleted all the contents of Dockerfile.j2  and replaced it with this:

{{ lookup('url', 'https://raw.githubusercontent.com/ericsysmin/docker-ansible-images/master/' ~ item.image ~ '/Dockerfile', split_lines=False) }}

So each time Molecule runs, it connects to this file, grabs the Dockerfile, and then uses it to build each docker container used by Molecule. Now I can centrally manage all of my Dockerfile files, and simplify my Dockerfiles by removing all of the if/then statements, and other logic. This does require that your system running Molecule requires internet access to the file location, if it fails, the Molecule execution will also fail.

Now in each of my roles, throughout my collections and standalone, I can modify by Dockerfiles and manage them from one location just as if I decided to produce Docker images from these Dockerfiles and then share them on Docker Hub or Quay.io.

Continue reading...
Ansible Collections: Role Tests with Molecule

Ansible Collections: Role Tests with Molecule

As many of you know or are finding out, Ansible is moving to Collections. But what does that mean? Well, it’s been a long time waiting but Collections provide a way to namespace modules, roles, and playbooks that can all be combined in a single package for you to consume. It also allows businesses, partners, and contributors to update modules without adhering to the Ansible core release cycle. So, if AWS updates their API, then the modules that go with those will be instantly accessible, or at least faster than we used to wait for core releases to get those modules. But what does this mean for roles?

Move to FQCN (Fully Qualified Collection Name)

As many of us our finding out we are needing to move our roles to the collection design. However, now we need to figure out how to test them with the new design and using the Collection Namespaces aka FQCN (Fully Qualified Collection Name) So what we used to write

Will now end up something like this

We also are going to have a new folder structure using ansible_collections/namespace/collection_name

Luckily the molecule team and all of its contributors ensured that collections are recognized and supported. And I will cover how we can test this with GitHub Actions (which happen to also be the preferred way at this moment to test your collections on the official Ansible-Collections Github https://github.com/ansible-collections.

Single Command Testing

Example with multiple role tests in one collection molecule test.

As you see, in this format I had to make sure RedHat specific roles don’t get run on non-RedHat systems. But then this tests every role together and doesn’t easily allow me to scale to even more operating systems.  It will get long, and crazy with lots of when statements, and each time you add a role, you’ll have to edit this one and ensure the environment configuration is correct for all of the roles. It was at this point I realized maybe I should move away from Travis-CI, and also was encouraged to by the Ansible team. Gundalow and others recommended moving to GitHub Actions which are the preferred method now in the community. So I explored that option.

I also at this time decided to move away from the monolithic “default” scenario and instead divide scenarios based on roles. This is what I moved to.

Now I was able to individually ensure each environment was correct. That includes each roles’ dependencies, etc, and that it doesn’t affect the others. It prevented any form of cross-contamination on testing, and what’s expected in requirements. This fixed one of my issues I had with testing, however, it did add a bit of complexity, but each one is almost identical so I could easily copy and paste one of these to help build tests for the new role.

Matrix Testing with GitHub Actions

When I started testing how I would do this using Github Actions I explored using Matrix workflows. That looked something like this (which was really awesome because I couldn’t do it in Travis-CI…I don’t know if I can go back to Travis-CI because apparently for me GitHub tests are much faster.)

However, here’s the issue with this…each commit no matter where it’s made will trigger the matrix to execute meaning 4 x 6 tests! Even though I modified 1 role. Also, EPEL doesn’t work on Ubuntu or Debian. So then I’d have to use a lot of these exclude  statements:

Of course, that’s not scalable. So, I gave it a bit of thought. Why don’t we treat each role for what it is? It’s a separate role. Editing Role1 shouldn’t affect Role2 or even need to test Role2 in this situation. So I decided to create multiple workflows. Using GitHub Workflows I created the following structure.

Each workflow is specific to each role, and each one looks similar. This is the template I used.

You can change the operating systems if you want, this is just one of the examples I had. I solved the issue with the cross-contamination I had earlier, as well as made the tests easier to verify and check, as well as independent test state icons for the README.md. But I still had an issue. If I make a change to Role1, Role2 still builds…not desired and wastes build time against GitHub Actions.

Luckily in GitHub Actions, we can do include, or exclude paths on the trigger. So I replaced this section on: ["push", "pull_request"] with

So now the role only executes when the items specific to that role are edited. Saving me possibly money, and build time so other jobs in my GitHub can execute.

Now my completed .github/workflow/chrony.yml  looks like this:

Since these changes have been made now I am able to ensure that all of my roles are independently tested each time they are edited without treating everything as one giant repo and having tests run for 10+ minutes each as all of my roles execute. Now they are all tested in parallel, and against their own supported operating systems.

To see a copy of the repository used for this you can see https://github.com/ericsysmin/ansible-collection-system which you are free to clone, modify, change, use a reference. I did make changes to the Dockerfile because I do not host my own docker images, and don’t plan to. I highly suggested taking a look at my molecule/role_name/Dockerfile.j2  files to get an idea on what I did to get services to work. My changes to Dockerfile.j2 are based on Multi-distribution Ansible testing with Molecule on Travis-CI, and check out molecule/role_name/molecule.yml  to see how I pass through the parameters.

If you have questions please feel free to comment.

 

Continue reading...
Multi-distribution Ansible testing with Molecule on Travis-CI

Multi-distribution Ansible testing with Molecule on Travis-CI

In this post I will cover how to test Ansible roles against multiple distributions while using Molecule on Travis-CI. First of course you’d need access to Travis-CI, and a GitHub repo. But I am going to skip those details and assume you’ve already figured that part out. Hint: /git-root/.travis.yml

I am going to cover two scenarios: an existing Ansible role, and a new Ansible role. Both have a few different steps.

Getting Started

What is Molecule?

Molecule is a testing tool with support of multiple instances, roles, including dependent roles, and able to deploy against multiple operating systems, distributions, and virtualization providers including cloud platforms. It also provides you with the ability to use test frameworks to verify end results. Molecule also lets you test multiple test scenarios such as different configurations of the role.

First steps you’re going to need to install Molecule. For futures sake, I am not going to duplicate the how too, nor the steps as that can always change. Instead I am going to reference the molecule documentation.

https://molecule.readthedocs.io/en/stable/installation.html

So, on that page they cover how to install molecule and it’s required dependencies. If you have issues just find #ansible-molecule on Freenode IRC and people will help you.

You’ll also need to install docker. I’m also not going to show you how to install docker, it has changed a few times, and for the same of not screwing your environment up too much I’ll direct you to Docker’s official guide. You can find the steps for that located here:

https://docs.docker.com/install/

Existing Ansible Role

When we are using an existing Ansible role, it’s fairly safe to assume you have a “test” directory. We can essentially toss that one out, by toss it, delete it, move it, or convert it. It’s non-sense and doesn’t do much more but run the role locally. Who wants to test by editing your existing current host? Not me! We have better things like Docker to do that.

So, after Molecule, and Docker are installed, we can go ahead and work on getting Molecule setup on our existing role.

  1. Navigate to your role’s root
  2. In your role directory we need to initialize a new Molecule scenario.
  3. This will create a new folder named molecule in your roles root directory. In that folder you will have the following.

    These files are the default files created by molecule at the writing of this post. You can find out what each of these do at the Molecule documentation website. https://molecule.readthedocs.io/en/stable/ You can customize any of these to perform specific python testinfra, and other tests against your system.

Creating a New Role with Molecule Init

If you are starting from scratch and are creating a new role. The process to create the role is a bit easier. You’ll likely want to use these steps instead of the older ansible-galaxy init role_name process. Ansible Galaxy init process still creates the old tests which run locally, and don’t provide all of the lint tests, and other tests we’d want to make sure ran to verify quality of our role.

  1. To create the role we will run
  2. This will create the following directory tree in your roles root directory.

    These files are the default files created by molecule at the writing of this post. You can find out what each of these do at the Molecule documentation website. https://molecule.readthedocs.io/en/stable/ You can customize any of these to perform specific python testinfra, and other tests against your system.
  3. After this step you would work on your role and the tasks, vars, and other items needed. Once done creating the role, proceed to Configuring Molecule & Travis-CI for Multiple Distribution Testing.

Configuring Molecule & Travis-CI for Multiple Distribution Testing

  1. First file we want to edit is the molecule.yml  file. This file provides settings and configuration to Molecule when it runs. Initially the file will look like this

    By default Molecule will want to run your tests on CentOS 7 docker image. Yes you can add additional platforms here which would sequentially test on them. But the more listed the longer the test. These are not ran asynchronously. We want faster tests so we want to run asynchronously. We are going to change this file so that we can provide some values via Travis-CI. This is what it will look like.

    Adding the ${MOLECULE_DISTRO:-centos:7} allows us to specify as a var to molecule which docker image should be used in the testing process. :-centos:7 allows us to specify a default of centos:7 as the image. Without this then any situation without a MOLECULE_DISTRO  var would return an error.
  2. We will sometimes also want to edit the playbook.yml file located in the molecule/default/ directory. By default it will look like a plain role declaration as so.

    However, we may want to use some parameters, and we can do that as well.

    You can also have different playbook.yml files within the same scenario, or even multiple scenarios, but we can save that for another day.
  3. Next we will need to configure the Travis-CI configuration file. Basically since this file didn’t already exist you can use mine. Just make sure you replace my_role_name with the name of your role

    So, what this file will do is on Travis-CI create 8 different executions, each one with a different distribution and version using docker images of each. Then execute those in parallel. Each one will get a copy of the role, and execute the molecule tests against it.
  4. Once your role is properly added and repository enabled on Travis-CI you should end up seeing multiple build jobs for the build. Here’s a screenshot from an existing role I’ve built before.
  5. That’s it! You’re now finished! You’ve successfully configured molecule to test against multiple distributions.
Continue reading...