Select Page

The creator decided on the Mozilla Foundation to obtain a donation as a part of the Write for DOnations program.

Advent

Unit checking out in Ansible is secret to meaking certain roles serve as as supposed. Molecule makes this procedure more straightforward via permitting you to specify situations that take a look at roles in opposition to other environments. The usage of Ansible below the hood, Molecule offloads roles to a provisioner that deploys the function in a configured setting and calls a verifier (similar to Testinfra) to test for configuration go with the flow. This guarantees that your function has made the entire anticipated adjustments to the surroundings in that specific state of affairs.

On this information, you are going to construct an Ansible function that deploys Apache to a number and configures Firewalld. To check that this function works as supposed, you are going to create a take a look at in Molecule the usage of Docker as a motive force and Testinfra, a Python library for checking out the state of servers. Molecule will provision Docker boxes to check the function and Testinfra will test that the server has been configured as supposed. If you end up completed, you are able to create a couple of take a look at circumstances for builds throughout environments and run those assessments the usage of Molecule.

Necessities

Earlier than you start this information you’ll be able to want the next:

Step 1 — Making ready the Atmosphere

Let’s start via making a digital setting on our host and putting in the programs required for our take a look at inside that setting.

Get started via logging in as your non-root person and ensuring your repositories are up-to-date:

This may increasingly make certain that your package deal repository comprises the newest model of the python-pip package deal, which can set up pip and Python 2.7. We can use pip to create a digital setting and set up further programs. To put in pip, run:

  • sudo apt-get set up -y python-pip

Use pip to put in the virtualenv Python module and any updates:

  • pip set up pip virtualenv -U

The -U flag tells pip to replace any up to now put in programs.

Subsequent, let’s create and turn on the digital setting:

Turn on it to make certain that your movements are limited to that setting:

Set up molecule, ansible, and docker-py the usage of pip:

  • pip set up molecule ansible docker-py

Here’s what every of those programs will do:

  • molecule: That is the primary Molecule package deal, used for checking out roles.
  • ansible: This package deal allows the usage of Ansible playbooks, which execute the function and its related assessments.
  • docker-py: This Python library is utilized by Molecule to interface with Docker. We’d like this since we are the usage of Docker as a motive force.

Subsequent, let’s create a job in Molecule.

Step 2 — Making a Position in Molecule

With our surroundings arrange, let’s use Molecule to create a fundamental function that we’re going to use to check the set up of Apache. This procedure will create the listing construction and a few preliminary assessments, and specify Docker as the driving force in order that Molecule makes use of Docker to run its assessments.

Create a brand new function referred to as httpd:

  • molecule init function -r httpd -d docker

The -r flag specifies the title of the function, whilst -d specifies the driving force, which provisions the hosts for Molecule to make use of in checking out.

Turn out to be the listing of the newly created function:

Take a look at the default function to test if Molecule has been arrange correctly:

You’ll see output that can record every of the default take a look at movements:

Output

--> Validating schema /house/sammy/httpd/molecule/default/molecule.yml. Validation finished effectively. --> Take a look at matrix └── default ├── lint ├── wreck ├── dependency ├── syntax ├── create ├── get ready ├── converge ├── idempotence ├── side_effect ├── test └── wreck ...

Earlier than beginning the take a look at, Molecule validates the configuration dossier molecule.yml to verify the whole thing is so as. It additionally prints this take a look at matrix, which specifies the order of take a look at movements.

We can speak about every take a look at motion intimately as soon as we have now created our function and custom designed our assessments. For now, be aware of the PLAY_RECAP for every take a look at, and make certain that not one of the default movements returns a failed standing. For instance, the PLAY_RECAP for the default 'create' motion must appear to be this:

Output

... PLAY RECAP ********************************************************************* localhost : good enough=5 modified=4 unreachable=0 failed=0

Let’s transfer directly to enhancing our function to configure Apache and Firewalld.

Step 3 — Configuring Apache

To configure Apache, we will be able to create a duties dossier for the function, specifying programs to put in and services and products to permit. Those main points shall be extracted from a variables dossier and template that we will be able to use to switch the default Apache index web page.

Create a duties dossier for the function the usage of nano or your favourite textual content editor:

