Ansible jinja2 manipulate lists based on multi level values - ansible

I am trying to manipulate this list in Ansible:
webserver:
sites:
- user: userone
domains:
- domain: domainone.com
- domain: domaintwo.com
- user: usertwo
domains:
- domain: domainthree.com
- user: userthree
domains:
- domain: domainfour.com
- domain: domainfive.com
Into this:
domains_with_user:
- domain: domainone.com
user: userone
- domain: domaintwo.com
user: userone
- domain: domainthree.com
user: usertwo
- domain: domainfour.com
user: userthree
- domain: domainfive.com
user: userthree
But then with code based on only the first "webserver:" config.
How can I do this? I'd prefer to be able to do it as a new variable decleration ("domains_with_user": {{ some code }})

You can use a loop with the filter subelements
---
- hosts: localhost
gather_facts: false
vars:
webserver:
sites:
- user: userone
domains:
- domain: domainone.com
- domain: domaintwo.com
- user: usertwo
domains:
- domain: domainthree.com
- user: userthree
domains:
- domain: domainfour.com
- domain: domainfive.com
tasks:
- name: Set domains_with_user variable
set_fact:
domains_with_user: "{{ domains_with_user | default([]) + [{ 'domain': item.1.domain , 'user': item.0.user }] }}"
loop: "{{ webserver.sites | subelements('domains') }}"
- name: DEBUG
debug:
msg: "{{ domains_with_user }}"
and the output:
PLAY [localhost] **********************************************************************************
TASK [Set domains_with_user variable] *************************************************************
ok: [localhost] => (item=[{'user': 'userone', 'domains': [{'domain': 'domainone.com'}, {'domain': 'domaintwo.com'}]}, {'domain': 'domainone.com'}])
ok: [localhost] => (item=[{'user': 'userone', 'domains': [{'domain': 'domainone.com'}, {'domain': 'domaintwo.com'}]}, {'domain': 'domaintwo.com'}])
ok: [localhost] => (item=[{'user': 'usertwo', 'domains': [{'domain': 'domainthree.com'}]}, {'domain': 'domainthree.com'}])
ok: [localhost] => (item=[{'user': 'userthree', 'domains': [{'domain': 'domainfour.com'}, {'domain': 'domainfive.com'}]}, {'domain': 'domainfour.com'}])
ok: [localhost] => (item=[{'user': 'userthree', 'domains': [{'domain': 'domainfour.com'}, {'domain': 'domainfive.com'}]}, {'domain': 'domainfive.com'}])
TASK [DEBUG] **************************************************************************************
ok: [localhost] => {
"msg": [
{
"domain": "domainone.com",
"user": "userone"
},
{
"domain": "domaintwo.com",
"user": "userone"
},
{
"domain": "domainthree.com",
"user": "usertwo"
},
{
"domain": "domainfour.com",
"user": "userthree"
},
{
"domain": "domainfive.com",
"user": "userthree"
}
]
}
PLAY RECAP ****************************************************************************************

Related

Merge 2 lists of dictionaries by property value in Ansible

