Checking Ansible Roles via Molecule Delegated Driver







Molecule is an excellent tool for testing Ansible roles, it follows a robust and flexible validation process to ensure a good level of role quality. Almost all of the Molecule documentation focuses on the docker driver, where tests are run against the container server, but while it is a good choice for most use cases, there may be cases where it might be useful to switch to an external cloud backend using a delegated driver .







Unfortunately, the delegated driver documentation is mostly just a few lines in the official doc, whereas a clearer explanation and a few examples can be of immense help to those developers who want to use Molecule in this way.







This post builds on my experience developing a simple Ansible role from 0 to galaxy and focuses on using a delegated driver integrated with Google Cloud Platform. I took the following useful links for my project as a starting point:









: Molecule?







, , β€” Molecule:







instance-config API. instance-config, instance-config.







: instance-config ?







Instance-config β€” Ansible, YAML Molecule ( $HOME/.cache/molecule/<role-name>/<scenario-name>/instance_config.yml



), :







- address: 10.10.15.17
 identity_file: /home/fabio/.ssh/id_rsa # mutually exclusive with
                                        # password
 instance: millennium_falcon
 port: 22
 user: hansolo
# password: ssh_password # mutually exclusive with identity_file
 become_method: sudo # optional
# become_pass: password_if_required # optional
      
      





, Windows, WinRM.







create.yml







, , instance-config, . , Molecule , molecule init



, :







molecule init scenario -driver-name=delegated
      
      





:







.
β”œβ”€β”€ INSTALL.rst
β”œβ”€β”€ converge.yml
β”œβ”€β”€ create.yml
β”œβ”€β”€ destroy.yml
β”œβ”€β”€ molecule.yml
└── verify.yml
      
      





  • molecule.yml



    β€” Molecule, , .
  • create.yml



    β€” Ansible instance-config.
  • destroy.yml



    Ansible instance-config
  • converge.yml



  • verify.yml



  • INSTALL.rst



    Molecule


create.yml



, Molecule:







---
- name: Create
 hosts: localhost
 connection: local
 gather_facts: false
 no_log: "{{ molecule_no_log }}"
 tasks:

 # Developer must implement.
 # Developer must map instance config.
 # Mandatory configuration for Molecule to function.

 β€” name: Populate instance config dict
 set_fact:
 instance_conf_dict: {
 'instance': "{{ }}",
 'address': "{{ }}",
 'user': "{{ }}",
 'port': "{{ }}",
 'identity_file': "{{ }}", }
 with_items: "{{ server.results }}"
 register: instance_config_dict
 when: server.changed | bool

 β€” name: Convert instance config dict to a list
 set_fact:
 instance_conf: {{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}"
 when: server.changed | bool

 β€” name: Dump instance config
 copy:
 content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}"
 dest: "{{ molecule_instance_config }}"
 when: server.changed | bool
      
      





: , , instance-config.yml



. Ansible, ( ) . , github, , VMWare:







…
 7     - name: Create molecule instance(s)
 8      vmware_guest:
 9        hostname: "{{ molecule_yml.driver.hostname }}"
10        esxi_hostname: "{{ molecule_yml.driver.esxi_hostname }}"
11        username: "{{ molecule_yml.driver.username }}"
12        password: "{{ molecule_yml.driver.password }}"
13        datacenter: "{{ molecule_yml.driver.datacenter }}"
14        validate_certs: "{{ molecule_yml.driver.validate_certs }}"
15        resource_pool: "{{ molecule_yml.driver.resource_pool }}"
16         folder: "{{ molecule_yml.driver.folder }}"
17         name: "{{ item.name }}"
18         template: "{{ item.template }}"
19         hardware:
20           memory_mb: "{{ item.memory | default(omit) }}"
21           num_cpus: "{{ item.cpu | default(omit) }}"
22         wait_for_ip_address: "yes"
23         state: poweredon
24       register: server
25       with_items: "{{ molecule_yml.platforms }}"
26     
27     - name: Populate instance config dict
28       set_fact:
29         instance_conf_dict: {
30           'instance': "{{ item.instance.hw_name }}",
31           'address': "{{ item.instance.ipv4 }}",
32           'user': "vagrant",
33           'port': "22",
34           'identity_file': 'identity_file': "{{
                     molecule_yml.driver.ssh_identity_file }}"
35         }
36       with_items: "{{ server.results }}"
37       register: instance_config_dict
38       when: server is changed
…
      
      





vmware_guest



( 7–23) VMWare. , molecule.yml



( 25). , , molecule.yml



, molecule_yml



.







, vmware_guest



, ( 24), , , (instance-config



) ( 27 ). , , .