You’ll be able to see that the dossier already exists. Delete what is there and paste the next code to put in the desired programs and permit the right kind services and products, HTML defaults, and firewall settings:

~/httpd/duties/major.yml

---
- title: "Ensure required packages are present"
  yum:
    title: "{{ pkg_list }}"
    state: provide

- title: "Ensure latest index.html is present"
  template:
    src: index.html.j2
    dest: /var/www/html/index.html

- title: "Ensure httpd service is started and enabled"
  provider:
    title: "{{ item }}"
    state: began
    enabled: True
  with_items: "{{ svc_list }}"

- title: "Whitelist http in firewalld"
  firewalld:
    provider: http
    state: enabled
    everlasting: True
    speedy: True

This playbook comprises Four duties:

  • Make certain required programs are provide: This activity will set up the programs indexed within the variables dossier below pkg_list. The variables dossier shall be positioned at ~/httpd/vars/major.yml and you are going to create it on the finish of this segment.
  • Make certain newest index.html is provide: This activity will replica a template web page index.html.j2 and paste it over the default index dossier /var/www/html/index.html generated via Apache. You’ll additionally create this template on this step.
  • Make certain httpd provider is began and enabled: This activity will get started and permit the services and products indexed in svc_list within the variables dossier.
  • Whitelist http in firewalld: This activity will whitelist the http provider in firewalld. Firewalld is an entire firewall answer provide via default on CentOS servers. For the http provider to paintings, we wish to disclose the desired ports. Teaching firewalld to whitelist a provider guarantees that it whitelists all of the ports that the provider calls for.

Save and shut the dossier when you’re completed.

Subsequent, let’s create a templates listing for the index.html.j2 template web page:

Create the web page itself:

  • nano templates/index.html.j2

Paste within the following boilerplate code:

~/httpd/templates/index.html.j2

Controlled via Ansible

Save and shut the dossier.

The general step in finishing the function is writing the variables dossier, which supplies the names of programs and services and products to our major function playbook:

Paste over the default content material with the next code, which specifies pkg_list and svc_list:

vars/major.yml

---
pkg_list:
  - httpd
  - firewalld
svc_list:
  - httpd
  - firewalld

Those lists include the next data:

  • pkg_list: This incorporates the names of the programs that the function will set up: httpd and firewalld.
  • svc_list: This incorporates the names of the services and products that the function will get started and permit: httpd and firewalld.

Notice: Be sure that your variables dossier does not have any clean strains or your take a look at will fail all through linting.

Now that we have now completed growing our function, let’s configure Molecule to check if it really works as supposed.

Step 4 — Editing the Position for Operating Exams

Configuring Molecule comes to two steps: enhancing the Molecule configuration dossier itself, and making a customized yamllint dossier. Yamllint is a YAML code linter that exams for syntax validity, key repetition, and beauty issues like line size, trailing areas, and indentation.

Our adjustments will come with:

  • Including an approach to ~/httpd/molecule/default/molecule.yml to make use of a customized yamllint configuration dossier and growing the dossier itself. This dossier will permit two exceptions: strains more than 80 characters and truthy values. As a result of Ansible and Yamllint use conflicting syntax to precise truthy values, this will likely save you useless syntax mistakes.
  • Including platform specs. As a result of we are checking out a job that configures and begins the httpd systemd provider, we wish to use a picture with systemd configured and privileged mode enabled. For this instructional, we will be able to use the milcom/centos7-systemd symbol available on Docker Hub. Privileged mode permits boxes to run with nearly the entire functions in their host gadget.

Let’s edit molecule.yml to replicate those adjustments:

  • nano molecule/default/molecule.yml

Upload the highlighted yamllint choices and platform data:

~/httpd/molecule/default/molecule.yml

---
dependency:
  title: galaxy
motive force:
  title: docker
lint:
  title: yamllint
  choices:
    config-file: molecule/default/yamllint.yml
platforms:
  - title: centos7
    symbol: milcom/centos7-systemd
    privileged: True
provisioner:
  title: ansible
  lint:
    title: ansible-lint
state of affairs:
  title: default
verifier:
  title: testinfra
  lint:
    title: flake8

