Hello,
I am attempting to make my EC2 VPC infrastructure indempotent. I have a list of VPC dictionaries for a region. Each VPC has a list of security_groups. I am having problems using the with_subelements: loop/lookup
My contrived playbook: Two VPCs, each has a sub-list of security_group dictionaries:
`
- hosts: localhost
vars:
vpcs: - name: my vpc 1
cidr_block: 10.0.0.0/16
subnets: - cidr: 10.0.0.0/24
az: us-west-2a
security_groups: - name: all
description: all hosts
rules: - proto: tcp
from_port: 80
to_port: 80
cidr_ip: 0.0.0.0/0
rules_egress: - proto: all
from_port: all
to_port: all
cidr_ip: 0.0.0.0/0 - name: my vpc 2
cidr_block: 10.10.0.0/16
subnets: - cidr: 10.10.0.0/24
az: us-west-2a
security_groups: - name: all
description: all hosts
rules: - proto: tcp
from_port: 443
to_port: 443
cidr_ip: 0.0.0.0/0
rules_egress: - proto: all
from_port: all
to_port: all
cidr_ip: 0.0.0.0/0
tasks:
-
local_action:
module: ec2_vpc
resource_tags: { Name: “{{ item.name }}” }
cidr_block: “{{ item.cidr_block }}”
subnets: “{{ item.subnets }}”
state: present
with_items: vpcs
register: result_vpcs -
debug: var=result_vpcs
-
local_action:
module: ec2_group
name: “{{ item[1].name }}”
description: “{{ item[1].description }}”
rules: “{{ item[1].rules }}”
rules_egress: “{{ item[1].rules_egress }}”
58 with_subelements:
59 - result_vpcs.results
60 - item
`
For each dictionary in the list result_vpcs.results, I want to get the sub-element of the item.security_groups list as the basis for creating my security groups. This is nuanced but really useful (i.e. idempotent).
`
“result_vpcs”: {
“changed”: false,
“msg”: “All items completed”,
“results”: [
{
“changed”: false,
“invocation”: {
“module_args”: “”,
“module_name”: “ec2_vpc”
},
“item”: {
“cidr_block”: “10.0.0.0/16”,
“name”: “my vpc 1”,
“security_groups”: [
{
“description”: “all hosts”,
“name”: “all”,
“rules”: [
{
“cidr_ip”: “0.0.0.0/0”,
“from_port”: 80,
“proto”: “tcp”,
“to_port”: 80
}
],
“rules_egress”: [
{
“cidr_ip”: “0.0.0.0/0”,
“from_port”: “all”,
“proto”: “all”,
“to_port”: “all”
}
]
}
],
“subnets”: [
{
“az”: “us-west-2a”,
“cidr”: “10.0.0.0/24”
}
]
},
“subnets”: [
{
“az”: “us-west-2a”,
“cidr”: “10.0.0.0/24”,
“id”: “subnet-886eb6ff”,
“resource_tags”: {}
}
],
“vpc”: {
“cidr_block”: “10.0.0.0/16”,
“dhcp_options_id”: “dopt-0ee3056b”,
“id”: “vpc-67f35302”,
“region”: “us-west-2”,
“state”: “available”
},
“vpc_id”: “vpc-67f35302”
},
{
“changed”: false,
“invocation”: {
“module_args”: “”,
“module_name”: “ec2_vpc”
},
“item”: {
“cidr_block”: “10.10.0.0/16”,
“name”: “my vpc 2”,
“security_groups”: [
{
“description”: “all hosts”,
“name”: “all”,
“rules”: [
{
“cidr_ip”: “0.0.0.0/0”,
“from_port”: 443,
“proto”: “tcp”,
“to_port”: 443
}
],
“rules_egress”: [
{
“cidr_ip”: “0.0.0.0/0”,
“from_port”: “all”,
“proto”: “all”,
“to_port”: “all”
}
]
}
],
“subnets”: [
{
“az”: “us-west-2a”,
“cidr”: “10.10.0.0/24”
}
]
},
“subnets”: [
{
“az”: “us-west-2a”,
“cidr”: “10.10.0.0/24”,
“id”: “subnet-746fb703”,
“resource_tags”: {}
}
],
“vpc”: {
“cidr_block”: “10.10.0.0/16”,
“dhcp_options_id”: “dopt-0ee3056b”,
“id”: “vpc-60f35305”,
“region”: “us-west-2”,
“state”: “available”
},
“vpc_id”: “vpc-60f35305”
}
]
}
}
`
The error from using sub_elements:
TASK: [ec2_group] *************************************************************
fatal: [localhost] => the key item should point to a list, got '{‘subnets’: [[{‘cidr’: ‘10.0.0.0/24’, ‘az’: ‘us-west-2a’}], ’
`
`
No surprise there. I read the code and see that it expects a string as the key name to use. Is there a way I can traverse the result_vpcs to create the security_groups like I want? I’ve looked at using with_nested, but that doesn’t do what I want.
Perhaps with_subelements should be changed a bit to allow either a string or an arbitrary list. I.e. so one can use item.security_groups as the second term instead of simply a string.
This seems like what I want: https://github.com/ansible/ansible/pull/6370
Am I overlooking some loop/filter capability in Ansible that can be used in my scenario?
Thanks,
Robb