Search code examples
ansibleansible-inventory

Is it possible to loop through array of specific host and configuration


I'm trying to figure out if it's possible to have a play that will loop through an array of hosts with a specific host variable configured/defined.

For example, this is my inventory file

controlplanes:
  hosts:
    host1.example.com:
workers:
  hosts:
    host2.example.com:
      longhorn:
        storage: true
    host3.example.com:
      longhorn:
        storage: true

Basically my goal is to run kubectl label command from one host to apply annotations to specific kubernetes nodes, but I only want to have the command run against a specific list of hosts, e.g. hosts that have longhorn.storage=true, so in the above example, I should only loop through 2 hosts.

Is this possible? I know I can loop through all hosts, but I can't seem to access variables of any given host, I thought hostvars[hostname].longhorn.storage might give me access, but results seem to indicate it's not defined, so I think my approach is incorrect.

- name: Loop Test
  hosts: controlplanes
  tasks:
    - debug:
        msg: "{{ item }}"
      loop:
        - "{{ groups['all'] }}"

Solution

  • Create the list longhorn_group in the first play

    - hosts: all
      tasks:
        - set_fact:
            longhorn_storage: "{{ longhorn.storage|d(false) }}"
        - set_fact:
            longhorn_group: "{{ hostvars|dict2items|
                                selectattr('value.longhorn_storage')|
                                map(attribute='key') }}"
          run_once: true
    

    and use it in the second play

    - hosts: controlplanes
      tasks:
        - debug:
            var: longhorn_group
        - debug:
            msg: "{{ item }}"
          loop: "{{ longhorn_group }}"
    

    gives (abridge)

    TASK [debug] *********************************************************************************
    ok: [host1.example.com] => 
      longhorn_group:
      - host2.example.com
      - host3.example.com
    
    TASK [debug] *********************************************************************************
    ok: [host1.example.com] => (item=host2.example.com) => 
      msg: host2.example.com
    ok: [host1.example.com] => (item=host3.example.com) => 
      msg: host3.example.com
    

    Example of a complete playbook for testing

    - hosts: all
      tasks:
        - set_fact:
            longhorn_storage: "{{ longhorn.storage|d(false) }}"
        - set_fact:
            longhorn_group: "{{ hostvars|dict2items|
                                selectattr('value.longhorn_storage')|
                                map(attribute='key') }}"
          run_once: true
    
    - hosts: controlplanes
      tasks:
        - debug:
            var: longhorn_group
        - debug:
            msg: "{{ item }}"
          loop: "{{ longhorn_group }}"