Repository: ansible/ansible-modules-core

Issue:
ec2_vpc subnets in seemingly random order
When building VPCs using the ec2_vpc module the subnets are returned in a seemingly arbitrary order. It would be nice if they were returned in the order specified or ordered by cidr block to simplify deploying EC2 instances into specific subnets consistently. 



Discussion:
# Can You Help Us Out?

Thanks for filing a ticket! I am the friendly GitHub Ansibot. 

It looks like you might not have filled out the issue description based on our standard issue template.  You might not have known about that, and that's ok too, we'll tell you how to do it.

We have a standard template because Ansible is a really busy project and it helps to have some standard information in each ticket, and GitHub doesn't yet provide a standard facility to do this like some other bug trackers.  We hope you understand as this is really valuable to us!. 

Solving this is simple: please copy the contents of this [template](https://raw.githubusercontent.com/ansible/ansible/devel/ISSUE_TEMPLATE.md) and **paste it into the description** of your ticket.  That's it!

# If You Had A Question To Ask Instead

If you happened to have a "how do I do this in Ansible" type of question, that's probably more of a user-list question than a bug report, and you should probably ask this question on the project mailing list instead.  

However, if you think you have a bug, the report is the way to go!  We definitely want all the bugs filed :)  Just trying to help!

# About Priority Tags

Since you're here, we'll also share some useful information at this time.

In general tickets will be assigned a priority between P1 (highest) and P5, and then worked in priority order. We may also have some follow up questions along the way, so keeping up with follow up comments via GitHub notifications is a good idea.

Due to large interest in Ansible, humans may not comment on your ticket immediately.  

# Mailing Lists

If you have concerns or questions, you're welcome to stop by the ansible-project or ansible-development mailing lists, as appropriate.  Here are the links:
- https://groups.google.com/forum/#!forum/ansible-project - for discussion of bugs and how-to type questions
- https://groups.google.com/forum/#!forum/ansible-devel - for discussion on how to implement a code change, or feature brainstorming among developers

Thanks again for the interest in Ansible!

Try something along the lines of the following playbook, Add a few subnets, remove a few subnets, and you'll notice the ordering  is fairly arbitrary. 

```
---
- hosts: provisioner
  sudo: no
  gather_facts: no
  pre_tasks:
    - include_vars: "{{ inventory_dir }}/vault"
  post_tasks:
    - pip: name=boto state=present
    - local_action:
        module: ec2_vpc
        state: present
        cidr_block: 10.0.0.0/24
        resource_tags: { "env" : "prod" }
        region: us-east-1
        subnets:
          - cidr: 10.0.0.0/26
            az: us-east-1b
            resource_tags: { "env": "prod", "sec": "public" }
          - cidr: 10.0.0.64/26
            az: us-east-1b
            resource_tags: { "env": "prod", "sec": "public" }
          - cidr: 10.0.0.128/26
            az: us-east-1c
            resource_tags: { "env": "prod", "sec": "public" }
          - cidr: 10.0.0.192/26
            az: us-east-1c
            resource_tags: { "env": "prod", "sec": "public" }
        internet_gateway: true
        route_tables:
          - subnets:
              - 10.0.0.0/26
              - 10.0.0.128/26
            routes:
              - dest: 0.0.0.0/0
                gw: igw
        wait: yes
      register: vpc

    - debug: var=vpc

    - name: "Create AZ A Web Instance"
      local_action:
        module: ec2
        count: 1
        assign_public_ip: True
        instance_tags: { "env": "prod", "tier": "app", "az": "a" }
        id: app
        key_name:
        instance_type: t1.micro
        vpc_subnet_id: "{{ vpc.subnets[0].id }}"

    - name: "Create AZ A Mongo Instance"
      local_action:
        module: ec2
        count: 1
        assign_public_ip: False
        instance_tags: { "env": "prod", "tier": "db", "az": "a" }
        id: app
        key_name:
        instance_type: t1.micro
        vpc_subnet_id: "{{ vpc.subnets[1].id }}"

    - name: "Create AZ B Web Instance"
      local_action:
        module: ec2
        count: 1
        assign_public_ip: True
        instance_tags: { "env": "prod", "tier": "app", "az": "a" }
        id: app
        key_name:
        instance_type: t1.micro
        vpc_subnet_id: "{{ vpc.subnets[2].id }}"

    - name: "Create AZ B Mongo Instance"
      local_action:
        module: ec2
        count: 1
        assign_public_ip: False
        instance_tags: { "env": "prod", "tier": "db", "az": "a" }
        id: app
        key_name:
        instance_type: t1.micro
        vpc_subnet_id: "{{ vpc.subnets[3].id }}"

```