Google Cloud Platform (GCP)







, , , , docker-secured Ansible. GCP . Ansible GCP , , , .







:







  • python 2.7
  • ansible 2.9.6
  • molecule 3.0.2
  • ansible-lint 4.2.0
  • yamllint 1.20.0
  • flake8 3.7.9 (mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1) CPython 2.7.17 Linux


yamllint, ansible-lint flake8 β€” , .







docker-secured







, API- ssl. , , Docker:









ssl , , .







, GitHub:







git clone https://github.com/fabiomarinetti/fmarinetti.docker-secured.git
      
      





GCP







, GCP, . , GCP . , Ansible GCP.







ansible-272015



service



, secret.json



.







molecule.yml







molecule.yml



.







, molecule.yml



driver



. , , , , GCP, ssh , , , , ad-hoc . molecule_yml



(, molecule_yml.driver.region



).







20 driver:
21   name: delegated
22   gcp_service_account_key: ${GOOGLE_APPLICATION_CREDENTIALS}
23   gcp_project_id: ansible-272015
24   region: us-east1
25   zone: us-east1-c
26   ssh_user: ${SSH_USER}
27   ssh_pub_key_file: "${SSH_ID_FILE}.pub"
28   ssh_key_file: "${SSH_ID_FILE}"
29   network_name: ansible-network
30   subnet_name: ansible-subnet
31   firewall_name: ansible-firewall
32   ip_cidr_range: 172.16.0.0/28
      
      





molecule.yml



, (, , , …) , . CentOS 7, Ubuntu Xenial 16.04 Ubuntu Bionic 18.04. (, CentOS Ubuntu), Ansible.







41 platforms:
42   - name: "ds-centos7-${TRAVIS_BUILD_ID}"
43     image_family: projects/centos-cloud/global/images/family
                     /centos-7
44     machine_type: n1-standard-1
45     size_gb: 200
46     groups:
47       - centos
48   - name: "ds-ubuntu-bionic-${TRAVIS_BUILD_ID}"
49     image_family: projects/ubuntu-os-cloud/global/images/family
                     /ubuntu-1804-lts
50     machine_type: n1-standard-1
51     size_gb: 200
52     groups:
53       - ubuntu
54   - name:  "ds-ubuntu-xenial-${TRAVIS_BUILD_ID}"
55     image_family: projects/ubuntu-os-cloud/global/images/family
                     /ubuntu-1604-lts
56     machine_type: n1-standard-1
57     size_gb: 200
58     groups:
59       - ubuntu
      
      





molecule.yml



, .







create.yml







, create.yml



β€” , . gcp (GCP). GCP - , , , , , module_defaults



gcp.







 7   module_defaults:
 8     group/gcp:
 9       project: "{{ molecule_yml.driver.gcp_project_id }}"
10       auth_kind: serviceaccount
11       service_account_file: "{{ 
              molecule_yml.driver.gcp_service_account_key }}"
      
      





, VMWare, GCP β€” , , : , IP- . , :







16 β€” name: create instances
17   include_tasks: tasks/create_instance.yml
18   loop: "{{ molecule_yml.platforms }}"
      
      





create_instance.yml



IP-, . , , , , , , instance-config.







7 - name: initialize instance facts
 8   set_fact:
 9     instance_created:
10       instances: []
11   when: instance_created is not defined
... create the instance and return instance variable ...
56 - name: update instance facts
57   set_fact:
58     instance_created:
59       changed: instance.changed | bool
60       instances: "{{ instance_created.instances + [ instance ]}}"
      
      





isntance-config instance_create



:







20     - name: Populate instance config dict
21       set_fact:
22         instance_conf_dict: {
23           'instance': "{{ item.name }}",
24           'address': "{{
               item.networkInterfaces[0].accessConfigs[0].natIP }}",
25           'user': "{{ molecule_yml.driver.ssh_user }}",
26           'port': "22",
27           'identity_file': "{{ molecule_yml.driver.ssh_key_file
               }}", }
28       with_items: "{{ instance_created.instances }}"
29       register: instance_config_dict
30       when: instance_created.changed
      
      





, , VMWare, servers is changed









, , :







molecule create --scenario-name=gcp
      
      





, , / :







  • lint,
  • prepare, . ubuntu.
  • converge,
  • idempotence,
  • verify, ,


molecule <phase> --scenario-name=gcp
      
      





, , , .







destroy.yml



( ). , , . , :







molecule destroy --scenario-name=gcp
      
      





, :







molecule test --scenario-test=gcp
      
      











, Molecule, , GCP. : AWS, Azure, Digital Ocean… , Molecule. , .








All Articles