I'm trying to merge 2 lists of dictionary objects by one of the properties, but I can't seem to find the correct syntax/filters to do so
default_settings:
- { name: 'setting1', value: 'default value1' }
- { name: 'setting2', value: 'default value2' }
overrides:
- { name: 'setting1', value: 'overridden value' }
- { name: 'setting3', value: 'new value3' }
This should result in:
result:
- { name: 'setting1', value: 'overridden value' }
- { name: 'setting2', value: 'default value2' }
- { name: 'setting3', value: 'new value3' }
I've tried my luck with simply adding them, using combine filter, but those things either only work on dictionaries or lists, but not lists of dictionaries.
Of course after 2 hours of trying and searching and eventually making this post, I managed to get it working in a final little thing I tested. So for those who have the same problem, you can use the groupby filter, combined with a mapped last and mapped combine.
---
- hosts: localhost
connection: local
gather_facts: no
vars:
default_settings:
- { name: 'setting1', value: 'default value1' }
- { name: 'setting2', value: 'default value2' }
overrides:
- { name: 'setting1', value: 'overridden value' }
- { name: 'setting3', value: 'new value3' }
tasks:
- debug:
msg: "{{ item.name }} = {{ item.value }}"
loop: "{{ (default_settings + overrides) | groupby('name') | map('last') | map('combine') }}"
TASK [debug] *********************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'name': 'setting1', 'value': 'overridden value'}) => {
"msg": "setting1 = overridden value"
}
ok: [localhost] => (item={'name': 'setting2', 'value': 'default value2'}) => {
"msg": "setting2 = default value2"
}
ok: [localhost] => (item={'name': 'setting3', 'value': 'new value3'}) => {
"msg": "setting3 = new value3"
}
The easiest way is to convert them to dictionaries and combine them:
- hosts: localhost
gather_facts: no
vars:
default_settings:
- { name: 'setting1', value: 'default value1' }
- { name: 'setting2', value: 'default value2' }
overrides:
- { name: 'setting1', value: 'overridden value' }
- { name: 'setting3', value: 'new value3' }
combined_settings: "{{ [default_settings, overrides] | map('items2dict', key_name='name') | combine }}"
tasks:
- name: now you have a dict
debug:
msg: "{{ combined_settings }}"
- name: which you can convert back to a list to iterate over
debug:
msg: "{{ item.key }}: {{ item.value }}"
loop: "{{ combined_settings | dict2items }}"
TASK [now you have a dict] ********************************************************
ok: [localhost] => {
"msg": {
"setting1": "overridden value",
"setting2": "default value2",
"setting3": "new value3"
}
}
TASK [which you can convert back to a list to iterate over] ***********************
ok: [localhost] => (item={'key': 'setting1', 'value': 'overridden value'}) => {
"msg": "setting1: overridden value"
}
ok: [localhost] => (item={'key': 'setting2', 'value': 'default value2'}) => {
"msg": "setting2: default value2"
}
ok: [localhost] => (item={'key': 'setting3', 'value': 'new value3'}) => {
"msg": "setting3: new value3"
}

Filter result with selectattr in an Ansible playbook

