ansible concatenate variables if condition is fulfilled

90 views Asked by At

I want to set vlans for mikrotik switch with ansible, but for this I need to concatenate variables bases on condition (tag existence)

Now my task:

core-access=eth1,eth2,eth3
core-access=eth11,eth12,eth13
wifi=eth4,eth5
core=eth6

#Tasks:

    - name: Create/update vlan with core-access and wifi tag
      community.routeros.command:
        commands:
          - /interface bridge vlan add tagged={{ core-access }},{{ wifi }} \
      with_dict: "{{ global_vlan_list }}"
      loop_control:
        loop_var: item
      when:
        - host_vlans is not defined
        - item.value.type is defined
        - '"core-access" in item.value.type'
        - '"access" not in item.value.type'
        - '"wifi" in item.value.type'

    - name: Create/update vlan with access and wifi tag
      community.routeros.command:
        commands:
          - /interface bridge vlan add tagged={{ access }},{{ wifi }} \
      with_dict: "{{ global_vlan_list }}"
      loop_control:
        loop_var: item
      when:
        - host_vlans is not defined
        - item.value.type is defined
        - '"core-access" not in item.value.type'
        - '"access" in item.value.type'
        - '"wifi" in item.value.type'

    - name: Create/update vlan with access-core, access and wifi tag
      community.routeros.command:
        commands:
          - /interface bridge vlan add tagged={{ core-acces }},{{access}},{{ wifi }} \
      with_dict: "{{ global_vlan_list }}"
      loop_control:
        loop_var: item
      when:
        - host_vlans is not defined
        - item.value.type is defined
        - '"core-access" in item.value.type'
        - '"access" in item.value.type'
        - '"wifi" in item.value.type'

How can I solve this with one task. Now I use 6, but if I use 4-5 tags, the code become unusable.

I try to find a solution to use if in ansible, but without success. I want to simplify this solution. Maybe I'm coloser to solution with next step, but don't work: - name: Create/update vlan with access tag debug: msg: test {{ port_core if '"access" in item.value.type' else "" }},{{ port_wifi if '"wifi" in item.value.type' else "" }}

2

There are 2 answers

0
Akos On

Sorry, I forget to define exactly the global_vlan_list variable.

I got the answer: https://hup.hu/node/182039#comment-2931460

- hosts: localhost
  vars:
    interfaces:
      core-access: ['eth1', 'eth2', 'eth3']
      wlan: ['eth4', 'eth5']
      access: ['eth6']
    global_vlan_list:
      1: { type: ["core-access", "access", "wlan"] }
      2: { type: [] }
      3: { type: ["core-access", "access"] }
  tasks:
  - name: Create/update vlan
    debug:
      msg: "interface bridge vlan add tagged={{ item.value.type | map('extract', interfaces) | flatten | join(',') }}"
    with_dict: "{{ global_vlan_list }}"
    when: item.value.type | map('extract', interfaces) | flatten
2
Vladimir Botka On
  • A better structure for global_vlan_list is really a list ,not a dictionary
  global_vlan_list:
    - [core-access, access, wlan]
    - []
    - [core-access, access]

This simplifies the iteration

    - debug:
        msg: "interface bridge vlan add tagged={{ result }}"
      loop: "{{ global_vlan_list }}"
      vars:
        result: "{{ item|map('extract', interfaces)|flatten|join(',') }}"
      when: result|length > 0

gives

TASK [debug] ********************************************************
ok: [localhost] => (item=['core-access', 'access', 'wlan']) => 
  msg: interface bridge vlan add tagged=eth1,eth2,eth3,eth6,eth4,eth5
skipping: [localhost] => (item=[]) 
ok: [localhost] => (item=['core-access', 'access']) => 
  msg: interface bridge vlan add tagged=eth1,eth2,eth3,eth6
  • Optionally, you can create the lists of vlan interfaces in the vars
  vlan_interfaces: |
    {% filter from_yaml %}
    {% for i in global_vlan_list %}
    - {{ i|map('extract', interfaces)|flatten }}
    {% endfor %}
    {% endfilter %}

