Reputation: 13
I have this list of firwalld zones to configure:
fw_zones:
- name: "example"
target: "DROP"
allowed_services:
- ssh
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
- name: "another_example"
target: "DROP"
allowed_services:
- ssh
- http
- ntp
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
- echo-request
and I want to use the firewalld
module to do so. While setting new zones shouldn't be a problem, and setting their default target can probably only be done using command
module, I am struggling to find a solution for enabling services/icmp blocks since I'm already iterating over a list (fw_zones
). Is there a straightforward solution to achieving this?
I tried different setups of this list, like:
fw_zones:
example:
target: "DROP"
allowed_services:
- ssh
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
another_example:
target: "DROP"
allowed_services:
- ssh
- http
- ntp
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
- echo-request
and using | dict2items
, but in all cases I couldn't figure out how to iterate over the icmp_blocks
and allowed_services
lists.
Upvotes: 1
Views: 60
Reputation: 3516
What you're looking for is nested loops.
While the recommendation is to construct the data in a way that avoids nested loops, it's obvious that sometimes it will make the maintenance of the data complicated, like in your case.
So, you can either run the loop over some product
of your list, or use the nested include_tasks
. In my opinion, the difference would be that using product
could be more elegant, but nested tasks are more straightforward.
So, given your initial list, you can do something like the following:
# playbook.yaml
---
- name: Manage the firewalld settings
hosts: all
tasks:
- name: Looping over the zones
include_tasks: firewalld_zones_loop.yaml
loop: "{{ fw_zones }}"
loop_control:
loop_var: fw_zone
# firewalld_zones_loop.yaml
---
- name: Looping over the services
include_tasks: firewalld_services_loop.yaml
loop: "{{ fw_zone.allowed_services }}"
loop_control:
loop_var: fw_service
# firewalld_services_loop.yaml
---
- name: Set the firewall rule
firewalld:
zone: "{{ fw_zone.name }}"
target: "{{ fw_zone.target }}"
service: "{{ fw_service }}"
icmp_block: "{{ fw_icmp_block }}"
state: enabled
# ...
loop_control:
loop_var: fw_icmp_block
Upvotes: 1
Reputation: 68189
Use the filter subelements or the lookup plugin subelements. I prefer the filter, but the difference is only in the syntax. For example,
fw_zones:
- name: example
target: DROP
allowed_services:
- ssh
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
- name: another_example
target: DROP
allowed_services:
- ssh
- http
- ntp
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
- echo-request
iterate allowed_services
- name: Iterate allowed_services
debug:
msg: "{{ item.0.name }} {{ item.1 }}"
loop: "{{ fw_zones | subelements('allowed_services') }}"
loop_control:
label: "{{ item.0.name }} {{ item.1 }}"
gives (abridged)
msg: example ssh
msg: another_example ssh
msg: another_example http
msg: another_example ntp
Iterate icmp_blocks
- name: Iterate icmp_blocks
debug:
msg: "{{ item.0.name }} {{ item.1 }}"
loop: "{{ fw_zones | subelements('icmp_blocks') }}"
loop_control:
label: "{{ item.0.name }} {{ item.1 }}"
gives (abridged)
msg: example fragmentation-needed
msg: another_example fragmentation-needed
msg: another_example echo-request
fw_zones:
example:
target: DROP
allowed_services:
- ssh
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
another_example:
target: DROP
allowed_services:
- ssh
- http
- ntp
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
- echo-request
In this case, use the filter dict2items to convert the dictionary to a list and use the key/value attributes. The below tasks give the same results
- name: Iterate allowed_services
debug:
msg: "{{ item.0.key }} {{ item.1 }}"
loop: "{{ fw_zones | dict2items | subelements('value.allowed_services') }}"
loop_control:
label: "{{ item.0.key }} {{ item.1 }}"
- name: Iterate icmp_blocks
debug:
msg: "{{ item.0.key }} {{ item.1 }}"
loop: "{{ fw_zones | dict2items | subelements('value.icmp_blocks') }}"
loop_control:
label: "{{ item.0.key }} {{ item.1 }}"
Example of a complete playbook for testing
- hosts: localhost
vars:
fw_zones:
example:
target: DROP
allowed_services:
- ssh
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
another_example:
target: DROP
allowed_services:
- ssh
- http
- ntp
icmp_block_inversion: true
icmp_blocks:
- fragmentation-needed
- echo-request
tasks:
- name: Iterate allowed_services
debug:
msg: "{{ item.0.key }} {{ item.1 }}"
loop: "{{ fw_zones | dict2items | subelements('value.allowed_services') }}"
loop_control:
label: "{{ item.0.key }} {{ item.1 }}"
- name: Iterate icmp_blocks
debug:
msg: "{{ item.0.key }} {{ item.1 }}"
loop: "{{ fw_zones | dict2items | subelements('value.icmp_blocks') }}"
loop_control:
label: "{{ item.0.key }} {{ item.1 }}"
Upvotes: 1