Save and shut the dossier when you’re achieved.

Notice the reference in molecule.yml to the yamllint dossier at molecule/default/yamllint.yml. Let’s create this dossier:

  • nano molecule/default/yamllint.yml

Input the customized configuration on your take a look at setting via pasting the next regulations, which outline line size specs and truthy price settings:

~/httpd/molecule/default/yamllint.yml

---
extends: default
regulations:
  line-length:
    max: 120
    stage: caution
  truthy: disable

We have added two regulations:

  • line_length: This rule specifies that the utmost allowed line size is 120 characters (up from 80 characters), and that the linter must throw a caution if the rule of thumb is violated.
  • truthy: This rule disables truthy values since Ansible and Yamllint use conflicting syntax to precise them. This may increasingly save you useless syntax mistakes.

Now that we have now effectively configured the take a look at setting, let’s transfer directly to writing the take a look at circumstances that Molecule will run in opposition to our container after executing the function.

Step 5 — Writing Take a look at Circumstances

Within the take a look at for this function, we will be able to test the next prerequisites:

  • That the httpd and firewalld programs are put in.
  • That the httpd and firewalld services and products are operating and enabled.
  • That the http provider is enabled in our firewall settings.
  • That index.html incorporates the similar knowledge laid out in our template dossier.

If all of those assessments cross, then the function works as supposed.

To jot down the take a look at circumstances for those prerequisites, let’s edit the default assessments in ~/httpd/molecule/default/assessments/test_default.py. The usage of Testinfra, we will be able to write the take a look at circumstances as Python purposes that use Molecule categories.

Open test_default.py:

  • nano molecule/default/assessments/test_default.py

Delete the contents of the dossier so to write the assessments from scratch.

Notice: As you write your assessments, ensure that they’re separated via two new strains or they are going to fail.

Get started via uploading the desired Python modules:

~/httpd/molecule/default/assessments/test_default.py

import os
import pytest

import testinfra.utils.ansible_runner

Those modules come with:

  • os: This integrated Python module allows operating-system-dependent capability, making it conceivable for Python to interface with the underlying working formulation.
  • pytest: The pytest module allows take a look at writing.
  • testinfra.utils.ansible_runner: This Testinfra module makes use of Ansible as the backend for command execution.

Below the module imports, paste within the following code, which makes use of the Ansible backend to go back the present host example:

~/httpd/molecule/default/assessments/test_default.py

...
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')

With our take a look at dossier configured to make use of the Ansible backend, let’s write unit assessments to check the state of our host.

The primary take a look at will make certain that httpd and firewalld are put in:

~/httpd/molecule/default/assessments/test_default.py

... 

@pytest.mark.parametrize('pkg', [
  'httpd',
  'firewalld'
])
def test_pkg(host, pkg):
    package deal = host.package deal(pkg)

    assert package deal.is_installed

The take a look at starts with the pytest.mark.parametrize decorator, which permits us to parameterize the arguments for the take a look at. This primary take a look at will take test_pkg as a parameter to check for the presence of the httpd and firewalld programs.

The following take a look at exams whether or not or no longer httpd and firewalld are operating and enabled. It takes test_svc as a parameter:

~/httpd/molecule/default/assessments/test_default.py

... 

@pytest.mark.parametrize('svc', [
  'httpd',
  'firewalld'
])
def test_svc(host, svc):
    provider = host.provider(svc)

    assert provider.is_running
    assert provider.is_enabled

The remaining take a look at exams that the information and contents handed to parametrize() exist. If the dossier is not created via our function and the content material is not set correctly, assert will go back False:

~/httpd/molecule/default/assessments/test_default.py

... 

@pytest.mark.parametrize('dossier, content material', [
  ("/etc/firewalld/zones/public.xml", ""),
  ("/var/www/html/index.html", "Managed by Ansible")
])
def test_files(host, dossier, content material):
    dossier = host.dossier(dossier)

    assert dossier.exists
    assert dossier.incorporates(content material)

In every take a look at, assert will go back True or False relying at the take a look at consequence.

The completed dossier seems like this:

~/httpd/molecule/default/assessments/test_default.py

import os
import pytest

import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')


