Reputation: 77
I am trying to loop over a following variable structure using ansible and what I want is to loop over each subnet. For subnets-1 I want to get network, cidr, vlan similarly loop other keys subnets-2, subnets-3
flavor.json
{
"subnets-1": [
{
"network": "test1",
"cidr": 21,
"vlan": 123
},
{
"network": "test2",
"cidr": 22,
"vlan": 234
}
],
"subnets-2": [
{
"network": "test3",
"cidr": 43,
"vlan": 879
},
{
"network": "test4",
"cidr": 21,
"vlan": "12fsd"
},
{
"network": "test5",
"cidr": "22sdf",
"vlan": "234sdfd"
}
],
"subnets-3": [
{
"network": "test44",
"cidr": "fg",
"vlan": "dsfsd"
}
]
}
I have tried something like below using with_dict
playbook.yml (ansible 2.9.7)
---
- hosts: local
gather_facts: no
tasks:
- name: lookup yaml
set_fact:
flavors: "{{ lookup('file','flavor.json') | from_json }}"
- name: json out
debug:
msg: "{{ flavors }}"
- name: check keys
shell: |
echo "s_name = {{ item.network }}"
echo "s_cidr = {{ item.cidr }}"
echo "s_vlan = {{ item.vlan }}"
with_dict:
"{{ flavors }}"
This is the error I get when playbook was executed
Error:
fatal: [192.168.110.128]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'network'\n\nThe error appears to be in '/root/fla.yml': line 19, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: check keys\n ^ here\n"
}
Upvotes: 1
Views: 4470
Reputation: 68024
Use include_vars. It's simpler compared to lookup and from_yaml, e.g.
- include_vars:
file: flavor.json
name: flavors
gives
flavors:
subnets-1:
- {cidr: 21, network: test1, vlan: 123}
- {cidr: 22, network: test2, vlan: 234}
subnets-2:
- {cidr: 43, network: test3, vlan: 879}
- {cidr: 21, network: test4, vlan: 12fsd}
- {cidr: 22sdf, network: test5, vlan: 234sdfd}
subnets-3:
- {cidr: fg, network: test44, vlan: dsfsd}
Then convert the dictionary to list and iterate with_subelements, e.g.
- debug:
msg: "{{ item.0.key }}
{{ item.1.network }}
{{ item.1.cidr }}
{{ item.1.vlan }}"
with_subelements:
- "{{ flavors|dict2items }}"
- value
gives
msg: subnets-1 test1 21 123
msg: subnets-1 test2 22 234
msg: subnets-2 test3 43 879
msg: subnets-2 test4 21 12fsd
msg: subnets-2 test5 22sdf 234sdfd
msg: subnets-3 test44 fg dsfsd
Upvotes: 2
Reputation: 6158
Ansible does not do nested loops well. In this case, you know you have a maximum of three array elements. So you can loop like this:
- name: loop over flavors
debug:
msg: "{{ flavors[item.0][item.1] }}"
with_nested:
- "{{ flavors }}"
- [ 0, 1, 2 ]
when: flavors[item.0][item.1] is defined
Which results in something like this:
TASK [loop over flavors] *********************************************************************************************
ok: [localhost] => (item=['subnets-1', 0]) => {
"msg": {
"cidr": 21,
"network": "test1",
"vlan": 123
}
}
ok: [localhost] => (item=['subnets-1', 1]) => {
"msg": {
"cidr": 22,
"network": "test2",
"vlan": 234
}
}
skipping: [localhost] => (item=['subnets-1', 2])
ok: [localhost] => (item=['subnets-2', 0]) => {
"msg": {
"cidr": 43,
"network": "test3",
"vlan": 879
}
}
ok: [localhost] => (item=['subnets-2', 1]) => {
"msg": {
"cidr": 21,
"network": "test4",
"vlan": "12fsd"
}
}
ok: [localhost] => (item=['subnets-2', 2]) => {
"msg": {
"cidr": "22sdf",
"network": "test5",
"vlan": "234sdfd"
}
}
ok: [localhost] => (item=['subnets-3', 0]) => {
"msg": {
"cidr": "fg",
"network": "test44",
"vlan": "dsfsd"
}
}
skipping: [localhost] => (item=['subnets-3', 1])
skipping: [localhost] => (item=['subnets-3', 2])
Upvotes: 0