Repository: ansible/ansible

Issue:
dictionary changed size during iteration when using elb_target_group_facts
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
elb_target_group_facts

##### ANSIBLE VERSION
Using latest version in devel branch
```
ansible 2.5.0 (devel adc533804a) last updated 2017/09/12 14:51:23 (GMT -200)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/gustavo/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/gustavo/Documents/Tools/Ansible/source/ansible/lib/ansible
  executable location = /home/gustavo/Documents/Tools/Ansible/source/ansible/bin/ansible
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
Nothing special

##### OS / ENVIRONMENT
N/A (since it's an AWS module). My workstation is Linux Mint 18.0

##### SUMMARY
When using the module elb_target_group_facts I'm getting this exception:
```Traceback (most recent call last):
  File "/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py", line 270, in <module>
    main()
  File "/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py", line 266, in main
    list_target_groups(connection, module)
  File "/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py", line 228, in list_target_groups
    target_group.update(get_target_group_attributes(connection, module, target_group['TargetGroupArn']))
  File "/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py", line 187, in get_target_group_attributes
    for k, v in target_group_attributes.items():
RuntimeError: dictionary changed size during iteration

fatal: [localhost]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py\", line 270, in <module>\n    main()\n  File \"/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py\", line 266, in main\n    list_target_groups(connection, module)\n  File \"/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py\", line 228, in list_target_groups\n    target_group.update(get_target_group_attributes(connection, module, target_group['TargetGroupArn']))\n  File \"/tmp/ansible_8qarb7pi/ansible_module_elb_target_group_facts.py\", line 187, in get_target_group_attributes\n    for k, v in target_group_attributes.items():\nRuntimeError: dictionary changed size during iteration\n", 
    "module_stdout": "", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}
```

The issue seems to be in this piece of code:
```python
for k, v in target_group_attributes.items():
    target_group_attributes[k.replace('.', '_')] = v
    del target_group_attributes[k]
```
Located in line 187 of `/lib/ansible/modules/cloud/amazon/elb_target_group_facts.py`.

I've tried commenting these 3 lines and it works as expected.

##### STEPS TO REPRODUCE
Simple playbook
```yaml
- hosts: localhost
  gather_facts: no
  tasks:
    - elb_target_group_facts:
        profile: "{{ aws_profile }}"
```
##### EXPECTED RESULTS
Expected to get facts about all my target groups.

##### ACTUAL RESULTS
Got exception as below:
```
ansible-playbook 2.5.0 (devel adc533804a) last updated 2017/09/12 14:51:23 (GMT -200)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/gustavo/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/gustavo/Documents/Tools/Ansible/source/ansible/lib/ansible
  executable location = /home/gustavo/Documents/Tools/Ansible/source/ansible/bin/ansible-playbook
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]
Using /etc/ansible/ansible.cfg as config file
setting up inventory plugins
Set default localhost to localhost
Parsed /etc/ansible/hosts inventory source with ini plugin
 [WARNING]: Found both group and host with same name: nexus

 [WARNING]: Found both group and host with same name: sonar

 [WARNING]: Found both group and host with same name: ci-server

 [WARNING]: Found both group and host with same name: rundeck

Loading callback plugin default of type stdout, v2.0 from /home/gustavo/Documents/Tools/Ansible/source/ansible/lib/ansible/plugins/callback/__init__.pyc

PLAYBOOK: test.yml ***********************************************************************************************************************************************************************************************************************************************************************************************************
clear: <built-in method clear of dict object at 0x7f4c96e49398>
copy: <built-in method copy of dict object at 0x7f4c96e49398>
fromkeys: <built-in method fromkeys of type object at 0x906f00>
get: <built-in method get of dict object at 0x7f4c96e49398>
has_key: <built-in method has_key of dict object at 0x7f4c96e49398>
items: <built-in method items of dict object at 0x7f4c96e49398>
iteritems: <built-in method iteritems of dict object at 0x7f4c96e49398>
iterkeys: <built-in method iterkeys of dict object at 0x7f4c96e49398>
itervalues: <built-in method itervalues of dict object at 0x7f4c96e49398>
keys: <built-in method keys of dict object at 0x7f4c96e49398>
pop: <built-in method pop of dict object at 0x7f4c96e49398>
popitem: <built-in method popitem of dict object at 0x7f4c96e49398>
setdefault: <built-in method setdefault of dict object at 0x7f4c96e49398>
update: <built-in method update of dict object at 0x7f4c96e49398>
values: <built-in method values of dict object at 0x7f4c96e49398>
viewitems: <built-in method viewitems of dict object at 0x7f4c96e49398>
viewkeys: <built-in method viewkeys of dict object at 0x7f4c96e49398>
viewvalues: <built-in method viewvalues of dict object at 0x7f4c96e49398>
1 plays in test.yml

