At my current employer we have several servers in production with various providers, some of them with multiple IP addresses. When configuring the firewall to allow traffic from other servers I reached for Ansible. The obvious solution was to use a nested loop, something like this:
- name: Allow other servers ufw: rule: allow from_ip: '{{ item[1] }}' with_nested: - all_hosts - '{{ item.ansible_all_ipv4_addresses }}'
However, this syntax is invalid (and other variations I tried). Using include
with with_items
is deprecated and I didn't manage to get it to work with registering variables as well. What I had left was programmatically generating a playbook, but investigating further I found that Ansible can be imported as a Python module.
Incorporating Ansible in Python
To retrieve all of the ip addresses I'd ran the setup module to gather the information
from ansible.runner import Runner struct = Runner (module_name='setup', pattern='all_hosts').run()
Now we have a complex data structure that is the output of Ansible's fact gathering module. Running it in the interpreter and examining the structure is not hard at all and that is how I managed to write the following code to extract a list of all of our server's ip addresses.
ipaddresses = [] for host in struct['contacted']: for ip in struct['contacted'][host]['ansible_facts']['ansible_all_ipv4_addresses']: ipaddresses.append (ip)
Putting that information to good use
Now that we have a list of the ip addresses, we can start running Ansible commands right from with Python (just like we did) or build a playbook by outputting a YAML file. I chose the latter.
from yaml import safe_dump doc = {'all_ipv4': ipaddresses} print (safe_dump (doc), file='vars.yml')
This will create a vars.yml file with the all_ipv4 variable already defined there to be imported to any playbook and run. For example:
--- - hosts: all_hosts vars_files: - vars.yml tasks: - name: Allow other servers with_items: all_ipv4 ufw: rule: allow from_ip: '{{ item }}'
With this much little code we were able to query all of our hosts, extract the needed information and output it back to Ansible for further use. I see this as a product of the good decisions the Ansible developers choose early on (YAML, Python, SSH). As always, for any feedback you may have, email me.