Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ec2_instance module broken in Python 3.8 - dict keys modified during iteration #709

Closed
1 task done
Razique opened this issue Mar 14, 2022 · 6 comments · Fixed by #767
Closed
1 task done

ec2_instance module broken in Python 3.8 - dict keys modified during iteration #709

Razique opened this issue Mar 14, 2022 · 6 comments · Fixed by #767
Labels
bug This issue/PR relates to a bug has_pr module module p1 plugins plugin (any type) python3 traceback waiting_on_contributor Needs help. Feel free to engage to get things unblocked

Comments

@Razique
Copy link
Contributor

Razique commented Mar 14, 2022

Summary

The ec2_instance AWS module doesn't work in Python 3.8. This is due to the fact that the find_instances method pops keys from the filters dictionary while it is being iterated:

An exception occurred during task execution. To see the full traceback, use -vvv. The error was: RuntimeError: dictionary keys changed during iteration
fatal: [rmahroua-test-routing-AzB]: FAILED! => {"changed": false, "module_stderr": "Traceback (most recent call last):\n 
 File \"/home/rmahroua/.ansible/tmp/ansible-tmp-1647283103.3464394-212411615216081/AnsiballZ_ec2_instance.py\", 
line 102, in <module>\n    _ansiballz_main()\n  File \"/home/rmahroua/.ansible/tmp/ansible-
tmp-1647283103.3464394-212411615216081/AnsiballZ_ec2_instance.py\", line 94, in _ansiballz_main\n    
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/rmahroua/.ansible/tmp/ansible-
tmp-1647283103.3464394-212411615216081/AnsiballZ_ec2_instance.py\", line 40, in invoke_module\n    
runpy.run_module(mod_name='ansible.modules.cloud.amazon.ec2_instance', init_globals=None, run_name='__main__', 
alter_sys=True)\n  File \"/usr/lib64/python3.8/runpy.py\", line 207, in run_module\n    return _run_module_code(code, 
init_globals, run_name, mod_spec)\n  File \"/usr/lib64/python3.8/runpy.py\", line 97, in _run_module_code\n    
_run_code(code, mod_globals, init_globals,\n  File \"/usr/lib64/python3.8/runpy.py\", line 87, in _run_code\n    exec(code, 
run_globals)\n  File \"/tmp/ansible_ec2_instance_payload_j_rhever/ansible_ec2_instance_payload.zip/ansible/modules
/cloud/amazon/ec2_instance.py\", line 1710, in <module>\n  File \"/tmp/ansible_ec2_instance_payload_j_rhever
/ansible_ec2_instance_payload.zip/ansible/modules/cloud/amazon/ec2_instance.py\", line 1681, in main\n  File \"/tmp
/ansible_ec2_instance_payload_j_rhever/ansible_ec2_instance_payload.zip/ansible/modules/cloud/amazon
/ec2_instance.py\", line 1297, 
in find_instances
RuntimeError: dictionary keys changed during iteration", 
"module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

The fix consists in adding the sanitized keys to a new dictionary and passing it to the paginator instead of modifying the existing one as follows:

def find_instances(ec2, ids=None, filters=None):
    paginator = ec2.get_paginator('describe_instances')
    if ids:
        return list(paginator.paginate(
            InstanceIds=ids,
        ).search('Reservations[].Instances[]'))
    elif filters is None:
        module.fail_json(msg="No filters provided when they were required")
    elif filters is not None:
        sanitized_filters = dict()
        for key in filters.keys():
            if not key.startswith("tag:"):
                sanitized_filters[key.replace("_", "-")] = filters[key]
        return list(paginator.paginate(
            Filters=ansible_dict_to_boto3_filter_list(sanitized_filters)
        ).search('Reservations[].Instances[]'))
    return []

Issue Type

Bug Report

Component Name

ec2_instance

Ansible Version

