It is a good practice to place roles into a public or private galaxy and automatically test that they work after every change.
Create and activate virtualenv
virtualenv venv
source venv/bin/activate
Install Ansible and Molecule
pip install -r requirements.txt
molecule init role --role-name complicated-nginx
cd complicated-nginx
mkdir templates
cat <<'EOF' > templates/index.html.j2
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
<strong>Also please mind that here's some overly complicated stuff that we might see for example in configuration files sometimes:</strong>
{% for c in raw_data if mapping[c] in "deadbeef" %}{{ c }}{% endfor %}
</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
EOF
cat <<'EOF' > defaults/main.yml
---
raw_data: "eulmfkillcloldkue"
mapping:
q: o
c: d
e: d
o: b
i: a
d: e
p: u
r: k
a: l
m: o
f: e
l: u
k: z
u: w
EOF
cat <<'EOF' > tasks/main.yml
---
- name: generate index.html
template:
src: index.html.j2
dest: /usr/share/nginx/html/index.html
- name: start nginx
shell: nginx
tags: skip_ansible_lint
register: start_nginx
failed_when: "start_nginx.rc != 0 and 'Address in use' not in start_nginx.stderr"
changed_when: false
EOF
cat <<'EOF' > molecule/default/molecule.yml
---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
platforms:
- name: instance
image: nginx:alpine
published_ports:
- "0.0.0.0:80:80/tcp"
provisioner:
name: ansible
lint:
name: ansible-lint
scenario:
name: default
verifier:
name: testinfra
lint:
name: flake8
EOF
NOTE: before converging, please look at defaults and the index template and try to figure out what it will result into. This is just an example but there are many cases where infra code is complicated and testing needs to be in place. For example iptable rules could be generated in similar manner.
molecule converge
Open localhost. Did you guess the answer?
cat <<'EOF' > molecule/default/tests/test_default.py
import os
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
def test_index_file(host):
f = host.file('/usr/share/nginx/html/index.html')
assert "lollerskates" in f.content
EOF
Can you spot the error in provided test case?
molecule verify