Testing Ansible Roles with Molecule and Docker

# I will be taking this example on CentOS
# IT requires Ansible >= 2.2 and Python 2.7
sudo yum install -y epel-release
sudo yum install -y gcc python-pip python-devel openssl-devel
sudo python-pip install molecule
# This will initialize molecule-demo role and directory structure

molecule init role --driver-name docker --role-name molecule-demo --verifier-name testinfra
root@Ansible:/home/ubuntu/molecule-demo# tree
.
├── defaults
│ └── main.yml
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── molecule
│ └── default
│ ├── create.yml
│ ├── destroy.yml
│ ├── Dockerfile.j2
│ ├── INSTALL.rst
│ ├── molecule.yml
│ ├── playbook.yml
│ └── tests
│ ├── test_default.py
│ └── test_default.pyc
├── README.md
├── tasks
│ └── main.yml
└── vars
└── main.yml
8 directories, 14 files
# To run simple(default) test by molecule run following command$ molecule test
--> Test matrix
└── default
├── destroy
├── dependency
├── syntax
├── create
├── converge
├── idempotence
├── lint
├── side_effect
├── verify
└── destroy
--> Scenario: 'default'
--> Action: 'destroy'
PLAY [Destroy] *****************************************************************TASK [Destroy molecule instance(s)] ********************************************
ok: [localhost] => (item=(censored due to no_log))
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'syntax'
playbook: /home/ubuntu/molecule-demo/molecule/default/playbook.yml--> Scenario: 'default'
--> Action: 'create'
PLAY [Create] ******************************************************************TASK [Create Dockerfiles from image names] *************************************
changed: [localhost] => (item=(censored due to no_log))
TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item=(censored due to no_log))
TASK [Build an Ansible compatible image] ***************************************
changed: [localhost] => (item=(censored due to no_log))
TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=(censored due to no_log))
PLAY RECAP *********************************************************************
localhost : ok=4 changed=3 unreachable=0 failed=0
--> Scenario: 'default'
--> Action: 'converge'
PLAY [Converge] ****************************************************************TASK [Gathering Facts] *********************************************************
ok: [instance]
PLAY RECAP *********************************************************************
instance : ok=1 changed=0 unreachable=0 failed=0
--> Scenario: 'default'
--> Action: 'idempotence'
Idempotence completed successfully.
--> Scenario: 'default'
--> Action: 'lint'
--> Executing Yamllint on files found in /home/ubuntu/molecule-demo/...
Lint completed successfully.
--> Executing Flake8 on files found in /home/ubuntu/molecule-demo/molecule/default/tests/...
Lint completed successfully.
--> Executing Ansible Lint on /home/ubuntu/molecule-demo/molecule/default/playbook.yml...
Lint completed successfully.
--> Scenario: 'default'
--> Action: 'side_effect'
Skipping, side effect playbook not configured.
--> Scenario: 'default'
--> Action: 'verify'
--> Executing Testinfra tests found in /home/ubuntu/molecule-demo/molecule/default/tests/...
============================= test session starts ==============================
platform linux2 -- Python 2.7.12, pytest-3.2.2, py-1.4.34, pluggy-0.4.0
rootdir: /home/ubuntu/molecule-demo/molecule/default, inifile:
plugins: testinfra-1.6.3
collected 1 item
tests/test_default.py .=============================== warnings summary ===============================
None
Module already imported so can not be re-written: testinfra
-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 1 passed, 1 warnings in 4.39 seconds =====================
Verifier completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'
PLAY [Destroy] *****************************************************************TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=(censored due to no_log))
PLAY RECAP *********************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0
# put this code in task/main.yml
---
- name: "Installing httpd service"
yum:
name: httpd
state: installed
import osimport testinfra.utils.ansible_runnertestinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
def test_package(Package):
service = Package("httpd")
assert service.is_installed
root@Ansible:/home/ubuntu/molecule-demo# molecule test
--> Test matrix
└── default
├── destroy
├── dependency
├── syntax
├── create
├── converge
├── idempotence
├── lint
├── side_effect
├── verify
└── destroy
--> Scenario: 'default'
--> Action: 'destroy'
PLAY [Destroy] *****************************************************************TASK [Destroy molecule instance(s)] ********************************************
ok: [localhost] => (item=(censored due to no_log))
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'syntax'
playbook: /home/ubuntu/molecule-demo/molecule/default/playbook.yml--> Scenario: 'default'
--> Action: 'create'
PLAY [Create] ******************************************************************TASK [Create Dockerfiles from image names] *************************************
ok: [localhost] => (item=(censored due to no_log))
TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item=(censored due to no_log))
TASK [Build an Ansible compatible image] ***************************************
changed: [localhost] => (item=(censored due to no_log))
TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=(censored due to no_log))
PLAY RECAP *********************************************************************
localhost : ok=4 changed=2 unreachable=0 failed=0
--> Scenario: 'default'
--> Action: 'converge'
PLAY [Converge] ****************************************************************TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [molecule-demo : Installing httpd service] ********************************
changed: [instance]
PLAY RECAP *********************************************************************
instance : ok=2 changed=1 unreachable=0 failed=0
--> Scenario: 'default'
--> Action: 'idempotence'
Idempotence completed successfully.
--> Scenario: 'default'
--> Action: 'lint'
--> Executing Yamllint on files found in /home/ubuntu/molecule-demo/...
Lint completed successfully.
--> Executing Flake8 on files found in /home/ubuntu/molecule-demo/molecule/default/tests/...
Lint completed successfully.
--> Executing Ansible Lint on /home/ubuntu/molecule-demo/molecule/default/playbook.yml...
Lint completed successfully.
--> Scenario: 'default'
--> Action: 'side_effect'
Skipping, side effect playbook not configured.
--> Scenario: 'default'
--> Action: 'verify'
--> Executing Testinfra tests found in /home/ubuntu/molecule-demo/molecule/default/tests/...
============================= test session starts ==============================
platform linux2 -- Python 2.7.12, pytest-3.2.2, py-1.4.34, pluggy-0.4.0
rootdir: /home/ubuntu/molecule-demo/molecule/default, inifile:
plugins: testinfra-1.6.3
collected 1 item
tests/test_default.py .=============================== warnings summary ===============================
None
Module already imported so can not be re-written: testinfra
Package fixture is deprecated. Use host fixture and get Package module with host.package
TestinfraBackend fixture is deprecated. Use host fixture and get backend with host.backend
-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 1 passed, 3 warnings in 4.42 seconds =====================
Verifier completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'
PLAY [Destroy] *****************************************************************TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=(censored due to no_log))
PLAY RECAP *********************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0
---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
platforms:
- name: instance
image: centos:7
- name: instance2
image: centos:6.9
provisioner:
name: ansible
lint:
name: ansible-lint
scenario:
name: default
verifier:
name: testinfra
lint:
name: flake8

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store