ansible flipping inventory still reads in the same order

Viewed 110

I am working on a project aimed at populating the IP's of some routers based on East/West locations. The first host will always be the primary and the second will always be the secondary.

Based on the location passed, I flip the inventory. I see the inventory being flipped, but Ansible get the value from the list in the same order.

It doesn't matter what order the inventory list is read. I need for the first host to read the first element e.g. 20.21.22.23 and then the second host to read the second element 28.29.30.31.

Right now, ATL is always the first element and LAX the second.

ok: [ATL_isr_lab] => {
    "msg": [
        "20.21.22.23",
        "24.25.26.27",
        "24.25.26.28"
    ]
}
ok: [LAX_isr_lab] => {
    "msg": [
        "28.29.30.31",
        "32.33.34.35",
        "32.33.34.36"
    ]
}
------------------ Inventory Flipped -------------------------------
ok: [LAX_isr_lab] => {
    "msg": [
        "28.29.30.31",
        "32.33.34.35",
        "32.33.34.36"
    ]
}
ok: [ATL_isr_lab] => {
    "msg": [
        "20.21.22.23",
        "24.25.26.27",
        "24.25.26.28"
    ]
}
---
- hosts: test_hosts
  vars:
    region: east

    _Hub_IP: [ 20.21.22.23, 28.29.30.31]
    _Transit_IP: [ 24.25.26.27, 32.33.34.35]
    _Neighbor_IP: [24.25.26.28, 32.33.34.36]
    _idx: "{{ groups.all.index(inventory_hostname) }}"

  #flips inventory if west
  order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"
  become: yes
  ignore_unreachable: true
  gather_facts: false

  tasks: 
  - name: "Configure Router"
    debug:
      msg:
        - "{{ _Hub_IP[_idx|int] }}"
        - "{{ _Transit_IP[_idx|int] }}"
        - "{{ _Neighbor_IP[_idx|int] }}"
2 Answers

Well, the issue is not coming with the reverse_inventory and inventory value of the order parameter like you seems to think it is.

The issue is to think that groups.all is indeed reversed when you do use the reverse_inventory value.

Here is an example of this, with the playbook:

- hosts: localhost
  gather_facts: no
  order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"

  tasks:
    - debug:
        var: groups.all

Running it with, with the region as an extra-vars:

  • ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=east"
    Will yield:
    ok: [localhost] => 
      groups.all:
      - LAX_isr_lab
      - ATL_isr_lab
    
  • ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=west"
    Will yield:
    ok: [localhost] => 
      groups.all:
      - LAX_isr_lab
      - ATL_isr_lab
    

Still the sorting works, see:

- hosts: all
  gather_facts: no
  order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"

  tasks:
    - debug:

Run with:

  • ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=east"
    Will yield
    ok: [ATL_isr_lab] => 
      msg: Hello world!
    ok: [LAX_isr_lab] => 
      msg: Hello world!
    
  • ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=west"
    Will yield
    ok: [LAX_isr_lab] => 
      msg: Hello world!
    ok: [ATL_isr_lab] => 
      msg: Hello world!
    

So, what ends up being wrong is your _idx value.
To fix this, you could use the reverse filter of jinja with the same ternary as you are using in the order parameter, like this:

_idx: "{{ ((region == 'east')|ternary(groups.all|reverse, groups.all)).index(inventory_hostname) }}"

Working playbook:

- hosts: all
  gather_facts: no
  order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"

  vars:
    _Hub_IP: [20.21.22.23, 28.29.30.31]
    _Transit_IP: [24.25.26.27, 32.33.34.35]
    _Neighbor_IP: [24.25.26.28, 32.33.34.36]
    _idx: "{{ ((region == 'east')|ternary(groups.all|reverse, groups.all)).index(inventory_hostname) }}"

  tasks:
    - debug:
        msg:
          - "{{ _Hub_IP[_idx|int] }}"
          - "{{ _Transit_IP[_idx|int] }}"
          - "{{ _Neighbor_IP[_idx|int] }}"

Running examples:

  • ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=east"
    Will yield:
    ok: [ATL_isr_lab] => 
      msg:
      - 20.21.22.23
      - 24.25.26.27
      - 24.25.26.28
    ok: [LAX_isr_lab] => 
      msg:
      - 28.29.30.31
      - 32.33.34.35
      - 32.33.34.36
    
  • ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=west"
    Will yield:
    ok: [LAX_isr_lab] => 
      msg:
      - 20.21.22.23
      - 24.25.26.27
      - 24.25.26.28
    ok: [ATL_isr_lab] => 
      msg:
      - 28.29.30.31
      - 32.33.34.35
      - 32.33.34.36
    

Got it working as posted originally. I had to upgrade to ansible version 2.11.6. I'm running Debian 10 and apt-get update/apt-get upgrade did not find a newer version.

My solution involved deleting the version and installing it again through pip. After that, I ran the code and it worked flawlessly.

Related