Kevin C
Kevin C

Reputation: 5740

Create var based on list in dict

Imagine this dict on 4 different hosts.

# on host 1
my_dict:
  ip: 10.0.0.111
  roles:
    - name: something
      observer: false

# on host 2
my_dict:
  ip: 10.0.0.112
  roles:
    - name: something
      observer: false

# on host 3
my_dict:
  ip: 10.0.0.113
  roles:
    - name: something
      observer: true

# on host 4
my_dict:
  ip: 10.0.0.114
  roles:
    - name: whatever

When Ansible runs for all 4 hosts I want it to build a variable for each host having the roles name 'something'. The desired output is:

10.0.0.111 10.0.0.112 10.0.0.113:observer

There are 2 requirements:

I eventually want to use the var in a Jinja template, so to me, the var can be either set via an Ansible task or as a jinja template.

This doesn't work:

- name: set fact for ip
  debug:
    msg: >-
      {{ ansible_play_hosts |
      map('extract', hostvars, ['my_dict', 'ip'] ) |
      join(' ') }}
  when: ???

Upvotes: 2

Views: 125

Answers (1)

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39119

You could create two lists:

  • one with what should be postfixed to the IPs with the condition based on the observer property
  • the other one with the IPs

And then zip them back together.

Given:

- debug:
    msg: >-
      {{ 
        _ips | zip(_is_observer) | map('join') | join(' ')
      }}
  vars:
    _hosts: >-
      {{ 
        hostvars 
        | dict2items 
        | selectattr('key', 'in', ansible_play_hosts)
        | selectattr('value.my_dict.roles.0.name', '==', 'something')
      }}
    _is_observer: >-
      {{ 
        _hosts
        | map(attribute='value.my_dict.roles.0.observer') 
        | map('replace', false, '') 
        | map('replace', true, ':observer')
      }}
    _ips: >-
      {{
        _hosts
        | map(attribute='value.my_dict.ip')
      }}

This yields:

TASK [debug] *************************************************************
ok: [localhost] => 
  msg: 10.0.0.111 10.0.0.112 10.0.0.113:observer

Upvotes: 2

Related Questions