gives

  vlan_interfaces:
    - [eth1, eth2, eth3, eth6, eth4, eth5]
    - []
    - [eth1, eth2, eth3, eth6]

and simplify the iteration even further. The task below gives the same results

    - debug:
        msg: "interface bridge vlan add tagged={{ item|join(',') }}"
      loop: "{{ vlan_interfaces }}"
      when: item|length > 0
    - debug:
        msg: "{{ ansible_loop.index }}.
                 interface bridge vlan add tagged={{ item|join(',') }}"
      loop: "{{ vlan_interfaces }}"
      loop_control:
        extended: true
      when: item|length > 0

gives

TASK [debug] ****************************************************************
ok: [localhost] => (item=['eth1', 'eth2', 'eth3', 'eth6', 'eth4', 'eth5']) => 
  msg: 1. interface bridge vlan add tagged=eth1,eth2,eth3,eth6,eth4,eth5
skipping: [localhost] => (item=[]) 
ok: [localhost] => (item=['eth1', 'eth2', 'eth3', 'eth6']) => 
  msg: 3. interface bridge vlan add tagged=eth1,eth2,eth3,eth6

Example of a complete playbook for testing

- hosts: localhost

  vars:

    interfaces:
      core-access: [eth1, eth2, eth3]
      wlan: [eth4, eth5]
      access: [eth6]

    global_vlan_list:
      - [core-access, access, wlan]
      - []
      - [core-access, access]

    vlan_interfaces: |
      {% filter from_yaml %}
      {% for i in global_vlan_list %}
      - {{ i|map('extract', interfaces)|flatten }}
      {% endfor %}
      {% endfilter %}

  tasks:

    - debug:
        msg: "interface bridge vlan add tagged={{ result }}"
      loop: "{{ global_vlan_list }}"
      vars:
        result: "{{ item|map('extract', interfaces)|flatten|join(',') }}"
      when: result|length > 0

    - debug:
        var: vlan_interfaces|to_yaml

    - debug:
        msg: "interface bridge vlan add tagged={{ item|join(',') }}"
      loop: "{{ vlan_interfaces }}"
      when: item|length > 0

    - debug:
        msg: "{{ ansible_loop.index }}.
              interface bridge vlan add tagged={{ item|join(',') }}"
      loop: "{{ vlan_interfaces }}"
      loop_control:
        extended: true
      when: item|length > 0

Q: "I need a dictionary on vlan_list because I define vlan id."

A: Given a dictionary

  global_vlan_dict:
    1: [core-access, access, wlan]
    2: []
    3: [core-access, access]
  • You can create the list below and use it in the above code without any changes. The last example above shows how to use ansible_loop.index
  global_vlan_list: "{{ global_vlan_dict.values() }}"
  • The above option works if id are natural numbers. In the case of arbitrary id, for example
  global_vlan_dict:
    72: [core-access, access, wlan]
    4: []
    127: [core-access, access]

iterate the dictionary

    - debug:
        msg: "id: {{ item.key }} interface bridge vlan add tagged={{ result }}"
      loop: "{{ global_vlan_dict|dict2items }}"
      vars:
        result: "{{ item.value|map('extract', interfaces)|flatten|join(',') }}"
      when: result|length > 0

gives

TASK [debug] **********************************************************************************
ok: [localhost] => (item={'key': 72, 'value': ['core-access', 'access', 'wlan']}) => 
  msg: 'id: 72 interface bridge vlan add tagged=eth1,eth2,eth3,eth6,eth4,eth5'
skipping: [localhost] => (item={'key': 4, 'value': []}) 
ok: [localhost] => (item={'key': 127, 'value': ['core-access', 'access']}) => 
  msg: 'id: 127 interface bridge vlan add tagged=eth1,eth2,eth3,eth6'