ansible

Collecting variables from multiple hosts in a playbook


I have a playbook that collects a list of information from multiple hosts, and I want to collect those lists together into a single variable. So for example, my output might look like this:

ok: [ALBSWA052] => {
    "myvar": [
        "ALBSWA052 exists",
        "ALBSWA052 is secondary"
    ]
}
ok: [ALBSWA051] => {
    "myvar": [
        "ALBSWA051 exists",
        "ALBSWA051 is primary"
    ]
}

and I'd like to combine them into a list like

    "myvar": [
        "ALBSWA052 exists",
        "ALBSWA052 is secondary"
        "ALBSWA051 exists",
        "ALBSWA051 is primary"
    ]

Is there an elegant way to do this? The only way I can think of is to write it into a file and read it back in.


Solution

  • myvar1: "{{ ansible_play_hosts | map('extract', hostvars, 'myvar')
                                   | flatten }}"
    

    gives the expected result

    myvar1:
      - ALBSWA051 exists
      - ALBSWA051 is secondary
      - ALBSWA052 exists
      - ALBSWA052 is secondary
    
    myvar1: VARIABLE IS NOT DEFINED!
    

    In this case, use json_query. For example,

    myvar2: "{{ hostvars | json_query('*.myvar') | flatten }}"
    

    gives, if my_var is missing in ALBSWA052

    myvar2:
      - ALBSWA051 exists
      - ALBSWA051 is secondary
    
    shell> cat hosts
    ALBSWA051
    ALBSWA052
    ALBSWA053
    

    If myvar is defined in ALBSWA053 the former declaration will give

    myvar2:
      - ALBSWA051 exists
      - ALBSWA051 is secondary
      - ALBSWA053 exists
      - ALBSWA053 is secondary
    

    In this case, select the hostvars

    myvar3: "{{ hostvars | dict2items
                         | selectattr('key', 'in', ansible_play_hosts)
                         | json_query('[].value.myvar')
                         | flatten }}"
    

    gives

    myvar3:
      - ALBSWA051 exists
      - ALBSWA051 is secondary
    

    Of course, if myvar is defined in both ALBSWA051 and ALBSWA052 you get the expected result

    myvar3:
      - ALBSWA051 exists
      - ALBSWA051 is secondary
      - ALBSWA052 exists
      - ALBSWA052 is secondary
    

    Example of a complete playbook for testing

    shell> cat pb.yml
    - hosts: ALBSWA051,ALBSWA052
      gather_facts: false
    
      vars:
    
        myvar1: "{{ ansible_play_hosts | map('extract', hostvars, 'myvar')
                                       | flatten }}"
        myvar2: "{{ hostvars | json_query('*.myvar') | flatten }}"
        myvar3: "{{ hostvars | dict2items
                             | selectattr('key', 'in', ansible_play_hosts)
                             | json_query('[].value.myvar')
                             | flatten }}"
    
      tasks:
    
        - debug:
            var: myvar1
          run_once: true
    
        - debug:
            var: myvar2
          run_once: true
    
        - debug:
            var: myvar3
          run_once: true
    
    shell> tree .
    .
    ├── ansible.cfg
    ├── hosts
    ├── host_vars
    │   ├── ALBSWA051.yml
    │   ├── ALBSWA052.yml
    │   └── ALBSWA053.yml
    └── pb.yml
    
    shell> cat host_vars/ALBSWA051.yml 
    myvar: [ALBSWA051 exists, ALBSWA051 is secondary]
    
    shell> cat host_vars/ALBSWA052.yml 
    myvar: [ALBSWA052 exists, ALBSWA052 is secondary]
    
    shell> cat host_vars/ALBSWA053.yml 
    myvar: [ALBSWA053 exists, ALBSWA053 is secondary]