Michael
Michael

Reputation: 8758

ansible: sort of list comprehension?

Given this inventory:

[webservers]
10.0.0.51   private_ip='X.X.X.X'
10.0.0.52   private_ip='Y.Y.Y.Y'
10.0.0.53   private_ip='Z.Z.Z.Z'

How can I get a list of the private ips of the webservers?

webservers_private_ips: "{{  }}"  # ['X.X.X.X', 'Y.Y.Y.Y', 'Z.Z.Z.Z']

I know groups['webservers'] will give me this list ['10.0.0.51', '10.0.0.52', '10.0.0.53'] and I can get the private_ip of one with:

{{ hostvars[item]['private_ip'] }}
with_items: groups['webservers']

But I would like to declare a variable in my var file directly and not have a task to register it. It would be nice if something like the following could be done:

webservers_private_ips: "{{ hostvars[item]['private_ip'] }}  for item in groups['webservers']" 

Upvotes: 15

Views: 12319

Answers (3)

Thomas Quinot
Thomas Quinot

Reputation: 121

You can take advantage of the extract filter to get components of a composite data object:

  webservers_private_ips: "{{ groups['webservers']|map('extract', hostvars, 'private_ip')|list }}"

The extract filter is used to map from a list of indices to a list of values from a container (hash or array).

Upvotes: 12

toast38coza
toast38coza

Reputation: 9066

As of Ansible 2.2 you can use the json_query filter.

In your example it looks like:

- debug:
    msg: "{{item}}"
  loop: "{{hostvars | json_query(query)}}"
  vars:
    query: "* | [?contains(group_names, `webservers`)].private_ip"

"hostvars" is a hash of hostname (e.g. 10.0.0.51) to its respective variables. Filters cannot be applied to hashes (see this answer), so we need to retrieve a list of hostvar objects with "*". The resulting list of hostvars is filtered for hosts that are in the group "webservers". For all matching hashes, the query returns the value of "private_ip".

Docs: http://docs.ansible.com/ansible/latest/playbooks_filters.html#json-query-filter

Upvotes: 0

leucos
leucos

Reputation: 18269

It depends on the context. if you want to loops over private_ip variable in a task, you can do it like so :

- hosts: all
  tasks:
  - name: Print private_ips
    debug: var={{ hostvars[item]['private_ip'] }}
    with_items:
      - "{{ groups['webservers'] }}" 

Note that this will print the IPs 3 times, since it will run on each server, so depending on what you're trying to achieve, you'll have to set hosts: all to your frontend server or whatever.

You can also do this in a Jinja2 file if you plan to generate some config file. Again, it all depends on what you're aiming for.

Note that you can access IP information in facts gathered automatically by ansible :

$ ansible someserver -m setup
    ....
    "ansible_eth1": {
        "active": true, 
        "device": "eth1", 
        "ipv4": {
            "address": "192.168.252.6", 
            "netmask": "255.255.255.255", 
            "network": "192.168.252.6"
        }, 
        "mtu": 1500, 
        "promisc": false
    }, 
    ....

which might also be more suitable, depending what you're trying to do.

Good luck.

Upvotes: -2

Related Questions