Pruebas de Ansible usando Molecule con Ansible como verificador



En este tutorial, aprenderemos cómo probar el código del marco escrito en Ansible utilizando un marco de prueba conocido como Molecule. Dentro de Molecule, usaremos Ansible como verificador, que no pude encontrar en ningún otro lugar. ¡Vamos a hacerlo!



Contenido



  1. Introducción
  2. Molecule
  3. Molecule Ansible
  4. 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 conclusión, en mi opinión, este es el enfoque correcto para desarrollar pruebas de moléculas para roles de Ansible. El código de la infraestructura debe probarse antes de la implementación en un entorno de producción para evitar sorpresas desagradables. Este tutorial fue una demostración simple de cómo puede probar Ansible con Molecule usando Ansible Verifier. Por lo tanto, no es necesario aprender otro lenguaje de programación como Python, Ruby o Go.




All Articles