1

I'm running into the issue (feature?) described in Ansible group vars priority , presumably because I've gone about structuring my inventory incorrectly.

The idea was to have two tasks, which apply to all 'routers' or 'firewalls' as defined in the inventory. This part works fine -- Ansible correctly parses the inventory and distinguishes between the two.

The problem is that due to the way the inventory is parsed, it's using the same ansible_user and ansible_password for every customer group. Which apparently makes sense based on the documentation:

When groups of the same parent/child level are merged, it is done alphabetically, and the last group loaded overwrites the previous groups. For example, an a_group will be merged with b_group and b_group vars that match will overwrite the ones in a_group.

Can anyone advise how I should correct this? If I change the 'routers' and 'firewalls' subgroups to be unique, e.g., custA_routers, custB_routers, then it behaves as expected. However then I think I have to write tasks scoped to each of those subgroups. Note that all hosts are unique IP addresses.

Playbook:

---
- name: Check routers
  hosts: routers
  tasks:
    - name: Do stuff.
      <commands>
- name: Check firewalls
  hosts: firewalls
  tasks:
    - name: Do stuff.
      <commands>

Inventory:

all:
  vars:
    ansible_connection: network_cli
    ansible_network_os: ios
  children:
    customerOne:
      vars:
        ansible_user: userOne
        ansible_password: <vaulted pass>
      children:
        routers:
          hosts:
            x.x.x.x
            y.y.y.y
        firewalls:
          vars:
            ansible_network_os: asa
          hosts:
            z.z.z.z
    customerTwo:
      vars:
        ansible_user: userTwo
        ansible_password: <vaulted pass>
      children:
        routers:
          hosts:
            x.x.x.x
            y.y.y.y
        firewalls:
          vars:
            ansible_network_os: asa
          hosts:
            z.z.z.z
boomi
  • 113
  • 4

2 Answers2

2

It's possible to simplify the inventory

all:
  vars:
    ansible_connection: network_cli
    ansible_network_os: ios
  children:
    routers:
      hosts:
        x.x.x.x
        y.y.y.y
    firewalls:
      vars:
        ansible_network_os: asa
      hosts:
        z.z.z.z

and put the authentication data into a separate variable. Put it where it fits best. This might be 'all: vars:' section in the inventory, 'vars:' section in a playbook, 'group_vars/all' directory ...

auth:
  customerOne:
    ansible_user: userOne
    ansible_password: <vaulted pass>
  customerTwo:
    ansible_user: userTwo
    ansible_password: <vaulted pass>

Add a play in the top of the playbook and assign the variables according to the external variable customer

- name: Read variables
  gather_facts: false
  hosts: routers
  tasks:
    - set_fact:
        ansible_user: "{{ auth[customer].ansible_user }}"
        ansible_password: "{{ auth[customer].ansible_password }}"
      run_once: true

- name: Check routers
  hosts: routers
  tasks:
    - name: Do stuff.
      <commands>

Run the playbook and specify the customer

ansible-playbook playbook.yml -e "customer=customerTwo"
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • Thanks for the explanation Vladimir -- am I just expecting the inventory to do things it cannot? This will work, but it's going to make me run 20 or so instances of the playbook to cover all the customers. Technically that's easy enough to just put into a shell script, but not exactly elegant. – boomi Jan 23 '20 at 16:28
  • Yes. Inventory can't do it, but Ansible is very flexible. There are dozens of variations of how to implement this. I'd go for a vaulted file with the dictionary. Include the dictionary in a short playbook and [import_playbook](https://docs.ansible.com/ansible/latest/modules/import_playbook_module.html#import-playbook-import-a-playbook) at the top of other plays. If you have problems open new question. – Vladimir Botka Jan 23 '20 at 16:50
  • Great, I think that'll get me on track again. Thank you! – boomi Jan 23 '20 at 17:59
0

I thiink it is ideal to create two separate inventory, customerOneInventory.yaml and customerTwo.yaml or router.yaml and firewalls.yaml.. up to your need. You'll just specify the inventory file you need during ansible playbook run.

ansible-playbook heat-check-playbook.yaml -i customerOneInventory.yaml

letthefireflieslive
  • 11,493
  • 11
  • 37
  • 61
  • So basically I need to maintain separate inventories when group variables would "conflict"? – boomi Jan 23 '20 at 16:29