# Nested loops with subelements

**URL:** <https://forum.ansible.com/t/nested-loops-with-subelements/16698>\
**Category:** Ansible Project\
**Tags:** aws\
**Created:** [November 5, 2014, 5:25am UTC](https://forum.ansible.com/t/nested-loops-with-subelements/16698 "2014-11-05T05:25:08Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ananda\_Debnath](https://avatars.discourse-cdn.com/v4/letter/a/258eb7/32.png) [@Ananda\_Debnath](https://forum.ansible.com/u/Ananda_Debnath)\
**Post date:** [November 5, 2014, 5:25am UTC](https://forum.ansible.com/t/nested-loops-with-subelements/16698/1 "2014-11-05T05:25:08Z")

</div>

Hi,

As others have before me, I find the syntax for nested loops somewhat confusing ☹

Consider my group\_vars:  
ec2\_specs:

- { region: “us-east-1”, ami: “ami-b66ed3de”, count: 1, type: “t2.micro” }
- { region: “us-west-1”, ami: “ami-b56e64f0”, count: 2, type: “t2.micro” }
- { region: “sa-east-1”, ami: “ami-9337828e”, count: 1, type: “t2.micro” }

nginx\_containers:

- { name: “NGINX\_A”, hostport: “443” }
- { name: “NGINX\_B”, hostport: “444” }
- { name: “NGINX\_B”, hostport: “445” }

I’m setting up a security group for these instances like so:

- name: Setup AWS EC2 Security group  
ec2\_group:  
name: microserver\_security\_group  
description: “Security group for microservices”  
region: “{{ item.region }}”  
rules:
- proto: tcp  
from\_port: 22  
to\_port: 22  
cidr\_ip: 0.0.0.0/0
- proto: tcp  
**from\_port: 443**  
**to\_port: 445**  
cidr\_ip: 0.0.0.0/0  
rules\_egress:
- proto: all  
cidr\_ip: 0.0.0.0/0  
with\_items: ec2\_specs

This works because the host ports are continuous 443-445. I need to retain the flexibility of changing this to something like 443, 1443, 2443 … etc. One way to express this might be:

- name: Setup AWS EC2 Security group  
ec2\_group:  
name: microserver\_security\_group  
description: “Security group for microservices”  
region: “{{ item.region }}”  
rules:
- proto: tcp  
from\_port: 22  
to\_port: 22  
cidr\_ip: 0.0.0.0/0
- proto: tcp  
**from\_port: “{{ subitem.hostport }}”**  
**to\_port: “{{ subitem.hostport }}”**  
cidr\_ip: 0.0.0.0/0  
**with\_subitems: nginx\_containers**  
rules\_egress:
- proto: all  
cidr\_ip: 0.0.0.0/0  
with\_items: ec2\_specs

Something like: with\_XYZ at arbitrary levels with XYZ representing each item would be intuitive to me here. No doubt there are other ways of expressing this as well - where the syntax makes visual sense. As of now though, I don’t know how to accomplish this short of hard-coding it in the role tasks.

A second problem arising from the same problem (or my lack of syntactic know-how) is the way I call ec2 and use its somewhat clunky output.

- name: Setup AWS EC2 Instances  
ec2:  
instance\_type: “{{ item.type }}”  
image: “{{ item.ami }}”  
monitoring: no  
wait: yes  
group: microserver\_security\_group  
key\_name: microserver\_keypair  
instance\_tags:  
nvtype: microserver  
Name: “MicroServer”  
count: “{{ item.count }}”  
region: “{{ item.region }}”  
with\_items: ec2\_specs  
register: ec2

The only way I’ve found of using the output of the above is the following sanity test example:

- name: Test microsites 443  
shell: chdir={{ tempdir.stdout }} /usr/bin/curl -v -s -k --key test.key --cert test.crt https://{{ **item.1.public\_ip** }}:443  
**with\_subelements:**  
**- ec2.results**  
**- instances**  
register: curl\_out

Since the curl\_test itself runs from localhost, I can’t use the dynamic inventory within the site.yml file against the test role. I now have to hard-code N tests here - one for each host-port in the nginx\_containers variable. I’d much rather express this as a single task with a nested loop - but I haven’t been able to figure out how to.

Is this possible?

Many thanks,  
Ananda

---

<div class="post-metadata">

**Author:** ![Ananda\_Debnath](https://avatars.discourse-cdn.com/v4/letter/a/258eb7/32.png) [@Ananda\_Debnath](https://forum.ansible.com/u/Ananda_Debnath)\
**Post date:** [November 5, 2014, 5:34am UTC](https://forum.ansible.com/t/nested-loops-with-subelements/16698/2 "2014-11-05T05:34:52Z")

</div>

I guess I could express it as a nested dict in the first place?

ec2\_specs:

- { region: “us-east-1”, ami: “ami-b66ed3de”, count: 1, type: “t2.micro”, containers: [{ name: “NGINX\_A”, hostport: “443” }, { name: “NGINX\_B”, hostport: “444” }] }
- etc

I suspect though that if I need to express a large number of these, it can get error-prone - so a set of M properties and a set of N sub-properties would still be a more compact and less error-prone representation of this matrix.

---

<div class="post-metadata">

**Author:** ![Ananda\_Debnath](https://avatars.discourse-cdn.com/v4/letter/a/258eb7/32.png) [@Ananda\_Debnath](https://forum.ansible.com/u/Ananda_Debnath)\
**Post date:** [November 5, 2014, 11:42pm UTC](https://forum.ansible.com/t/nested-loops-with-subelements/16698/3 "2014-11-05T23:42:29Z")

</div>

Any recommendations?

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [November 7, 2014, 2:16pm UTC](https://forum.ansible.com/t/nested-loops-with-subelements/16698/4 "2014-11-07T14:16:35Z")

</div>

Sorry, I’m not sure what your specific question is.

I see a lot of text without a question mark and am having trouble parsing.

---

<div class="post-metadata">

**Author:** ![Ananda\_Debnath](https://avatars.discourse-cdn.com/v4/letter/a/258eb7/32.png) [@Ananda\_Debnath](https://forum.ansible.com/u/Ananda_Debnath)\
**Post date:** [November 7, 2014, 3:08pm UTC](https://forum.ansible.com/t/nested-loops-with-subelements/16698/5 "2014-11-07T15:08:51Z")

</div>

Thanks for looking Michael,

I was looking for an intuitive way for expressing nested variables in this use case.

In my group vars, I specify 3 ec2 region/ami specs:  
ec2\_specs:

- { region: “us-east-1”, ami: “ami-b66ed3de”, count: 1, type: “t2.micro” }
- { region: “us-west-1”, ami: “ami-b56e64f0”, count: 2, type: “t2.micro” }
- { region: “sa-east-1”, ami: “ami-9337828e”, count: 1, type: “t2.micro” }

I want to spin up _count_ instances of each ami. In _each_ of them I want to setup N separate processes that run on different ports:  
process\_ports:

- { name: “Process\_A”, hostport: “1443” }
- { name: “Process\_B”, hostport: “2974” }
- { name: “Process\_C”, hostport: “3555” }

To make sure these ports are accessible from the outside world I need to set up ec2 security groups for these instances. **How can I express this by using my group vars rather than hard coding them as I have done below?**

- name: Setup AWS EC2 Security group  
ec2\_group:  
name: microserver\_security\_group  
description: “Security group for microservices”  
region: “{{ item.region }}”  
rules:
- proto: tcp  
from\_port: 22  
to\_port: 22  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)
- proto: tcp  
**from\_port: 1443**  
**to\_port: 1443**  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)
- proto: tcp  
**from\_port: 2754**  
**to\_port: 2754**  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)
- proto: tcp  
**from\_port: 3555**  
**to\_port: 3555**  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)  
rules\_egress:
- proto: all  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)  
with\_items: **ec2\_specs**

Using nesting variables trivially doesn’t work:

- name: Setup AWS EC2 Security group  
ec2\_group:  
name: microserver\_security\_group  
description: “Security group for microservices”  
region: “{{ item[0].region }}”  
rules:
- proto: tcp  
from\_port: 22  
to\_port: 22  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)
- proto: tcp  
**from\_port: “{{ item[1].hostport }}”**  
**to\_port:** **“{{ item[1].hostport }}”**  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)  
rules\_egress:
- proto: all  
cidr\_ip: [0.0.0.0/0](http://0.0.0.0/0)  
with\_nested:  
**- ec2\_specs**  
**- process\_ports**

This simply causes 3 separate runs of the same ec2\_group command and I end up with a single security group in each region where only the last hostport is exposed (each run overwriting the previous run).

---

<div class="post-metadata">

**Author:** ![vaida.dan](https://avatars.discourse-cdn.com/v4/letter/v/5daacb/32.png) [@vaida.dan](https://forum.ansible.com/u/vaida.dan)\
**Post date:** [December 29, 2014, 10:15am UTC](https://forum.ansible.com/t/nested-loops-with-subelements/16698/6 "2014-12-29T10:15:01Z")

</div>

Hello Ananda,

Is your number of processes (containers in your case) static? What about the ports? do they have a particular generation rule that matters to you?