@pytest.mark.parametrize('pkg', [
  'httpd',
  'firewalld'
])
def test_pkg(host, pkg):
    package deal = host.package deal(pkg)

    assert package deal.is_installed


@pytest.mark.parametrize('svc', [
  'httpd',
  'firewalld'
])
def test_svc(host, svc):
    provider = host.provider(svc)

    assert provider.is_running
    assert provider.is_enabled


@pytest.mark.parametrize('dossier, content material', [
  ("/etc/firewalld/zones/public.xml", ""),
  ("/var/www/html/index.html", "Managed by Ansible")
])
def test_files(host, dossier, content material):
    dossier = host.dossier(dossier)

    assert dossier.exists
    assert dossier.incorporates(content material)

Now that we have now specified our take a look at circumstances, let’s take a look at the function.

Step 6 — Checking out the Position with Molecule

When we begin the take a look at, Molecule will execute the movements we outlined in our state of affairs. We can run the default molecule state of affairs once more, executing the movements within the default take a look at collection whilst taking a look extra intently at every.

Run the take a look at for the default state of affairs once more:

This may increasingly begin the take a look at run. The preliminary output prints the default take a look at matrix:

Output

--> Validating schema /house/sammy/httpd/molecule/default/molecule.yml. Validation finished effectively. --> Take a look at matrix └── default ├── lint ├── wreck ├── dependency ├── syntax ├── create ├── get ready ├── converge ├── idempotence ├── side_effect ├── test └── wreck

Let’s undergo every take a look at motion and the predicted output, beginning with linting.

The linting motion executes yamllint, flake8, and ansible-lint:

  • yamllint: This linter is accomplished on all YAML information provide within the function listing.
  • flake8: This Python code linter exams assessments created for Testinfra.
  • ansible-lint: This linter for Ansible playbooks is accomplished in all situations.

Output

... --> Situation: 'default' --> Motion: 'lint' --> Executing Yamllint on information present in /house/sammy/httpd/... Lint finished effectively. --> Executing Flake8 on information present in /house/sammy/httpd/molecule/default/assessments/... Lint finished effectively. --> Executing Ansible Lint on /house/sammy/httpd/molecule/default/playbook.yml... Lint finished effectively.

The following motion, wreck, is accomplished the usage of the wreck.yml dossier. That is achieved to check our function on a newly created container.

Via default, wreck is named two times: originally of the take a look at run, to delete any pre-existing boxes, and on the finish, to delete the newly created container:

Output

... --> Situation: 'default' --> Motion: 'wreck' PLAY [Destroy] ***************************************************************** TASK [Destroy molecule instance(s)] ******************************************** modified: [localhost] => (merchandise=None) TASK [Wait for instance(s) deletion to complete] ******************************* good enough: [localhost] => (merchandise=None) TASK [Delete docker network(s)] ************************************************ PLAY RECAP ********************************************************************* localhost : good enough=2 modified=1 unreachable=0 failed=0

After the wreck motion is whole, the take a look at will transfer directly to depedency. This motion lets you pull dependencies from ansible-galaxy in case your function calls for them. On this case, our function does no longer:

Output

... --> Situation: 'default' --> Motion: 'dependency' Skipping, lacking the necessities dossier.

The following take a look at motion is a syntax test, which is accomplished at the default playbook.yml playbook. It really works similarly to the --syntax-check flag within the command ansible-playbook --syntax-check playbook.yml:

Output

... --> Situation: 'default' --> Motion: 'syntax' playbook: /house/sammy/httpd/molecule/default/playbook.yml

Subsequent, the take a look at strikes directly to the create motion. This makes use of the create.yml dossier in our function’s Molecule listing to create a Docker container with our specs:

Output

... --> Situation: 'default' --> Motion: 'create' PLAY [Create] ****************************************************************** TASK [Log into a Docker registry] ********************************************** skipping: [localhost] => (merchandise=None) TASK [Create Dockerfiles from image names] ************************************* modified: [localhost] => (merchandise=None) TASK [Discover local Docker images] ******************************************** good enough: [localhost] => (merchandise=None) TASK [Build an Ansible compatible image] *************************************** modified: [localhost] => (merchandise=None) TASK [Create docker network(s)] ************************************************ TASK [Create molecule instance(s)] ********************************************* modified: [localhost] => (merchandise=None) TASK [Wait for instance(s) creation to complete] ******************************* modified: [localhost] => (merchandise=None) PLAY RECAP ********************************************************************* localhost : good enough=5 modified=4 unreachable=0 failed=0