PLAY [localhost] *************************************************************************************************************************************************************************************************************************************************************************************************************
META: ran handlers

TASK [elb_target_group_facts] ************************************************************************************************************************************************************************************************************************************************************************************************
task path: /home/gustavo/Documents/enkel/clientes/smiles/agile/playbooks/ecs/smiles-ansible-role-ecs-service/test.yml:4
Using module file /home/gustavo/Documents/Tools/Ansible/source/ansible/lib/ansible/modules/cloud/amazon/elb_target_group_facts.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: gustavo
<localhost> EXEC /bin/sh -c 'echo ~ && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/gustavo/.ansible/tmp/ansible-tmp-1505239382.8-235079325159918 `" && echo ansible-tmp-1505239382.8-235079325159918="` echo /home/gustavo/.ansible/tmp/ansible-tmp-1505239382.8-235079325159918 `" ) && sleep 0'
<localhost> PUT /tmp/tmpxQNS9D TO /home/gustavo/.ansible/tmp/ansible-tmp-1505239382.8-235079325159918/elb_target_group_facts.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/gustavo/.ansible/tmp/ansible-tmp-1505239382.8-235079325159918/ /home/gustavo/.ansible/tmp/ansible-tmp-1505239382.8-235079325159918/elb_target_group_facts.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python3 /home/gustavo/.ansible/tmp/ansible-tmp-1505239382.8-235079325159918/elb_target_group_facts.py; rm -rf "/home/gustavo/.ansible/tmp/ansible-tmp-1505239382.8-235079325159918/" > /dev/null 2>&1 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py", line 270, in <module>
    main()
  File "/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py", line 266, in main
    list_target_groups(connection, module)
  File "/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py", line 228, in list_target_groups
    target_group.update(get_target_group_attributes(connection, module, target_group['TargetGroupArn']))
  File "/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py", line 187, in get_target_group_attributes
    for k, v in target_group_attributes.items():
RuntimeError: dictionary changed size during iteration

fatal: [localhost]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py\", line 270, in <module>\n    main()\n  File \"/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py\", line 266, in main\n    list_target_groups(connection, module)\n  File \"/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py\", line 228, in list_target_groups\n    target_group.update(get_target_group_attributes(connection, module, target_group['TargetGroupArn']))\n  File \"/tmp/ansible_xlul11km/ansible_module_elb_target_group_facts.py\", line 187, in get_target_group_attributes\n    for k, v in target_group_attributes.items():\nRuntimeError: dictionary changed size during iteration\n", 
    "module_stdout": "", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}
        to retry, use: --limit @/home/gustavo/Documents/enkel/clientes/smiles/agile/playbooks/ecs/smiles-ansible-role-ecs-service/test.retry

PLAY RECAP *******************************************************************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1   

```



Discussion:
cc @willthames @wimnat
[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/elb_target_group_facts.py b/lib/ansible/modules/cloud/amazon/elb_target_group_facts.py
--- a/lib/ansible/modules/cloud/amazon/elb_target_group_facts.py
+++ b/lib/ansible/modules/cloud/amazon/elb_target_group_facts.py
@@ -184,11 +184,8 @@ def get_target_group_attributes(connection, module, target_group_arn):
         module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
 
     # Replace '.' with '_' in attribute key names to make it more Ansibley
-    for k, v in target_group_attributes.items():
-        target_group_attributes[k.replace('.', '_')] = v
-        del target_group_attributes[k]
-
-    return target_group_attributes
+    return dict((k.replace('.', '_'), v)
+                for (k, v) in target_group_attributes.items())
 
 
 def get_target_group_tags(connection, module, target_group_arn):


Test patch: