- name: Install packages package: name: "{{ item }}" state: present with_items: "{{ packagesToInstall }}"
packagesToInstall: ['logrotate', 'bzip2']
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.fixture
def get_vars(host):
defaults_files = "file=../../defaults/main.yml name=role_defaults"
ansible_vars = host.ansible(
"include_vars",
defaults_files)["ansible_facts"]["role_defaults"]
return ansible_vars
def test_packagesAreInstalled(get_vars, host):
for packageName in get_vars['packagesToInstall']:
package = host.package(packageName)
assert package.is_installed
--- dependency: name: galaxy driver: name: docker lint: name: yamllint options: config-file: molecule/default/yamllint.yml platforms: - name: ubuntu1604 image: ubuntu:16.04 privileged: True provisioner: name: ansible lint: name: ansible-lint scenario: name: default verifier: name: testinfra lint: name: flake8 options: max-line-length: 150
--- extends: myScenario rules: comments: disable comments-indentation: disable colons: max-spaces-before: 0 max-spaces-after: -1 line-length: max: 150 level: warning truthy: disable
This is pretty straightforward once you RTFM : use state: present
instead of state: latest
--> Validating schema /home/bob/v_molecule/Ansible_Roles/roles/logrotate/molecule/myScenario/molecule.yml. Validation completed successfully. --> Test matrix └── myScenario ├── lint ├── dependency ├── cleanup ├── destroy ├── syntax ├── create ├── prepare ├── converge ├── idempotence ├── side_effect ├── verify ├── cleanup └── destroy --> Scenario: 'myScenario' --> Action: 'lint' --> Scenario: 'myScenario' --> Action: 'dependency' --> Scenario: 'myScenario' --> Action: 'cleanup' --> Scenario: 'myScenario' --> Action: 'destroy'
Molecule action | Description | --> Test matrix (when running molecule action) |
---|---|---|
lint | syntax checking (yamllint + flake8 + ansible-lint) | └── myScenario
└── lint |
dependency | manage the role's dependencies (allows to pull dependencies from Ansible Galaxy if required) | └── myScenario
└── dependency |
cleanup | use the provisioner to cleanup any changes made to external systems during the stages of testing (by default : no action configured, nothing to do) | └── myScenario
└── cleanup |
destroy | use the provisioner to destroy the instances, based on destroy.yml
|
└── myScenario
├── dependency
├── cleanup
└── destroy |
syntax | works in a similar way to the --syntax-check flag in the command ansible-playbook --syntax-check playbook.yml | └── myScenario
└── syntax |
create | provision the test node(s), based on create.yml | └── myScenario
├── dependency
├── create
└── prepare |
prepare | Use the provisioner to prepare the instances into a particular starting state by running the "prepare" playbook : myRole/molecule/myScenario/prepare.yml | └── myScenario
└── prepare
|
converge | actually execute the role inside the test node by executing molecule/myScenario/playbook.yml | └── myScenario
├── dependency
├── create
├── prepare
└── converge |
idempotence | make sure no unexpected changes are made in multiple runs | └── myScenario
└── idempotence |
side_effect | test advanced stuff like HA failover (by default, nothing to do)
this is launched with the command : molecule side-effect
|
└── myScenario
└── side_effect |
verify | executes the tests you wrote earlier in test_myScenario.py | └── myScenario
└── verify |
For details on any of these actions :
This procedure and every further documentation will deliberately ignore everything related to Python 2 (methods, commands, tools, ...).
Cloning into 'Ansible_Roles'...
done.
$HOME/ |---- v_molecule/ | |---- Ansible_Roles/ | | |---- roles/ | | | |---- haproxy | | | |---- logrotate | | | |---- mysql | | | |---- | | | |---- role_nLet's pick a role to start working with :
--> Initializing new scenario myScenario... Initialized scenario in /home/bob/v_molecule/Ansible_Roles/roles/logrotate/molecule/myScenario successfully.
--- dependency: name: galaxy driver: what we'll use to provision the nodes we'll be testing on (details) name: docker lint: name: yamllint options: config-file: molecule/myScenario/yamllint.yml platforms: - name: ubuntu1604 image: ubuntu:16.04 privileged: True provisioner: name: ansible lint: name: ansible-lint scenario: name: myScenario verifier: the unit test framework we'll use name: testinfra lint: name: flake8
cat << EOF > molecule/myScenario/yamllint.yml--- extends: myScenario rules: line-length: max: 120 level: warning truthy: disableEOF
cd -- molecule destroy -bash: cd: too many argumentsmake sure you have enabled your Python virtual environment
TASK [Build an Ansible compatible image (new)] *********************************
changed: [localhost] => (item=molecule_local/ubuntu:16.04)
TASK [Build an Ansible compatible image (new)] *********************************
ok: [localhost] => (item=molecule_local/ubuntu:16.04)
NOT HAPPY!!!with a lot to complain about :
import os import pytest import testinfra.utils.ansible_runner testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE'] ).get_hosts('all') def test_hosts_file(host): f = host.file('/etc/hosts') assert f.exists assert f.user == 'root' assert f.group == 'root' @pytest.mark.parametrize('pkg', [ 'logrotate', 'bzip2' ]) def test_pkg(host, pkg): package = host.package(pkg) assert package.is_installed