Ansible: How to get a subelement of a nested list of dictionaries
Figured out how to use json_query properly.
- debug:
msg: "{{ dns_zone_config | json_query(_query) }}"
vars:
_query: "[].hosts[?!no_ptr_record][].[ip,ipv6][]"
Results in:
TASK [debug] ***********************************************************************************
ok: [localhost] => {
"msg": [
"10.180.0.200",
"fe80::1",
"11.180.0.200"
]
}
Needs just 1-2 sec instead of ~30 sec with double loops :)
Related videos on Youtube
Mario Nette
Updated on September 18, 2022Comments
-
Mario Nette over 1 year
I'd like to build our DNS zones via Ansible. The user should just maintain one variable for the forward-lookup zones (e.g. foo.bar). Reverse-lookup zones (0.0.10.in-appr.arpa) should be auto-generated with Ansible.
The forward-lookup zone variable should look like
dns_zone_config: - name: "internal.foo.bar" acl: - 10.180.0.0/24 - 10.180.8.0/24 hosts: - name: "fileshare" ip: 10.180.0.200 - name: "infra.foo.bar" acl: - acl-intern hosts: - name: "testhost1" ip: 11.180.0.100 no_ptr_record: true - name: "testhost2" ipv6: fe80::1 - name: "testhost3" ip: 11.180.0.200 - name: "mx.foo.bar" mx: - name: "xxxx" priority: xxxx target: xxxx
dns_zone_config is a list of dictionaries that may contains a key called "hosts" which is again a list of dictionaries.
My current way looks like:
- name: Collect all networks include_tasks: 01-networks.yml loop: "{{ dns_zone_config }}" when: item_dns_zone_config.hosts is defined loop_control: loop_var: item_dns_zone_config #from 01-networks.yml - name: Determine IPv4 networks set_fact: ipv4_networks: "{{ (ipv4_networks | default([])) + [ item.ip ] }}" loop: "{{ item_dns_zone_config.hosts }}" when: item.ip is defined and (item.no_ptr_record is not defined or not item.no_ptr_record)
I double loop over dns_zone_config and their host entries. This is very inefficient and slow. I'm pretty sure this can be solve smarter :D
Basically I just need list of all IPs of all zones. I tried json_query() and selectattr() filters but I'm struggling on the fact that not every host entry has IPv4 or IPv6 addresses defined. And I don't want contains IPs if a no_ptr_record: true variable is defined (false or not defined is ok).
From the snippet above the list would only contain: ipv4_networks:
['10.180.0.200','11.180.0.200']
-
simohe over 3 yearsCould you please explain the query? It looks great. I do not find
? !xx
on jmespath.org/tutorial.html#filter-projections (but I probably have found it out now by trying there). -
Mario Nette over 3 yearsWith
?
you start a condition check. With!
you can negate a boolean. So[?!no_ptr_record]
means take all elements where no_ptr_record is not true. If a list element has not no_ptr_record defined it will be also be handled as false (with negation it will be true). See jmespath.org/specification.html