14

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']" 
Michael
  • 8,357
  • 20
  • 58
  • 86

3 Answers3

12

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).

jhutar
  • 1,369
  • 2
  • 17
  • 32
Thomas Quinot
  • 121
  • 1
  • 5
0

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

Michael Seifert
  • 786
  • 5
  • 8
toast38coza
  • 8,650
  • 3
  • 39
  • 32
-2

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.

leucos
  • 17,661
  • 1
  • 44
  • 34
  • 1
    Thanks. Yes, as I said, I know how to do it in a task and in a template. What I am looking for is to create a variable with the list of private IPs that I can pass in different roles for example. – Michael Oct 21 '14 at 17:04
  • Could you tell us more about your use-case ? Especially, will you use them in a template ? – leucos Oct 21 '14 at 17:30
  • No, it's not to use in a template. One of the role I use expects a list of IP addresses as a variable. I could create this list manually in my vars file but I'd like to create this variable dynamically from the private_ip variables I have defined on each host. – Michael Oct 21 '14 at 17:38
  • I see. The only solution I can imagine is ugly hacks like looping over private IPs, appending them in a file, and then read that file in another task. You could also write your own lookup plugin that could eat your host group and split out array addresses. – leucos Oct 21 '14 at 19:48
  • Hum ok so I didn't miss anything, it's just not possible to do it in a clean way with Ansible. Too bad.Thanks – Michael Oct 21 '14 at 20:11
  • Lookup is clean, this is probably the way to go. Note that I might miss something, so all hope is not lost ;) – leucos Oct 22 '14 at 06:09
  • How can lookup help? I have mainly been using lookup to get the content of a file. – Michael Oct 22 '14 at 15:16
  • I was talking about writing a lookup plugin. You can do a lot more with lookup plugins than just read file. Have a look here : https://github.com/ansible/ansible/tree/devel/lib/ansible/runner/lookup_plugins. – leucos Oct 22 '14 at 19:10