@dbrennand I appreciate the follow up. Lots of great questions, but these are going to get confusing smashing it all together. I’ll try my best.
Question 1:
With group two as you explained it, are you referring to somebody testing Ansible content (such as a role or playbook) outside of a collection structure? E.g., a standalone role in a GitHub repo?
I’m focused on testing ansible content as part of a collection. The process for testing stand-alone roles has extensive documentation and examples and the process has generally stayed the same for a very long time.
Question 2:
Lack of documentation and examples for what exactly? Do you have specific tooling or scenarios in mind here?
How to test ansible content (YAML) as part of a collection.
The most typical scenario that has to be out-of-the-box is running local podman/docker containers that include systemd for an automation developer to test as they’re writing the code and validating ansible-lint won’t fail a pipeline.
Question 3:
Information that is available assumes python knowledge or outdated (prior to collections)
The challenge is mostly that there is nearly a decade of content covering how to do this (books, videos, blogs, etc) that sort-of work, don’t work at all anymore, or take the person down some really frustrating paths.
I just reviewed the molecule documentation and see there have been some major reworks in the past year that I wasn’t tracking. This is a huge step in the right direction thanks to folks like @cidrblock . There is now enough information there for someone to get started, which is a big improvement. Assuming people are aware, we likely see more examples of it that can be used as a reference.
So much of the the information related to collection testing assumes that it is module focused. We don’t do a great job of differentiating role only collections from collections with modules. So users will encounter a long list of tools that seem required but may not be needed for their use-case.
Question / Comment 4:
I was discussing with @konstruktoid about molecule-plugins recently on Matrix. We were talking about how the docker driver with newer molecule versions doesn’t need to be installed anymore. The community.docker collection can be used to create a container for the scenario in the create sequence. See the example here which parses ansible-collection-hardening/extensions/molecule/delete_users_docker/molecule.yml at molecule-docker-scenario · dbrennand/ansible-collection-hardening · GitHub to create the containers.
This is my major point of contention with the direction of ansible content testing. It appears that flexibility is being prioritized over simplicity. The ‘ansible-native’ approach provides a tremendous amount of capability but adds a lot of complexity. Enough complexity that even having done it many times I still end up having to relearn and troubleshoot it every time to get things working (for example fighting all the relative paths in the molecule configs). It also takes a non-opinionated stance on the implementation so there are many ways to get it working that have the same effect but are very unique. This makes troubleshooting and maintenance more difficult.
The old way:
# molecule.yml
driver:
name: docker
The new Ansible Native alternative:
# create.yml
---
- name: Create
hosts: localhost
gather_facts: false
vars:
molecule_inventory:
all:
children:
molecule:
hosts: {}
tasks:
- name: Create containers
community.docker.docker_container:
name: "{{ item.name }}"
hostname: "{{ item.name }}"
image: "{{ item.image }}"
state: started
command: "{{ item.command | default('sleep 1d') }}"
privileged: "{{ item.privileged | default(false) }}"
volumes: "{{ item.volumes | default(omit) }}"
log_driver: json-file
register: result
loop: "{{ molecule_yml.platforms }}"
loop_control:
label: "{{ item.name }}"
- name: Print container details
ansible.builtin.debug:
msg: "{{ result.results }}"
- name: Fail if container is not running
when: >
item.container.State.ExitCode != 0 or not item.container.State.Running
ansible.builtin.fail:
msg: >-
Container {{ item.container.Name }} failed to start properly.
Exit Code: {{ item.container.State.ExitCode }}.
Running: {{ item.container.State.Running }}.
loop: "{{ result.results }}"
loop_control:
label: "{{ item.container.Name }}"
- name: Add containers to molecule inventory
vars:
inventory_partial_yaml: |
all:
children:
molecule:
hosts:
"{{ item.name }}":
ansible_connection: community.docker.docker
ansible_python_interpreter: /usr/bin/python3
ansible.builtin.set_fact:
molecule_inventory: >-
{{ molecule_inventory | combine(inventory_partial_yaml | from_yaml,
recursive=true) }}
loop: "{{ molecule_yml.platforms }}"
loop_control:
label: "{{ item.name }}"
- name: Write molecule inventory
ansible.builtin.copy:
content: "{{ molecule_inventory | to_yaml }}"
dest: "{{ molecule_ephemeral_directory }}/inventory/molecule_inventory.yml"
mode: "0600"
- name: Force inventory refresh
ansible.builtin.meta: refresh_inventory
- name: Fail if molecule group is missing
ansible.builtin.assert:
that: "'molecule' in groups"
fail_msg: "molecule group was not found inside inventory groups: {{ groups }}"
run_once: true
- name: Validate inventory
hosts: molecule
gather_facts: false
tasks:
- name: Check container access
ansible.builtin.raw: /bin/true
changed_when: false
There may be valid reasons to move away from molecule drivers, but I think its worth considering how we can still live up to the goal of “radically simple IT automation”.