Filter out items that are in a group with Ansible Jinja2

Viewed 265

I'm trying to use a environment variable called MOLECULE_GROUP to filter out values that do not belong to a certain group. It's easier to show -- I'm trying to turn this:

platforms:
  - name: Ubuntu
    groups:
      - testme
  - name: Fedora
    groups:
      - donttestme

Into this:

platforms:
  - name: Ubuntu
    groups:
      - testme

I would use this to conditionally run scenarios that are members of a certain group by prepending the molecule command with MOLECULE_GROUP=testme. Molecule does not support filtering by groups like this so I want have custom create.yml and destroy.yml etc. but I need to know how to modify the molecule_yml.platforms value.

I tried using combinations of selectattr and map but could not figure it out.

2 Answers

There is a contains test that have been created by Ansible's extensions of Jinja2 that fits exactly this purpose.

Given the playbook:

- hosts: localhost
  gather_facts: no
  vars:
    MOLECULE_GROUP: testme
    platforms:
      - name: Ubuntu
        groups:
          - testme
      - name: Fedora
        groups:
          - donttestme

  tasks:
    - set_fact:
        platforms: >-
          {{ platforms | selectattr('groups', 'contains', MOLECULE_GROUP) }}
    
    - debug:
        var: platforms

This yields:

TASK [set_fact] ********************************************************
ok: [localhost]

TASK [debug] ***********************************************************
ok: [localhost] => 
  platforms:
  - groups:
    - testme
    name: Ubuntu

I ended up using the feedback to create an Ansible Molecule play that only runs on platforms that are in specific groups. To do this, you can:

Create custom create.yml and destroy.yml files. For Docker, you can just copy the source from https://github.com/ansible-community/molecule-docker/tree/main/src/molecule_docker/playbooks

Add the following to the top of each of the custom files:

- name: Update platforms
  hosts: localhost
  tasks:
    - name: Filtering platforms list using the group defined in the MOLECULE_GROUP environment variable
      set_fact:
        molecule_yml: "{{ molecule_yml | combine({'platforms': (molecule_yml.platforms | selectattr('groups', 'contains', lookup('env', 'MOLECULE_GROUP')))}) }}"
      when: ansible_env.MOLECULE_GROUP is defined

Then you can run and selectively target platforms in certain groups using the following command:

MOLECULE_GROUP=group_name molecule test -s docker

You might want to use this method if you have a lot of Molecule scenarios with code that repeats. You can see a full example of the implementation here (Note, the Molecule files are in both .config and molecule folders in the root of the repository):

https://github.com/ProfessorManhattan/ansible-androidstudio

Related