ansible 2.9.2
  config file = /mnt/ansicloud/ansicloud-full/playbooks/aws/ansible.cfg
  configured module search path = ['/home/rmahroua/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/rmahroua/.local/lib/python3.8/site-packages/ansible
  executable location = /home/rmahroua/.local/bin/ansible
  python version = 3.8.10 (default, May  4 2021, 00:00:00) [GCC 10.2.1 20201125 (Red Hat 10.2.1-9)]

Collection Versions

$ ansible-galaxy collection list

AWS SDK versions

Name: boto
Version: 2.49.0
Summary: Amazon Web Services Library
Home-page: https://github.com/boto/boto/
Author: Mitch Garnaat
Author-email: [email protected]
License: MIT
Location: /home/rmahroua/.local/lib/python3.8/site-packages
Requires:
Required-by: aws-automation
---
Name: boto3
Version: 1.21.11
Summary: The AWS SDK for Python
Home-page: https://github.com/boto/boto3
Author: Amazon Web Services
Author-email:
License: Apache License 2.0
Location: /usr/local/lib/python3.8/site-packages
Requires: botocore, jmespath, s3transfer
Required-by: aws-automation, aws-shell
---
Name: botocore
Version: 1.24.11
Summary: Low-level, data-driven core of boto 3.
Home-page: https://github.com/boto/botocore
Author: Amazon Web Services
Author-email:
License: Apache License 2.0
Location: /usr/local/lib/python3.8/site-packages
Requires: jmespath, python-dateutil, urllib3
Required-by: aws-automation, awscli, boto3, s3transfer

Configuration

ANSIBLE_PIPELINING(/mnt/ansicloud/ansicloud-full/playbooks/aws/ansible.cfg) = False
ANSIBLE_SSH_ARGS(/mnt/ansicloud/ansicloud-full/playbooks/aws/ansible.cfg) = -o ControlMaster=auto -o ControlPersist=120s -o PreferredAuthentications=publickey
DEFAULT_CALLBACK_WHITELIST(/mnt/ansicloud/ansicloud-full/playbooks/aws/ansible.cfg) = ['json', 'timer']
DEFAULT_ROLES_PATH(/mnt/ansicloud/ansicloud-full/playbooks/aws/ansible.cfg) = ['/mnt/ansicloud/ansicloud-full/playbooks/aws/roles']

OS / Environment

Fedora 33

Steps to Reproduce

- ec2:
    key_name: mykey
    instance_type: t2.micro
    image: ami-123456
    wait: yes
    group: webserver
    count: 3
    vpc_subnet_id: subnet-29e63245
    assign_public_ip: yes

Expected Results

EC2 instances should provision instead of the module failing with an error of RuntimeError: dictionary keys changed during iteration"

Actual Results

An exception occurred during task execution. To see the full traceback, use -vvv. The error was: RuntimeError: dictionary keys changed during iteration
fatal: [rmahroua-test-routing-AzB]: FAILED! => {"changed": false, "module_stderr": "Traceback (most recent call last):\n 
 File \"/home/rmahroua/.ansible/tmp/ansible-tmp-1647283103.3464394-212411615216081/AnsiballZ_ec2_instance.py\", 
line 102, in <module>\n    _ansiballz_main()\n  File \"/home/rmahroua/.ansible/tmp/ansible-
tmp-1647283103.3464394-212411615216081/AnsiballZ_ec2_instance.py\", line 94, in _ansiballz_main\n    
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/rmahroua/.ansible/tmp/ansible-
tmp-1647283103.3464394-212411615216081/AnsiballZ_ec2_instance.py\", line 40, in invoke_module\n    
runpy.run_module(mod_name='ansible.modules.cloud.amazon.ec2_instance', init_globals=None, run_name='__main__', 
alter_sys=True)\n  File \"/usr/lib64/python3.8/runpy.py\", line 207, in run_module\n    return _run_module_code(code, 
init_globals, run_name, mod_spec)\n  File \"/usr/lib64/python3.8/runpy.py\", line 97, in _run_module_code\n    
_run_code(code, mod_globals, init_globals,\n  File \"/usr/lib64/python3.8/runpy.py\", line 87, in _run_code\n    exec(code, 
run_globals)\n  File \"/tmp/ansible_ec2_instance_payload_j_rhever/ansible_ec2_instance_payload.zip/ansible/modules
/cloud/amazon/ec2_instance.py\", line 1710, in <module>\n  File \"/tmp/ansible_ec2_instance_payload_j_rhever
/ansible_ec2_instance_payload.zip/ansible/modules/cloud/amazon/ec2_instance.py\", line 1681, in main\n  File \"/tmp
/ansible_ec2_instance_payload_j_rhever/ansible_ec2_instance_payload.zip/ansible/modules/cloud/amazon
/ec2_instance.py\", line 1297, 
in find_instances
RuntimeError: dictionary keys changed during iteration", 
"module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

Code of Conduct

  • I agree to follow the Ansible Code of Conduct
@ansibullbot
Copy link

Files identified in the description:

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

@ansibullbot
Copy link

@ansibullbot ansibullbot added bug This issue/PR relates to a bug module module needs_triage plugins plugin (any type) python3 traceback labels Mar 14, 2022
@alinabuzachis
Copy link
Collaborator

@Razique Thank you for raising this. Would you be willing to open a pull request with the patch?

@alinabuzachis alinabuzachis added waiting_on_contributor Needs help. Feel free to engage to get things unblocked p1 and removed needs_triage labels Mar 15, 2022
@Razique
Copy link
Contributor Author

Razique commented Mar 15, 2022

Yup! I can work on this. I'll have to see whether contribution guide differs between AWS community collections and "core".

@alinabuzachis
Copy link
Collaborator

@Razique Awesome! Let me know if you need any help. If you want, you can also reach out to us on IRC #ansible-aws.

What you need is a changelog fragment https://docs.ansible.com/ansible/latest/community/development_process.html#id11 and also an integration test for this change.

@Razique
Copy link
Contributor Author

Razique commented Apr 2, 2022

@alinabuzachis I pushed the PR and created a fragment as required. Let me know if I forgot something!

softwarefactory-project-zuul bot pushed a commit that referenced this issue May 3, 2022
… 3.8 (#767)

Update ec2_instance find_instances to fix incompatibility with Python 3.8

SUMMARY

Update ec2_instance find_instances to use temporary dict. instead of inline changes. Fixes #709

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

ec2_instance
ADDITIONAL INFORMATION
Current ec2_module iterates over a filters dictionary to perform hyphen to underscore substitution while popping keys in the process. This is not compatible with Python 3.8. I have simply created a second dictionary, I can also create a shallow copy via the copy() module if the team prefers.

Reviewed-by: Bikouo Aubin <None>
Reviewed-by: Alina Buzachis <None>
Reviewed-by: Mark Chappell <None>
patchback bot pushed a commit that referenced this issue May 3, 2022
… 3.8 (#767)

Update ec2_instance find_instances to fix incompatibility with Python 3.8

SUMMARY

Update ec2_instance find_instances to use temporary dict. instead of inline changes. Fixes #709

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

ec2_instance
ADDITIONAL INFORMATION
Current ec2_module iterates over a filters dictionary to perform hyphen to underscore substitution while popping keys in the process. This is not compatible with Python 3.8. I have simply created a second dictionary, I can also create a shallow copy via the copy() module if the team prefers.

Reviewed-by: Bikouo Aubin <None>
Reviewed-by: Alina Buzachis <None>
Reviewed-by: Mark Chappell <None>
(cherry picked from commit 0ca065c)
patchback bot pushed a commit that referenced this issue May 3, 2022
… 3.8 (#767)

Update ec2_instance find_instances to fix incompatibility with Python 3.8

SUMMARY

Update ec2_instance find_instances to use temporary dict. instead of inline changes. Fixes #709

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

ec2_instance
ADDITIONAL INFORMATION
Current ec2_module iterates over a filters dictionary to perform hyphen to underscore substitution while popping keys in the process. This is not compatible with Python 3.8. I have simply created a second dictionary, I can also create a shallow copy via the copy() module if the team prefers.

Reviewed-by: Bikouo Aubin <None>
Reviewed-by: Alina Buzachis <None>
Reviewed-by: Mark Chappell <None>
(cherry picked from commit 0ca065c)
softwarefactory-project-zuul bot pushed a commit that referenced this issue May 3, 2022
… 3.8 (#767) (#800)

[PR #767/0ca065cf backport][stable-2] Update ec2_instance find_instances to fix incompatibility with Python 3.8

This is a backport of PR #767 as merged into main (0ca065c).
SUMMARY

Update ec2_instance find_instances to use temporary dict. instead of inline changes. Fixes #709

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

ec2_instance
ADDITIONAL INFORMATION
Current ec2_module iterates over a filters dictionary to perform hyphen to underscore substitution while popping keys in the process. This is not compatible with Python 3.8. I have simply created a second dictionary, I can also create a shallow copy via the copy() module if the team prefers.

Reviewed-by: Alina Buzachis <None>
Reviewed-by: Jill R <None>
softwarefactory-project-zuul bot pushed a commit that referenced this issue May 19, 2022
… 3.8 (#767) (#801)

[PR #767/0ca065cf backport][stable-3] Update ec2_instance find_instances to fix incompatibility with Python 3.8

This is a backport of PR #767 as merged into main (0ca065c).
SUMMARY

Update ec2_instance find_instances to use temporary dict. instead of inline changes. Fixes #709

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

ec2_instance
ADDITIONAL INFORMATION
Current ec2_module iterates over a filters dictionary to perform hyphen to underscore substitution while popping keys in the process. This is not compatible with Python 3.8. I have simply created a second dictionary, I can also create a shallow copy via the copy() module if the team prefers.

Reviewed-by: Alina Buzachis <None>
Reviewed-by: Mark Chappell <None>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue/PR relates to a bug has_pr module module p1 plugins plugin (any type) python3 traceback waiting_on_contributor Needs help. Feel free to engage to get things unblocked
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants