I am writing a playbook to set up a web application. Before I make any changes to the system I would like to validate that a hostname provided by passing a variable for the machine actually resolves to one of the IP addresses from ansible facts. If this isn't given the certificate generation later on will fail.
I am planning to get the results from community.general.dig and compare the A and AAAA keys in the result dictionary with IP addresses from the ansible facts all_ipv4_addresses/all_ipv6_addresses variables.
When one or a list of IP is in both dictionaries I want to continue with the playbook, else fail with a warning. These IPs I would like to reuse later to aquire the certificate.
I have looked into complex data manipulation but I cannot make proper sense of how to chain the filters to get my desired result. I also am struggling with the fact i have to compare multiple lists or dictionaries with each other.
My original approach was to use the fail builtin and loop over both lists from DNSpython and ansible facts to check for a match. This is insufficient as I need to reuse the list of matching IPs later. The comparison with the ansible_facts.default_ipv4.address
does not seem sufficient since they might have multiple network interfaces (ipv4 and 6) that might not be the default route.
The thought process I had in mind to validate if a certificate could be obtained should be to get all available IPs from all_ipv4_addresses
/ all_ipv6_addresses
and then store the intersection of these records with the valid A/AAAA records from resolving the app_host
variable.
I have found the intersect() filter and now I am just trying to put the entire thing in a condition. Thanks @U880D for pointing me in the right direction towards ansible_facts
, whose snipped i have reused for the start of my playbook:
- name: set up all app services on the target machine
hosts: all
gather_facts: true
gather_subset:
- "!all"
- "!min"
- "network" # in order to get the actual Remote Node configuration
become: yes
vars:
# always overwrite this with the previously setup FQDN
- app_host:
- app_vhost_webroot: /var/www/{{ app_host }}/public
# no trailing / leading slash ; can be an subdirectory like 'app/wws' relative to webroot
- app_path: wws
- app_db: app
- app_dbhost: localhost
- app_dbuser: app
- app_dbpassword: lookup('community.general.random_string', length=14, min_lower=1, min_upper=1, min_numeric=1, special=false)
# - app_customization_branch: ith
# eventually fill this automatically from calling git using branch name above
# no trailing / leading slash ; relative to app_path ; multiple customizations not yet supported
- app_customization_branch_dir: anpassungen/ith
- max_upload_size: '30M'
- phpversion: '7.2'
- dhparams_file: /etc/ssl/dhparams.pem
tasks:
- name: Check if app_host is set
ansible.builtin.fail:
msg: This playbook requires a FQDN set as app_host
when: app_host is undefined or app_host == '' or app_host == None
- name: Check if app_host resolves to an IPv4 address shared of the target machine
ansible.builtin.debug:
msg: "{{ lookup('community.general.dig', app_host, qtype='A', wantlist=True) | intersect(ansible_facts.all_ipv4_addresses) }}"
- name: Check if app_host resolves to an IPv6 address shared of the target machine
ansible.builtin.debug:
msg: "{{ lookup('community.general.dig', app_host, qtype='AAAA', wantlist=True) | intersect(ansible_facts.all_ipv6_addresses) }}"
All that is left would be to a 3rd task that would fail the playbook when theyre both empty. Currently I am strugging to move the variable from msg:
to when:
cause ansible complains about the use of J2 templating delimiters:
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{ lookup('community.general.dig', app_host, qtype='A', wantlist=True) |
intersect(ansible_facts.all_ipv4_addresses) }}
All I would like to do would be to add both lists of intersections together and ansible.builtin.fail when they union of both intersections I just created is empty. I thought of a when condition like:
{{ {{ lookup('community.general.dig', app_host, qtype='A', wantlist=True) | intersect(ansible_facts.all_ipv4_addresses) }} | union({{ lookup('community.general.dig', app_host, qtype='AAAA', wantlist=True) | intersect(ansible_facts.all_ipv6_addresses) }}) }} == []
but I seem to be not understanding something vital in how to build these expressions.