+1, this affect us, too

It would be very nice to have subnets returned in the same order as they were specified in playbook. 

2 repo admins: I don't see any way to refactor my playbook (or example playbook above) in order to overcome ordering issue so I did the quick fix in https://github.com/daniilyar/ansible-modules-core/commit/87b475786e7ec2bcbb506005381d863b42d67bf7 

Please review my code and notify me to process with PR if you agree with my update.

normally you submit the PR and then we review and/or merge the code

@daniilyar I'm not convinced this works correctly. I've just been testing it, and I get this fail:

```
TASK: [Change default route to NAT instance] ********************************** 
failed: [localhost -> 127.0.0.1] => {"failed": true, "parsed": false}
Traceback (most recent call last):
  File "/Users/markp/.ansible/tmp/ansible-tmp-1422639199.78-80626510026309/ec2_vpc", line 2388, in <module>
    main()
  File "/Users/markp/.ansible/tmp/ansible-tmp-1422639199.78-80626510026309/ec2_vpc", line 622, in main
    (vpc_dict, new_vpc_id, subnets_changed, changed) = create_vpc(module, vpc_conn)
  File "/Users/markp/.ansible/tmp/ansible-tmp-1422639199.78-80626510026309/ec2_vpc", line 501, in create_vpc
    for subnet in subnets:
TypeError: 'NoneType' object is not iterable
```

Line 501 is directly related to your change too. My play sets up a VPC, then a NAT instance, then tries to change the routing tables. [Here's the play](https://gist.github.com/phips/6821e17f988c91c0c0aa).

>   File "/Users/markp/.ansible/tmp/ansible-tmp-1422639199.78-80626510026309/ec2_vpc", line  501, in create_vpc
>    for subnet in subnets:

@phips, thank you for testing!

Reason is lacking of 'if subnets is not None' check. Fixed in https://github.com/daniilyar/ansible-modules-core/commit/8050644ad7d14b860967cd32d785741be6e4a888 
Could you, please, test it again while I am proceeding with PR ?

@daniilyar Yep, that one works! @bcoca - sorted lad.

@daniilyar wan't to submit a Pull request?

@bcoca, https://github.com/ansible/ansible-modules-core/pull/825


Resolving patch:
diff --git a/cloud/amazon/ec2_vpc.py b/cloud/amazon/ec2_vpc.py
--- a/cloud/amazon/ec2_vpc.py
+++ b/cloud/amazon/ec2_vpc.py
@@ -506,6 +506,15 @@ def create_vpc(module, vpc_conn):
             'id': sn.id,
         })
 
+    # Sort subnets by the order they were listed in the play
+    order = {}
+    for idx, val in enumerate(subnets):
+        order[val['cidr']] = idx
+
+    # Number of subnets in the play
+    subnets_in_play = len(subnets)
+    returned_subnets.sort(key=lambda x: order.get(x['cidr'], subnets_in_play))
+
     return (vpc_dict, created_vpc_id, returned_subnets, changed)
 
 def terminate_vpc(module, vpc_conn, vpc_id=None, cidr=None):


Test patch: