Repository: ansible/ansible

Issue:
ec2 module reports instance IDs in different sequence when launching instances 
##### ISSUE TYPE
 - Bug Report


##### COMPONENT NAME
ec2

##### ANSIBLE VERSION
```
max $ ansible --version
ansible 2.4.2.0
  config file = None
  configured module search path = [u'/Users/max/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Library/Python/2.7/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.10 (default, Jul 15 2017, 17:16:57) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)]
```

##### CONFIGURATION
```
max $ ansible-config dump --only-changed
max $
```

##### OS / ENVIRONMENT
Running from OSX.
You'll need to have setup keys/tokens to access AWS for the EC2 module to work.

##### SUMMARY
When creating instances with the EC2 module the tagged_instances result is in a different sequence than if you run the same command later. This breaks idempotence.

##### STEPS TO REPRODUCE
```yaml
---

- name: AWS | Provision Boxes
  hosts: localhost
  tags: provision
  become: false
  tasks:
  - ec2:
      key_name: .....
      group: ['.....']
      instance_type: t2.nano
      image: ....
      wait: yes
      wait_timeout: 500
      vpc_subnet_id: .......
      region: eu-west-1
      instance_tags: {"Name":"ansibletest","Project":"ansibletest","Scheduler":"Turn off nightly"}
      exact_count: 12
      assign_public_ip: no
      count_tag:
        Project: "ansibletest"
    register: aws_instances

  - set_fact:
      message: "{{ message| default([]) + [ aws_instances.tagged_instances[item|int].id ] }}"
    with_sequence: start=0 end={{aws_instances.tagged_instances|count - 1}}

  - debug:
      var: message

```
You'll need _your own_ key/group/subnet/ami settings, "....." won't work and neither will anything else I give you!
I've used the AWS linux and RedHat AMIs and t5.large and t2.nano instance types to reproduce this issue. I imagine those settings are not having any affect on the outcome.

##### EXPECTED RESULTS
First run reports :
```
TASK [debug] *********************************************************************************************************************
ok: [localhost] => {
    "message": [
        "i-075aa33c537265d85", 
        "i-09301cf1e8a06ce91", 
        "i-081ef6b6945d5c164", 
        "i-069c26d03ddbe1753", 
        "i-014fd94e0e8388479", 
        "i-0e8e6b87acc45a59f", 
        "i-023a47c8cd50efa5c", 
        "i-00dc58dac5b16b257", 
        "i-01e67403b9ea37db2", 
        "i-09761fccba66ae666", 
        "i-024115814c02e5f7e", 
        "i-05bb09530ea5a6893"
    ]
}
```
I would expect subsequent runs to produce the same results.

##### ACTUAL RESULTS
The sequence of instances is now different.

So when I loop through the tagged_instances[..] and assign a different task to each instance, they get different tasks when the script is re-run.

AFTER the instances are launched, the sequencing seems to be stable. I ran the same command over a hundred times and got the same output. But every time I launch instances, the result is different from subsequent runs. I'm pretty sure that in my previous version (might have been 2.3 something) it would always report instances in the same sequence.

```
ok: [localhost] => {
    "message": [
        "i-075aa33c537265d85", 
        "i-09301cf1e8a06ce91", 
        "i-0e8e6b87acc45a59f", 
        "i-023a47c8cd50efa5c", 
        "i-081ef6b6945d5c164", 
        "i-069c26d03ddbe1753", 
        "i-00dc58dac5b16b257", 
        "i-01e67403b9ea37db2", 
        "i-09761fccba66ae666", 
        "i-024115814c02e5f7e", 
        "i-05bb09530ea5a6893", 
        "i-014fd94e0e8388479"
    ]
}

```

ec2 module reports instance IDs in different sequence when launching instances 
##### ISSUE TYPE
 - Bug Report


##### COMPONENT NAME
ec2

##### ANSIBLE VERSION
```
max $ ansible --version
ansible 2.4.2.0
  config file = None
  configured module search path = [u'/Users/max/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Library/Python/2.7/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.10 (default, Jul 15 2017, 17:16:57) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)]
```

##### CONFIGURATION
```
max $ ansible-config dump --only-changed
max $
```

##### OS / ENVIRONMENT
Running from OSX.
You'll need to have setup keys/tokens to access AWS for the EC2 module to work.

