Ansible - Getting a list of IP addresses for a specific group
Posted on Sat 22 October 2016 in Computing
I had a very simple problem. I needed to get a list of IP addresses from a group of slave servers in inventory to use as part of a firewall ruleset task in a playbook for a master server (so access was only allowed to the master from the slaves). I knew the IP addresses were accessible via hostvars but as I only run this playbook on the master (I don't use a site.yml type god playbook) I knew I needed to run something on the slaves first to gather the facts that build hostvars. Also I wasn't using a template, so that ruled out using for loops in jinja2.
My approach to solving this was:
-
Create a playbook the runs on the slave servers but does nothing
-
Include this playbook in the master server playbook
-
Filter the hostvars data to produce a list consisting only of the IPv4 addresses for a specific host group
Note: You need ansible >= 2.1 for this to work for the map extract feature
slave_do_nothing.yml
---
# Does nothing but will gather facts for later use
- hosts: slave
tasks: []
master_server_test.yml
---
- include: slave_do_nothing.yml
- hosts: master
tasks:
- name: Do something with the slave ip address now in item
set_fact:
n00b: "{{ n00b| default([]) + [item] }}"
with_items:
"{{ groups['slave']|map('extract', hostvars,
['ansible_eth0', 'ipv4', 'address'])|list }}"
- debug: msg="{{ n00b }}"
I've included something else I also discovered along the way which was how to create a list and append items to it. You can see that fact n00b is created and defaults to a empty list and we add each item that is passed from with_items. We then use debug to print it at the end (a list of IP addresses). This should be very useful for debugging tasks in the future.
As a further example here is the task I use in a playbook for an icecast master server to allow inbound connections from the icecast relays.
- name: Allow inbound from icecast relays
firewalld:
zone: public
state: enabled
permanent: true
immediate: true
rich_rule:
"rule family=ipv4 source address={{ item }}
port port={{ icecast_port }} protocol=tcp accept"
with_items:
"{{ groups['icecast-relay']|map('extract', hostvars,
['ansible_eth0', 'ipv4', 'address'])|list }}"