After create, the take a look at strikes directly to the get ready motion. This motion executes the get ready playbook, which brings the host to a particular state ahead of operating converge. This turns out to be useful in case your function calls for a pre-configuration of the formulation ahead of the function is accomplished. Once more, this doesn’t observe to our function:

Output

... --> Situation: 'default' --> Motion: 'get ready' Skipping, get ready playbook no longer configured.

After get ready, the converge motion executes your function at the container via operating the playbook.yml playbook. If a couple of platforms are configured within the molecule.yml dossier, Molecule will converge on all of those:

Output

... --> Situation: 'default' --> Motion: 'converge' PLAY [Converge] **************************************************************** TASK [Gathering Facts] ********************************************************* good enough: [centos7] TASK [httpd : Ensure required packages are present] **************************** modified: [centos7] => (merchandise=[u'httpd', u'firewalld']) TASK [httpd : Ensure latest index.html is present] ***************************** modified: [centos7] TASK [httpd : Ensure httpd service is started and enabled] ********************* modified: [centos7] => (merchandise=httpd) modified: [centos7] => (merchandise=firewalld) TASK [httpd : Whitelist http in firewalld] ************************************* modified: [centos7] PLAY RECAP ********************************************************************* centos7 : good enough=5 modified=4 unreachable=0 failed=0

After coverge, the take a look at strikes directly to idempotence. This motion assessments the playbook for idempotence to verify no surprising adjustments are made in a couple of runs:

Output

... --> Situation: 'default' --> Motion: 'idempotence' Idempotence finished effectively.

The following take a look at motion is the side-effect motion. This permits you to produce scenarios by which you are able to take a look at extra issues, like HA failover. Via default, Molecule does not configure a side-effect playbook and the duty is skipped:

Output

... --> Situation: 'default' --> Motion: 'side_effect' Skipping, aspect impact playbook no longer configured.

Molecule will then run the verifier motion the usage of the default verifier, Testinfra. This motion executes the assessments you wrote previous in test_default.py. If all of the assessments cross effectively, you are going to see a luck message and Molecule will continue to the next move:

Output

... --> Situation: 'default' --> Motion: 'test' --> Executing Testinfra assessments present in /house/sammy/httpd/molecule/default/assessments/... ============================= take a look at consultation begins ============================== platform linux2 -- Python 2.7.12, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /house/sammy/httpd/molecule/default, inifile: plugins: testinfra-1.12.0 accrued 6 pieces assessments/test_default.py ...... [100%] ========================== 6 handed in 37.88 seconds =========================== Verifier finished effectively.

After all, Molecule destroys the circumstances finished all through the take a look at and deletes the community assigned to these circumstances:

Output

... --> Situation: 'default' --> Motion: 'wreck' PLAY [Destroy] ***************************************************************** TASK [Destroy molecule instance(s)] ******************************************** modified: [localhost] => (merchandise=None) TASK [Wait for instance(s) deletion to complete] ******************************* modified: [localhost] => (merchandise=None) TASK [Delete docker network(s)] ************************************************ PLAY RECAP ********************************************************************* localhost : good enough=2 modified=2 unreachable=0 failed=0

The take a look at movements are actually whole, verifying that our function labored as supposed.

Conclusion

On this article you created an Ansible function to put in and configure Apache and Firewalld. Then you definately wrote unit assessments with Testinfra that Molecule used to claim that the function ran effectively.

You’ll be able to use the similar fundamental approach for extremely advanced roles, and automate checking out the usage of a CI pipeline as smartly. Molecule is a extremely configurable instrument that can be utilized to check roles with any suppliers that Ansible helps, no longer simply Docker. Additionally it is conceivable to automate checking out in opposition to your individual infrastructure, ensuring that your roles are at all times up-to-date and purposeful. The reliable Molecule documentation is the most productive useful resource for studying methods to use Molecule.