I'm trying to get the playbook show only the filtered result.
But instead it showing filtered and non-filtered result.
e.g: I just want it to show only the files that not owned by root in the output.
- set_fact:
target_file: /var/log/apache2/
- name: verify that the logs ownership/perms are belong to system administrators and service accounts.
block:
- find:
paths: "{{ target_file }}"
patterns: "*.log"
register: ownership
failed_when: ownership.files | selectattr('pw_name', '!=', 'root')
- debug:
var: ownership
- find:
paths: "{{ target_file }}"
patterns: "*.log"
register: group
failed_when: group.files | selectattr('gr_name', '!=', 'adm')
- find:
paths: "{{ target_file }}"
patterns: "*.log"
register: permissions
failed_when: permissions.files | selectattr('mode', '!=', '0640')
- set_fact:
stig_text: "PASSED"
rescue:
- name: change the permission and ownership of the files
become: true
file:
path: "{{ item.path }}"
owner: root
group: adm
mode: 0640
with_items: "{{ ownership.files }}"
register: change_perms
- set_fact:
stig_text: "PASSED"
when: change_perms.changed == true
Debug output:
TASK [debug] ************************************************************
ok: [localhost] => {
"ownership": {
"changed": false,
"examined": 18,
"failed": false,
"failed_when_result": false,
"files": [
{
"atime": 1652373886.9567592,
"ctime": 1652373886.9567592,
"dev": 2,
"gid": 0,
"gr_name": "root",
"inode": 3096224743982700,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1652373886.9567592,
"nlink": 1,
"path": "/var/log/alternatives.log",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 49270,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
},
{
"atime": 1623178394.0,
"ctime": 1652791696.643692,
"dev": 2,
"gid": 0,
"gr_name": "root",
"inode": 3377699720693451,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0600",
"mtime": 1623117753.0,
"nlink": 1,
"path": "/var/log/ubuntu-advantage.log",
"pw_name": "root",
"rgrp": false,
"roth": false,
"rusr": true,
"size": 0,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
],
"matched": 6,
"msg": ""
}
}
Your code structure is a very strange and inefficient approach to this problem.
This is my best guess at what you were trying to do:
- name: Verify the ownership and permissions on logs
vars:
target_file: /var/log/apache2/
block:
- name: Find all log files under {{ target_file }}
find:
paths: "{{ target_file }}"
patterns: "*.log"
register: log_files
- name: Fix permissions and ownership
file:
path: "{{ item.path }}"
owner: root
group: adm
mode: "0640"
become: true
loop: "{{ logs_bad_owner | union(logs_bad_group) | union(logs_bad_perms) }}"
loop_control:
label: "{{ item.path }}"
vars:
logs_bad_owner: "{{ log_files.files | selectattr('pw_name', '!=', 'root') }}"
logs_bad_group: "{{ log_files.files | selectattr('gr_name', '!=', 'adm') }}"
logs_bad_perms: "{{ log_files.files | selectattr('mode', '!=', '0640') }}"
- set_fact:
stig_text: PASSED
rescue:
- set_fact:
stig_text: FAILED
This avoids unnecessary work like running the same find multiple times or looping over the entire set of files when you're only interested in the ones that need fixing.
Because your debug is just after a command that would fail if pw_name is not root, due to your failed_when condition, the debug just won't happen if there is any problematic file, and enters the rescue tasks instead, so when you do see the any debug task result, it means there was no problematic file, in terms on ownership, really.
Now the reason being pointed, you have to understand that Ansible is all about idempotency:
An operation is idempotent if the result of performing it once is exactly the same as the result of performing it repeatedly without any intervening actions.
Source: https://docs.ansible.com/ansible/latest/reference_appendices/glossary.html
So, you don't even have to do anything complex here you just have to set the rights and ownership to what it should:
- name: change the permission and ownership of the files
file:
path: "{{ item }}"
owner: root
group: adm
mode: 0640
with_fileglob:
- /var/log/apache2/*.log
register: permission_audit
And then, if you want to make an audit report, you can do something like:
- name: List of security remediation run during this audit
debug:
var: >-
permission_audit.results
| selectattr('changed')
| map(attribute='diff')
Which would yield something like:
TASK [List of security remediation run during this audit] ********************
ok: [localhost] =>
permission_audit.results | selectattr('changed') | map(attribute='diff'):
- after:
mode: '0640'
path: /var/log/apache2/access.1.log
before:
mode: '0777'
path: /var/log/apache2/access.1.log
- after:
mode: '0640'
path: /var/log/apache2/access.2.log
before:
mode: '0777'
path: /var/log/apache2/access.2.log
If you want to show the success or the failure of the audit in the result of the playbook you can even go one step further and assert the length of this list:
- name: Security audit result
assert:
that: permission_changes | length == 0
fail_msg: Audit on Apache log file rights failed
success_msg: Audit on Apache log file rights passed
vars:
permission_changes: >-
{{
permission_audit.results
| selectattr('changed')
| map(attribute='diff')
}}
And now our playbook will either end in
TASK [Security audit result] **********************************************
ok: [localhost] => changed=false
msg: Audit on Apache log file rights passed
PLAY RECAP ****************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
Or in
TASK [Security audit result] **********************************************
fatal: [localhost]: FAILED! => changed=false
assertion: permission_changes | length == 0
evaluated_to: false
msg: Audit on Apache log file rights failed
PLAY RECAP ****************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=1
Given ten log files; two having rights issues and the two tasks:
- file:
path: "{{ item }}"
owner: root
group: adm
mode: 0640
with_fileglob:
- /var/log/apache2/*.log
register: permission_audit
- name: List of security remediation run during this audit
debug:
var: >-
permission_audit.results
| selectattr('changed')
| map(attribute='diff')
This would yield:
TASK [file] *****************************************************************
changed: [localhost] => (item=/var/log/apache2/access.1.log)
ok: [localhost] => (item=/var/log/apache2/access.10.log)
ok: [localhost] => (item=/var/log/apache2/access.4.log)
ok: [localhost] => (item=/var/log/apache2/access.9.log)
ok: [localhost] => (item=/var/log/apache2/access.7.log)
ok: [localhost] => (item=/var/log/apache2/access.3.log)
ok: [localhost] => (item=/var/log/apache2/access.5.log)
ok: [localhost] => (item=/var/log/apache2/access.8.log)
ok: [localhost] => (item=/var/log/apache2/access.6.log)
changed: [localhost] => (item=/var/log/apache2/access.2.log)
TASK [List of security remediation run during this audit] *******************
ok: [localhost] =>
permission_audit.results | selectattr('changed') | map(attribute='diff'):
- after:
mode: '0640'
path: /var/log/apache2/access.1.log
before:
mode: '0777'
path: /var/log/apache2/access.1.log
- after:
mode: '0640'
path: /var/log/apache2/access.2.log
before:
mode: '0777'
path: /var/log/apache2/access.2.log
And if you rerun those same two tasks again, then it ends up in:
TASK [file] *****************************************************************
ok: [localhost] => (item=/var/log/apache2/access.1.log)
ok: [localhost] => (item=/var/log/apache2/access.10.log)
ok: [localhost] => (item=/var/log/apache2/access.4.log)
ok: [localhost] => (item=/var/log/apache2/access.9.log)
ok: [localhost] => (item=/var/log/apache2/access.7.log)
ok: [localhost] => (item=/var/log/apache2/access.3.log)
ok: [localhost] => (item=/var/log/apache2/access.5.log)
ok: [localhost] => (item=/var/log/apache2/access.8.log)
ok: [localhost] => (item=/var/log/apache2/access.6.log)
ok: [localhost] => (item=/var/log/apache2/access.2.log)
TASK [List of security remediation run during this audit] *******************
ok: [localhost] =>
permission_audit.results | selectattr('changed') | map(attribute='diff'): []
Now, with an empty list on the last debug, we know our security audit passed everything with a green check.

Ansible append list on the delegated host

I have a requirement to build a list in a delegated host. Here is what I have so far. Under the "set the task" task, this line shut_interface: "{{ hostvars[item.value.hostname].shut_interface + [item.value.interface] }}" under set_fact is not really building a list.
---
- name: Test Play 1
hosts: localhost
gather_facts: no
vars:
devices:
test1:
hostname: host1
interface: Gi1/43
test2:
hostname: host1
interface: Gi1/44
test3:
hostname: host2
interface: Gi1/1
test4:
hostname: host2
interface: Gi1/2
tasks:
- name: Test Task 1
debug:
msg: "{{ devices }}"
- name: Initiate empty list
set_fact:
device_list: []
delegate_to: localhost
- name: Add devices
set_fact:
device_list: "{{ device_list + [item.value.hostname] }}"
delegate_to: localhost
delegate_facts: True
with_dict: "{{ devices }}"
- name: Initialize shut interface
set_fact:
shut_interface: []
delegate_to: "{{ item.value.hostname }}"
delegate_facts: True
with_dict: "{{ devices }}"
- name: set the task
set_fact:
shut_interface: "{{ hostvars[item.value.hostname].shut_interface + [item.value.interface] }}"
delegate_to: "{{ item.value.hostname }}"
delegate_facts: True
with_dict: "{{ devices }}"
- name: Test Play 2
hosts: "{{ hostvars['localhost']['device_list'] }}"
gather_facts: no
tasks:
- name: Tests 2
debug:
msg: "{{ shut_interface }}"
PLAY [Test Play 1] **************************************************************************************************************************************************************************************
TASK [Test Task 1] **************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"test1": {
"hostname": "host1",
"interface": "Gi1/43"
},
"test2": {
"hostname": "host1",
"interface": "Gi1/44"
},
"test3": {
"hostname": "host2",
"interface": "Gi1/1"
},
"test4": {
"hostname": "host2",
"interface": "Gi1/2"
}
}
}
TASK [Initiate empty list] ******************************************************************************************************************************************************************************
ok: [localhost -> localhost]
TASK [Add devices] **************************************************************************************************************************************************************************************
ok: [localhost -> localhost] => (item={'key': 'test1', 'value': {'hostname': 'host1', 'interface': 'Gi1/43'}})
ok: [localhost -> localhost] => (item={'key': 'test2', 'value': {'hostname': 'host1', 'interface': 'Gi1/44'}})
ok: [localhost -> localhost] => (item={'key': 'test3', 'value': {'hostname': 'host2', 'interface': 'Gi1/1'}})
ok: [localhost -> localhost] => (item={'key': 'test4', 'value': {'hostname': 'host2', 'interface': 'Gi1/2'}})
TASK [Initialize shut interface] ************************************************************************************************************************************************************************
ok: [localhost -> host1] => (item={'key': 'test1', 'value': {'hostname': 'host1', 'interface': 'Gi1/43'}})
ok: [localhost -> host1] => (item={'key': 'test2', 'value': {'hostname': 'host1', 'interface': 'Gi1/44'}})
ok: [localhost -> host2] => (item={'key': 'test3', 'value': {'hostname': 'host2', 'interface': 'Gi1/1'}})
ok: [localhost -> host2] => (item={'key': 'test4', 'value': {'hostname': 'host2', 'interface': 'Gi1/2'}})
TASK [set the task] *************************************************************************************************************************************************************************************
ok: [localhost -> host1] => (item={'key': 'test1', 'value': {'hostname': 'host1', 'interface': 'Gi1/43'}})
ok: [localhost -> host1] => (item={'key': 'test2', 'value': {'hostname': 'host1', 'interface': 'Gi1/44'}})
ok: [localhost -> host2] => (item={'key': 'test3', 'value': {'hostname': 'host2', 'interface': 'Gi1/1'}})
ok: [localhost -> host2] => (item={'key': 'test4', 'value': {'hostname': 'host2', 'interface': 'Gi1/2'}})
PLAY [Test Play 2] **************************************************************************************************************************************************************************************
TASK [Tests 2] ******************************************************************************************************************************************************************************************
ok: [host1] => {
"msg": [
"Gi1/44".
]
}
ok: [host2] => {
"msg": [
"Gi1/2".
]
}
I am expecting [Gi1/43, Gi1/44]for host 1 and [Gi1/1, Gi1/2] in host2. Any ideas?
I'm assuming that you don't want to change the device variable's data structure, so you can probably do something like the following:
---
- name: Test Play 1
hosts: 127.0.0.1
connection: local
gather_facts: no
vars:
devices:
test1:
hostname: host1
interface: Gi1/43
test2:
hostname: host1
interface: Gi1/44
test3:
hostname: host2
interface: Gi1/1
test4:
hostname: host2
interface: Gi1/2
tasks:
- name: Test Task 1
debug:
var: devices
- name: Add host_list
set_fact:
shut_interface_list: >-
{{ shut_interface_list|default({})|combine({devices[item].hostname:
(shut_interface_list[devices[item].hostname]|default([])) +
[(devices[item]|default({'interface': ''})).interface]
})
}}
loop: "{{ devices.keys()|list }}"
- name: Test Task 2
debug:
var: shut_interface_list
- name: Add testing hosts
add_host:
name: "{{ item }}"
groups: test_group
ansible_host: 127.0.0.1
loop: "{{ shut_interface_list.keys()|list }}"
- name: Test Play 2
hosts: test_group
vars:
shut_interfaces: "{{ hostvars['localhost']['shut_interface_list'][inventory_hostname] }}"
gather_facts: no
tasks:
- name: Test Task 3
debug:
var: shut_interfaces
Which should give you this result:
TASK [Test Task 3] ***********************************************************************************************************************************
ok: [host1] => {
"shut_interfaces": [
"Gi1/43",
"Gi1/44"
]
}
ok: [host2] => {
"shut_interfaces": [
"Gi1/1",
"Gi1/2"
]
}
Please correct the vars section declaration. Since you are defining the same hostnames twice the ansible reading the last defined vars as final and you are getting task2 output as Gi1/44 and Gi1/2.
vars:
devices:
test1:
hostname: host1
interface:
- Gi1/43
- Gi1/44
test2:
hostname: host2
interface:
- Gi1/1
- Gi1/2

Use two with_items loops in one Task

I did quite some research on this question. Though i did not find the answer to solve my problem.
I want to delete a directorys content with ansibe with deleting the directory itself. I want to do this for multiple directorys.
In theory i want to do something like this:
- name: Delete dir on Prod/Stag
file:
state: "{{ item.1 }}"
path: "{{ /path/ }}{{ item.2 }}/"
with_items.1:
- absent
- directory
with_items.2:
- test1
- test2
- test3
- test4
Sadly this does not work.
This is what i have right now.
- name: Delete dir
file:
state: absent
path: "{{ path }}{{ item }}/"
with_items:
- test1
- test2
- test3
- test4
Is there a way to make this code shorter by creating two loops?
You want with_nested:
- debug:
msg: "state: {{ item.0 }}; path: {{ item.1 }}"
with_nested:
- [ absent, directory ]
- [ sys, wifi, reco-properties, threshold-prod ]
Results in:
TASK [debug] *******************************************************************
ok: [localhost] => (item=[u'absent', u'sys']) => {
"msg": "state: absent; path: sys"
}
ok: [localhost] => (item=[u'absent', u'wifi']) => {
"msg": "state: absent; path: wifi"
}
ok: [localhost] => (item=[u'absent', u'reco-properties']) => {
"msg": "state: absent; path: reco-properties"
}
ok: [localhost] => (item=[u'absent', u'threshold-prod']) => {
"msg": "state: absent; path: threshold-prod"
}
ok: [localhost] => (item=[u'directory', u'sys']) => {
"msg": "state: directory; path: sys"
}
ok: [localhost] => (item=[u'directory', u'wifi']) => {
"msg": "state: directory; path: wifi"
}
ok: [localhost] => (item=[u'directory', u'reco-properties']) => {
"msg": "state: directory; path: reco-properties"
}
ok: [localhost] => (item=[u'directory', u'threshold-prod']) => {
"msg": "state: directory; path: threshold-prod"
}
https://docs.ansible.com/ansible/2.4/playbooks_loops.html#nested-loops

Loops inside inventory files?

Is it possible to use loops in the inventory files? For example in one inv file I got:
---
ISPs:
- name: ISP1
- name: ISP2
networks:
- name: network1
- name: network2
- name: network3
and then I want to create something like this in this same inventory:
from ISP1 to network1 permit
from ISP1 to network2 permit
from ISP1 to network3 permit
from ISP2 to network1 permit
from ISP2 to network2 permit
from ISP2 to network3 permit
but I think that using loops I could do it faster instead of copy-paste and write down all of the possible combinations. Is it even possible?
example:
from {{ item[0] }} to {{ item[1] }} permit
with_nested:
- [ 'ISP1', 'ISP2' ]
- [ 'network1', 'network2', 'network3' ]
will create something like this:
from ISP1 to network1 permit
from ISP1 to network2 permit
from ISP1 to network3 permit
from ISP2 to network1 permit
from ISP2 to network2 permit
from ISP2 to network3 permit
Thanks for any answer!
here is 2 variants,
see https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#with-nested-with-cartesian
---
- hosts: localhost
connection: local
gather_facts: false
vars:
ISPs:
- name: ISP1
- name: ISP2
networks:
- name: network1
- name: network2
- name: network3
tasks:
- name: Using with_nested
debug:
msg: '{{ item.0.name }} - {{item.1.name }} '
with_nested:
- '{{ ISPs }}'
- '{{ networks }}'
- name: Using loop
debug:
msg: '{{ item.0.name }} - {{item.1.name }} '
loop: "{{ ISPs | product(networks) | list }}"
Output:
PLAY [localhost] *******************************************************************************************************************************************************************************************
TASK [Using with_nested] ***********************************************************************************************************************************************************************************
ok: [localhost] => (item=[{u'name': u'ISP1'}, {u'name': u'network1'}]) => {
"msg": "ISP1 - network1 "
}
ok: [localhost] => (item=[{u'name': u'ISP1'}, {u'name': u'network2'}]) => {
"msg": "ISP1 - network2 "
}
ok: [localhost] => (item=[{u'name': u'ISP1'}, {u'name': u'network3'}]) => {
"msg": "ISP1 - network3 "
}
ok: [localhost] => (item=[{u'name': u'ISP2'}, {u'name': u'network1'}]) => {
"msg": "ISP2 - network1 "
}
ok: [localhost] => (item=[{u'name': u'ISP2'}, {u'name': u'network2'}]) => {
"msg": "ISP2 - network2 "
}
ok: [localhost] => (item=[{u'name': u'ISP2'}, {u'name': u'network3'}]) => {
"msg": "ISP2 - network3 "
}
TASK [Using loop] ******************************************************************************************************************************************************************************************
ok: [localhost] => (item=[{u'name': u'ISP1'}, {u'name': u'network1'}]) => {
"msg": "ISP1 - network1 "
}
ok: [localhost] => (item=[{u'name': u'ISP1'}, {u'name': u'network2'}]) => {
"msg": "ISP1 - network2 "
}
ok: [localhost] => (item=[{u'name': u'ISP1'}, {u'name': u'network3'}]) => {
"msg": "ISP1 - network3 "
}
ok: [localhost] => (item=[{u'name': u'ISP2'}, {u'name': u'network1'}]) => {
"msg": "ISP2 - network1 "
}
ok: [localhost] => (item=[{u'name': u'ISP2'}, {u'name': u'network2'}]) => {
"msg": "ISP2 - network2 "
}
ok: [localhost] => (item=[{u'name': u'ISP2'}, {u'name': u'network3'}]) => {
"msg": "ISP2 - network3 "
}
PLAY RECAP *************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
It is possible to do, but applying login inside ansible code will be messy, So better idea is to invoke any bash or python script in ansible & pass these two list as an argument to that script & return the expected array from the script at the end & store this value to fact using set_fact
Example:
tasks:
- set_fact: isp_networks="{{ lookup('pipe','python script.py ' + {{ISPs}} + ' ' + {{networks}}) }}"
- debug: var={{isp_networks}}

Resources