Dans ce didacticiel, nous allons apprendre à tester le code du framework écrit dans Ansible à l'aide d'un framework de test appelé Molecule. À l'intérieur de Molecule, nous utiliserons Ansible comme vérificateur, que je n'ai trouvé nulle part ailleurs. Faisons le!
Contenu
- introduction
- Installation de la molécule
- Molecule Ansible
- Ansible Ansible Verifier
Ansible — , , , , . , . -.
, . . , , , , .
Molecule — , Ansible. 26 Ansible Molecule Ansible-lint Red Hat Ansible. Red Hat , , .
Molecule , , , .
Molecule TDD- . , , , Molecule.
Molecule
, UNIX.
Molecule :
- Python 2.7 Python 3.5 ( Python 3.7)
- Ansible 2.5 ( Ansible 2.9.6)
- Docker ( )
Pip — Molecule. Python 2.7.9 ( ) Python 3.4 ( ), PIP Python.
Molecule pip:
$ pip3 install molecule
. « Molecule». , Molecule, $ molecule --version
.
Ansible Playbooks , , Ansible , .. Ansible , , , , , , , Ansible, , , — , , (, ).
Molecule Ansible
Molecule Ansible:
. Molecule Ansible
Molecules Ansible Galaxy Ansible. Molecule:
$ molecule init role <the_role_name>
. Initiating Ansible
Molecule , , , , , :
$ molecule init scenario -r <the_already_existing_role_name>
, Molecule, Molecule . :
.
├── README.md
├── files/
├── handlers/
├── meta/
├── tasks/
├── templates/
├── tests/
├── vars/
└── molecule/
└── default
├── molecule.yml
├── converge.yml
├── verify.yml
└── INSTALL.rst
Molecule :
molecule.yml
molecule.yml Molecule, .
---
dependency:
name: galaxy
enabled: true # to disable, set to false
driver:
name: docker
platforms:
- name: instance
image: docker.io/pycontribs/centos:7
pre_build_image: true
provisioner:
name: ansible
verifier:
name: ansible
dependency:
, . Ansible Galaxy — , Molecule. — Shell Gilt. dependency
true
, , enabled
false.
driver:
Molecule, . Molecule — Docker, , : AWS, Azure, Google Cloud, Vagrant, Hetzner Cloud . . Molecule .
platforms:
, . , , , , .
provisioner:
Provider — , converge.yml ( ). — Ansible.
verifier:
verifier — , . verify.yml, , ( ) ( ). — Ansible, , : testinfra, goss inspec. testinfra , - UX , Python, testinfra , Ansible , . git issue .
, , — lint . Molevel.yml .
lint:
Lint , Molecule , , , . — yamllint, ansible-lint, flake8 .
scenario:
Molecule. , , . , .
, — , Molecule. , :
scenario:
create_sequence:
- dependency
- create
- prepare
check_sequence:
- dependency
- cleanup
- destroy
- create
- prepare
- converge
- check
- destroy
converge_sequence:
- dependency
- create
- prepare
- converge
destroy_sequence:
- dependency
- cleanup
- destroy
test_sequence:
- dependency
- lint
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- cleanup
- destroy
, , Molecule, , $ molecule create
, create_sequence, $ molecule check
check_sequence .
, , , , , , .
Converge.yml
converge.yml, , , . . , $ molecule converge
.
verify.yml
verify.yml , . , . , $ molecule verify
.
INSTALL.rst
, Molecule .
Ansible Ansible Verifier
, , , Ansible Ansible Molecule.
$ molecule test
test_sequence, , , , , .
, , BDD, :
# given phase
$ molecule create
# when phase
$ molecule converge
# then phase
$ molecule verify
, () . , .
— TDD . . , alpha-services, :
- 1. Java-1.8 -.
- 2:
/var/log/tomcat
,tomcat
,tomcat
0755
- 3. , httpd
- 4.
template/tomcat/context.xml
/etc/tomcat/context.xml
, Molecule :
$ molecule init role alpha-services
, . alpha-services/molecule/default/roles/test_alpha-services
:
$ cd alpha-services
$ mkdir -p molecule/default/roles/test_alpha-services
. test_alpha-services
, Ansible ( , , , ). main.yml. yml, , test_
. , java test_java.yml
.
$ cd molecule/default/roles/test_alpha-services
$ mkdir defaults && touch defaults/main.yml
$ mkdir tasks && touch tasks/main.yml tasks/test_java.yml tasks/test_tomcat.yml tasks/test_httpd.yml tasks/test_aws.yml
$ mkdir vars && touch vars/main.yml
:
alpha-services/
├── README.md
├── files/
├── handlers/
├── meta/
├── tasks/
├── templates/
├── tests/
├── vars/
└── molecule/
└── default
├── molecule.yml
├── converge.yml
├── verify.yml
├── INSTALL.rst
└── roles/
└── test_alpha-services/
├── defaults/
└── main.yml
├── tasks/
├── main.yml
├── test_java.yml
├── test_tomcat.yml
├── test_httpd.yml
└── test_aws.yml
└── vars/
└── main.yml
molecule.yml:
---
dependency:
name: galaxy
enabled: false
driver:
name: docker
platforms:
- name: instance
image: docker.io/pycontribs/centos:7
pre_build_image: true
provisioner:
name: ansible
verifier:
name: ansible
converge.yml :
---
- name: Converge
hosts: all
tasks:
- name: "Include alpha-services"
include_role:
name: "alpha-services"
verify.yaml, :
---
# This is an example playbook to execute Ansible tests.
- name: Verify
hosts: all
tasks:
- name: "Include test_alpha-services"
include_role:
name: "test_alpha-services"
GIVEN : $ molecule create
.
$ molecule create
--> Test matrix
└── default
├── dependency
├── create
└── prepare
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, dependency is disabled.
--> Scenario: 'default'
--> Action: 'create'
--> Sanity checks: 'docker'
PLAY [Create] ******************************************************************
TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item=None)
TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item=None)
TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/pycontribs/centos:7)
TASK [Create docker network(s)] ************************************************
TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=instance)
TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: Wait for instance(s) creation to complete (300 retries left).
changed: [localhost] => (item=None)
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=5 changed=2 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
--> Scenario: 'default'
--> Action: 'prepare'
Skipping, prepare playbook not configured.
WHEN : $ molecule converge
, . .
$ molecule converge
--> Test matrix
└── default
├── dependency
├── create
├── prepare
└── converge
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, dependency is disabled.
--> Scenario: 'default'
--> Action: 'create'
Skipping, instances already created.
--> Scenario: 'default'
--> Action: 'prepare'
Skipping, prepare playbook not configured.
--> Scenario: 'default'
--> Action: 'converge'
--> Sanity checks: 'docker'
PLAY [Converge] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Include alpha-services] **************************************************
TASK [alpha-services : include java installation tasks] ************************
included: /Users/chukwudiuzoma/Documents/DevOps/ANSIBLE/MyTutorials/AnsibleTestingWithMolecule/alpha-services/tasks/java.yml for instance
TASK [alpha-services : Install java] *******************************************
changed: [instance]
PLAY RECAP *********************************************************************
instance : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
.
TDD, , , , .
1. Java-1.8.0 -
---
- name: "java - check Java package status"
package:
name: "java-1.8.0"
state: "installed"
check_mode: yes
register: pkg_status
- name: "java - test java package is installed"
assert:
that:
- not pkg_status.changed
Java java-1.8.0
pkg_status
. , java-1.8.0
, not pkg_status.changed
true
, . .
test_java.yml
alpha-services/molecule/default/roles/test_alpha-services/tasks/main.yml
:
---
- name: "include tasks for testing Java"
include_tasks: "test_java.yml"
THEN : $ molecule verify
. , :
$ molecule verify
--> Test matrix
└── default
└── verify
--> Scenario: 'default'
--> Action: 'verify'
--> Running Ansible Verifier
--> Sanity checks: 'docker'
PLAY [Verify] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Include test_alpha-services] *********************************************
TASK [test_alpha-services : include tasks for testing Java] ********************
included: /Users/chukwudiuzoma/Documents/DevOps/ANSIBLE/MyTutorials/AnsibleTestingWithMolecule/alpha-services/molecule/default/roles/test_alpha-services/tasks/test_java.yml for instance
TASK [test_alpha-services : Check Java package status] *************************
changed: [instance]
TASK [test_alpha-services : Test java package is installed] ********************
fatal: [instance]: FAILED! => {
"assertion": "not pkg_status.changed",
"changed": false,
"evaluated_to": false,
"msg": "Assertion failed"
}
PLAY RECAP *********************************************************************
instance : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
ERROR:
1. alpha-services/tasks/java.yml
:
---
- name: "Install '{{ java_required_software }}'"
package:
name: "{{ java_required_software }}"
lock_timeout: 60
state: "present"
java.yml
alpha-services/tasks/main.yml
:
---
- name: "Include java installation tasks"
include_tasks: "java.yml"
WHEN : $ molecule converge
, .
THEN : $ molecule verify
, , .
$ molecule verify
--> Test matrix
└── default
└── verify
--> Scenario: 'default'
--> Action: 'verify'
--> Running Ansible Verifier
--> Sanity checks: 'docker'
PLAY [Verify] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Include test_alpha-services] *********************************************
TASK [test_alpha-services : include tasks for testing Java] ********************
included: /Users/chukwudiuzoma/Documents/DevOps/ANSIBLE/MyTutorials/AnsibleTestingWithMolecule/alpha-services/molecule/default/roles/test_alpha-services/tasks/test_java.yml for instance
TASK [test_alpha-services : Check Java package status] *************************
ok: [instance]
TASK [test_alpha-services : Test java package is installed] ********************
ok: [instance] => {
"changed": false,
"msg": "All assertions passed"
}
PLAY RECAP *********************************************************************
instance : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verifier completed successfully.
2. /var/log/tomcat
, tomcat
, tomcat
0755
.
---
- name: "tomcat - '{{ test_tomcat_home_dir }}' - retrieve information from path"
stat:
path: "{{ test_tomcat_home_dir }}"
register: directory
- name: "tomcat - assert that directory '{{ test_tomcat_home_dir }}' is created correctly"
assert:
that:
- "directory.stat.exists"
- "directory.stat.isdir"
- "directory.stat.mode == {{ test_tomcat_mode }}"
- "directory.stat.pw_name == {{ test_tomcat_user }}"
- "directory.stat.gr_name == {{ test_tomcat_group}}"
yml- Molecule:
---
#TOMCAT
test_tomcat_mode: "0755"
test_tomcat_user: "tomcat"
test_tomcat_group: "tomcat"
test_tomcat_home_dir: "/var/log/tomcat"
stat
Ansible , .
test_java.yml
alpha-services/molecule/default/roles/test_alpha-services/tasks/main.yml
:
---
- name: "include tasks for testing Tomcat"
include_tasks: "test_tomcat.yml"
$ molecule verify
, , . :
---
- name: "tomcat - create required tomcat logging directory"
file:
path: "{{ tomcat_home_dir }}"
state: "directory"
mode: "0755"
owner: "{{ tomcat_user }}"
group: "{{ tomcat_group }}"
recurse: yes
yml :
---
#TOMCAT
tomcat_mode: "0755"
tomcat_user: "tomcat"
tomcat_group: "tomcat"
tomcat_home_dir: "/var/log/tomcat"
tomcat.yml alpha-services/tasks/main.yml
:
---
- name: "Include java installation tasks"
include_tasks: "java.yml"
: $ molecule converge
, .
: $ molecule verify
, , .
3: , httpd
, Ansible . Ansible, « Ansible — . , , , - . Ansible — , ».
, , , , :
TASK [alpha-services : httpd - start and enable httpd service] *****************
fatal: [instance]: FAILED! => {"changed": false, "msg": "Could not find the requested service httpd: host"}
:
---
- name: "Httpd - install httpd service"
package:
name: "httpd"
state: "latest"
- name: "Httpd - start and enable httpd service"
service:
name: "httpd"
state: "started"
enabled: "yes"
, httpd
Linux systemd, . , platforms
Molelele.yml:
---
platforms:
- name: instance
image: docker.io/pycontribs/centos:7
pre_build_image: false # we don't need ansible installed on the instance
command: /sbin/init
tmpfs:
- /run
- /tmp
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
privileged: true
systemd https://molecule.readthedocs.io/en/latest/examples.html
$ molecule create
$ molecule converge
. , httpd . httpd, :
$ molecule login # this logs you into the docker container shell
$ systemctl | grep httpd
httpd.service loaded active running The Apache HTTP Server
$ exit # this logs you out of the docker container to your local terminal
4. template/tomcat/context.xml /etc/tomcat/context.xml.
, , -. , , , - , . , , . , , Ansible .
:
- name: "tomcat - test tomcat file"
block:
- name: "tomcat - retrieve information from path '{{ test_tomcat_context_xml_file }}'"
stat:
path: "{{ test_tomcat_context_xml_file }}"
register: remote_file
- name: "tomcat - assert that '{{ test_tomcat_context_xml_file }}' file is created correctly"
assert:
that:
- "remote_file.stat.exists"
- "remote_file.stat.isreg" # is a regular file
- "remote_file.stat.path == '{{ test_tomcat_context_xml_file }}'"
- "remote_file.stat.mode == '0755'"
test_tomcat_conf_dir: "/etc/tomcat"
test_tomcat_context_xml_file: "{{ test_tomcat_conf_dir }}/context.xml"
$ molecule verify
, , . :
- name: "tomcat - copy dynamic tomcat server config files"
template:
src: "{{ tomcat_context_xml_file }}"
dest: "{{ tomcat_conf_dir }}"
tomcat_conf_dir: "/etc/tomcat"
tomcat_context_xml_file: "tomcat/context.xml"
$ molecule converge
, $ molecule verify
. , .
, , $ molecule test
, Molecule test_sequence
. .
En conclusion, à mon avis, c'est la bonne approche pour développer des tests Molecule pour les rôles Ansible. Le code d'infrastructure doit être testé avant le déploiement dans un environnement de production pour éviter les mauvaises surprises. Ce didacticiel était une simple démonstration de la façon dont vous pouvez tester Ansible avec Molecule à l'aide d'Ansible Verifier. Ainsi, il n'est pas nécessaire d'apprendre un autre langage de programmation comme Python, Ruby ou Go.