Using yaml anchors for loop items module parameters

Hi Ansible community,
is it possible to use YAML anchors, to populate module parameters in a loop?

Example 1: Doing it without anchors (currently working):

- name: "Create a Meraki RF profile"
  vars:
    rf_profiles:
      - name: PROFILE1
        bandSelectionType: ap
        twoFourGhzSettings:
          minBitrate: 24
          channelWidth: auto
          maxPower: 17
          minPower: 5              
      - name: PROFILE2
        bandSelectionType: ap
        twoFourGhzSettings:
          minBitrate: 36
          channelWidth: auto
          maxPower: 19
          minPower: 2           
  cisco.meraki.networks_wireless_rf_profiles:
    name: "{{ item.name }}"
    bandSelectionType: "{{ item.bandSelectionType }}"
    # .... other parameters
  loop: "{{ rf_profiles }}"

The drawback of this solution is, that all possible module parameters must be included in the variable block and also the module block. Furthermore, optional parameters, which are defaulted by the target system, must be catched if they do not exist in the vars block (e.g. using default filter)

Example 2: Doing it with anchors (currently not working):

- name: "Create a Meraki RF profile"
  vars:
    rf_profiles:  &rf_profile_anchor
      - name: PROFILE1
        bandSelectionType: ap
        twoFourGhzSettings:
          minBitrate: 24
          channelWidth: auto
          maxPower: 17
          minPower: 5              
      - name: PROFILE2
        bandSelectionType: ap
        twoFourGhzSettings:
          minBitrate: 36
          channelWidth: auto
          maxPower: 19
          minPower: 2           
  cisco.meraki.networks_wireless_rf_profiles:
    <<: *rf_profile_anchor
  loop: "{{ rf_profiles }}"

With this solution I want to inject the module properties directly from the variable loop iteration. However, this does not really work - only the content of the first list item is transmitted in the actual module.

Is there an elegant way to do this?

Hi, the YAML anchors and aliases are supported, but AFAIK it’s a bit difficult to use with loop as you expected.

Since anchors are a feature of YAML, all aliases are resolved before Ansible evaluates it as a playbook. This means that Ansible cannot know that the playbook contains anchors. Refer to:

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_advanced_syntax.html#yaml-anchors-and-aliases-sharing-variable-values

Alternatively, you can simply passing dict to modules:

- name: "Create a Meraki RF profile"
  vars:
    rf_profiles:
      - name: PROFILE1
        bandSelectionType: ap
        twoFourGhzSettings:
          minBitrate: 24
          channelWidth: auto
          maxPower: 17
          minPower: 5              
      - name: PROFILE2
        bandSelectionType: ap
        twoFourGhzSettings:
          minBitrate: 36
          channelWidth: auto
          maxPower: 19
          minPower: 2           
  cisco.meraki.networks_wireless_rf_profiles: "{{ item }}"
  loop: "{{ rf_profiles }}"

This will probably result following [WARNING] to be shown, but may works as expected anyway.

[WARNING]: Using a variable for a task's 'args' is unsafe in some situations (see https://docs.ansible.com/ansible/devel/reference_appendices/faq.html#argsplat-unsafe)

Refer to the following FAQ to know why this may be unsafe: Frequently Asked Questions β€” Ansible Community Documentation

2 Likes