Reputation: 3
I am pretty new to Ansible as a network engineer and have found it breaking my brain. I've used basic loops in some Ansible playbooks. Now I'm trying something a bit more complex and I'm sure I'm missing something because it feels like it should be simple.
I want to take these variables in a playbook:
vars:
smb_tcp_ports:
- '139'
- '445'
smb_udp_ports:
- '137'
- '138'
smb_ips:
- '172.16.13.130'
- '172.16.13.0/26'
- '200X:8X0:fX4a:X053::/64'
- '200X:8X0:fX4a:X050::130'
and loop through them so I build a new variable like this:
vars:
smb_allowed_ips_tcp:
- { ip: "172.16.13.130", port: ['139','445'] }
- { ip: "172.16.13.0/26", port: ['139','445'] }
- { ip: "X001:8X0:fX4a:X053::/64", port: ['139','445'] }
- { ip: "X001:8X0:fX4a:X050::130", port: ['139','445'] }
smb_allowed_ips_udp:
- { ip: "172.16.13.130", port: ['137','138'] }
- { ip: "172.16.13.0/26", port: ['137','138'] }
- { ip: "200X:8X0:fX4a:X053::/64", port: ['137','138'] }
- { ip: "200X:8X0:fX4a:X050::130", port: ['137','138'] }
^^^ the above bit that I want to generate is the bit that I'm struggling with ^^^ Then I can send it to this:
- name: Allow SMB TCP
ufw:
rule: allow
src: '{{ item.0.ip }}'
port: '{{ item.1 }}'
proto: tcp
with_subelements:
- "{{ smb_allowed_ips_tcp }}"
- port
when: "'smbserver' in group_names"
- name: Allow SMB UDP
ufw:
rule: allow
src: '{{ item.0.ip }}'
port: '{{ item.1 }}'
proto: udp
with_subelements:
- "{{ smb_allowed_ips_udp }}"
- port
when: "'smbserver' in group_names"
The question used to have a lot of words here. I deleted it. Thanks Larsks. I hope this is clearer?
I tried set_facts, but there is loads of stuff I don't understand in examples i see, like adding | symbols and writing list, product etc, and I always end up breaking. It also doesnt seem to add as an array, it overwrites.
Answered here: using https://ansibledaily.com/process-complex-variables-with-set_fact-and-with_items/
---
- hosts: myhosts
gather_facts: true
become: true
vars:
smb_tcp_ports:
- '139'
- '445'
smb_udp_ports:
- '137'
- '138'
smb_ips:
- '172.16.13.130'
- '172.16.13.0/26'
- '200X:8X0:fX4a:X053::/64'
- '200X:8X0:fX4a:X050::130'
smb_ips_tcp: {}
tasks:
- name: Populate IPs in dict
set_fact:
smb_ips_tcp: "{{ smb_ips_tcp | combine({'ip': item}) }}"
with_items:
- "{{ smb_ips }}"
register: smbout
- name: Populate ports in dict
set_fact:
smb_ips_tcp: "{{ item | combine({'port': smb_tcp_ports}) }}"
with_items:
- "{{ smbout.results | map(attribute='ansible_facts.smb_ips_tcp') | list }}"
register: smbout
- name: smbout results
set_fact:
smb_ips_tcp: "{{ smbout.results | map(attribute='ansible_facts.smb_ips_tcp') | list }}"
- name: Allow SMB TCP
ufw:
rule: allow
src: '{{ item.0.ip }}'
port: '{{ item.1 }}'
proto: tcp
with_subelements:
- "{{ smb_ips_tcp }}"
- port
I think I had missed the register bit. So when I tried the register facts bit before it kept leaving me with one key value pair. Which was useless. The register though is allowing me to keep all the key values and use them again.
Unsure if this is a duplicate question now.
Upvotes: 0
Views: 623
Reputation: 311238
It sounds like you may have resolved your question, but I thought you might be interested in an alternative implementation. I would probably solve this using the product
filter, which produces the cartesian product of two lists. For example, to produce smb_allowed_ips_tcp
, I would write:
- name: create smb_allowed_ips_tcp
set_fact:
smb_allowed_ips_tcp: "{{ smb_allowed_ips_tcp + [{'ip': item.0, 'port': item.1}] }}"
loop: "{{ smb_ips|product(smb_tcp_ports)|list }}"
vars:
smb_allowed_ips_tcp: []
This produces a data structure that looks like:
TASK [debug] ******************************************************************************************
ok: [localhost] => {
"smb_allowed_ips_tcp": [
{
"ip": "172.16.13.130",
"port": "139"
},
{
"ip": "172.16.13.130",
"port": "445"
},
{
"ip": "172.16.13.0/26",
"port": "139"
},
{
"ip": "172.16.13.0/26",
"port": "445"
},
{
"ip": "200X:8X0:fX4a:X053::/64",
"port": "139"
},
{
"ip": "200X:8X0:fX4a:X053::/64",
"port": "445"
},
{
"ip": "200X:8X0:fX4a:X050::130",
"port": "139"
},
{
"ip": "200X:8X0:fX4a:X050::130",
"port": "445"
}
]
}
We can feed that to the ufw
module like this:
- name: Allow SMB TCP
ufw:
rule: allow
src: '{{ item.ip }}'
port: '{{ item.port }}'
proto: tcp
loop: "{{ smb_allowed_ips_tcp }}"
There are fewer tasks required for this solution, and I think the logic is a little easier to follow.
Upvotes: 1