##### SUMMARY
When creating instances with the EC2 module the tagged_instances result is in a different sequence than if you run the same command later. This breaks idempotence.

##### STEPS TO REPRODUCE
```yaml
---

- name: AWS | Provision Boxes
  hosts: localhost
  tags: provision
  become: false
  tasks:
  - ec2:
      key_name: .....
      group: ['.....']
      instance_type: t2.nano
      image: ....
      wait: yes
      wait_timeout: 500
      vpc_subnet_id: .......
      region: eu-west-1
      instance_tags: {"Name":"ansibletest","Project":"ansibletest","Scheduler":"Turn off nightly"}
      exact_count: 12
      assign_public_ip: no
      count_tag:
        Project: "ansibletest"
    register: aws_instances

  - set_fact:
      message: "{{ message| default([]) + [ aws_instances.tagged_instances[item|int].id ] }}"
    with_sequence: start=0 end={{aws_instances.tagged_instances|count - 1}}

  - debug:
      var: message

```
You'll need _your own_ key/group/subnet/ami settings, "....." won't work and neither will anything else I give you!
I've used the AWS linux and RedHat AMIs and t5.large and t2.nano instance types to reproduce this issue. I imagine those settings are not having any affect on the outcome.

##### EXPECTED RESULTS
First run reports :
```
TASK [debug] *********************************************************************************************************************
ok: [localhost] => {
    "message": [
        "i-075aa33c537265d85", 
        "i-09301cf1e8a06ce91", 
        "i-081ef6b6945d5c164", 
        "i-069c26d03ddbe1753", 
        "i-014fd94e0e8388479", 
        "i-0e8e6b87acc45a59f", 
        "i-023a47c8cd50efa5c", 
        "i-00dc58dac5b16b257", 
        "i-01e67403b9ea37db2", 
        "i-09761fccba66ae666", 
        "i-024115814c02e5f7e", 
        "i-05bb09530ea5a6893"
    ]
}
```
I would expect subsequent runs to produce the same results.

##### ACTUAL RESULTS
The sequence of instances is now different.

So when I loop through the tagged_instances[..] and assign a different task to each instance, they get different tasks when the script is re-run.

AFTER the instances are launched, the sequencing seems to be stable. I ran the same command over a hundred times and got the same output. But every time I launch instances, the result is different from subsequent runs. I'm pretty sure that in my previous version (might have been 2.3 something) it would always report instances in the same sequence.

```
ok: [localhost] => {
    "message": [
        "i-075aa33c537265d85", 
        "i-09301cf1e8a06ce91", 
        "i-0e8e6b87acc45a59f", 
        "i-023a47c8cd50efa5c", 
        "i-081ef6b6945d5c164", 
        "i-069c26d03ddbe1753", 
        "i-00dc58dac5b16b257", 
        "i-01e67403b9ea37db2", 
        "i-09761fccba66ae666", 
        "i-024115814c02e5f7e", 
        "i-05bb09530ea5a6893", 
        "i-014fd94e0e8388479"
    ]
}

```



Discussion:
Files identified in the description:
* [lib/ansible/modules/cloud/amazon/ec2.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/amazon/ec2.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @lwade @tgerla @willthames
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Files identified in the description:
* [lib/ansible/modules/cloud/amazon/ec2.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/amazon/ec2.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @lwade @tgerla @willthames
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/amazon/ec2.py b/lib/ansible/modules/cloud/amazon/ec2.py
--- a/lib/ansible/modules/cloud/amazon/ec2.py
+++ b/lib/ansible/modules/cloud/amazon/ec2.py
@@ -1755,6 +1755,14 @@ def main():
         else:
             (tagged_instances, instance_dict_array, new_instance_ids, changed) = enforce_count(module, ec2, vpc)
 
+    # Always return instances in the same order
+    if new_instance_ids:
+        new_instance_ids.sort()
+    if instance_dict_array:
+        instance_dict_array.sort(key=lambda x: x['id'])
+    if tagged_instances:
+        tagged_instances.sort(key=lambda x: x['id'])
+
     module.exit_json(changed=changed, instance_ids=new_instance_ids, instances=instance_dict_array, tagged_instances=tagged_instances)
 
 


Test patch: