Skip to content

Commit

Permalink
Merge pull request ansible-collections#614 from tremble/stability/ec2…
Browse files Browse the repository at this point in the history
…_vpc_peer

Add NotFound retries when tagging a new VPC Peering connection

SUMMARY
Prior to botocore 1.17.24 it wasn't possible to tag the connection as a part of the creation call.  As such a separate create_tags call is performed after the creation.  However, this leads to a race condition when "I(wait=False)".
Rather than adding hard to test logic, add InvalidVpcPeeringConnectionID.NotFound retries to the tagging.
Also move from custom tag handling code over to the shared code in ansible_collections.amazon.aws.plugins.module_utils.ec2
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
ec2_vpc_peer
ADDITIONAL INFORMATION
TASK [ec2_vpc_peer : Create local account VPC peering Connection] **************
task path: /home/zuul/.ansible/collections/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_peer/tasks/main.yml:403
<testhost> ESTABLISH LOCAL CONNECTION FOR USER: zuul
<testhost> EXEC /bin/sh -c 'echo ~zuul && sleep 0'
<testhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/zuul/.ansible/tmp `"&& mkdir "` echo /home/zuul/.ansible/tmp/ansible-tmp-1624925621.1931164-8629-186765425497910 `" && echo ansible-tmp-1624925621.1931164-8629-186765425497910="` echo /home/zuul/.ansible/tmp/ansible-tmp-1624925621.1931164-8629-186765425497910 `" ) && sleep 0'
Using module file /home/zuul/.ansible/collections/ansible_collections/community/aws/plugins/modules/ec2_vpc_peer.py
<testhost> PUT /home/zuul/.ansible/tmp/ansible-local-8151h1f3kbcc/tmplyozom8u TO /home/zuul/.ansible/tmp/ansible-tmp-1624925621.1931164-8629-186765425497910/AnsiballZ_ec2_vpc_peer.py
<testhost> EXEC /bin/sh -c 'chmod u+x /home/zuul/.ansible/tmp/ansible-tmp-1624925621.1931164-8629-186765425497910/ /home/zuul/.ansible/tmp/ansible-tmp-1624925621.1931164-8629-186765425497910/AnsiballZ_ec2_vpc_peer.py && sleep 0'
<testhost> EXEC /bin/sh -c 'ANSIBLE_DEBUG_BOTOCORE_LOGS=True /home/zuul/venv/bin/python3.6 /home/zuul/.ansible/tmp/ansible-tmp-1624925621.1931164-8629-186765425497910/AnsiballZ_ec2_vpc_peer.py && sleep 0'
<testhost> EXEC /bin/sh -c 'rm -f -r /home/zuul/.ansible/tmp/ansible-tmp-1624925621.1931164-8629-186765425497910/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
  File "/tmp/ansible_ec2_vpc_peer_payload_bbdh2ojz/ansible_ec2_vpc_peer_payload.zip/ansible_collections/community/aws/plugins/modules/ec2_vpc_peer.py", line 559, in create_tags
  File "/tmp/ansible_ec2_vpc_peer_payload_bbdh2ojz/ansible_ec2_vpc_peer_payload.zip/ansible_collections/amazon/aws/plugins/module_utils/core.py", line 288, in deciding_wrapper
    return retrying_wrapper(*args, **kwargs)
  File "/tmp/ansible_ec2_vpc_peer_payload_bbdh2ojz/ansible_ec2_vpc_peer_payload.zip/ansible_collections/amazon/aws/plugins/module_utils/cloud.py", line 154, in retry_func
    raise e
  File "/tmp/ansible_ec2_vpc_peer_payload_bbdh2ojz/ansible_ec2_vpc_peer_payload.zip/ansible_collections/amazon/aws/plugins/module_utils/cloud.py", line 144, in retry_func
    return f(*args, **kwargs)
  File "/home/zuul/venv/lib/python3.6/site-packages/botocore/client.py", line 386, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/home/zuul/venv/lib/python3.6/site-packages/botocore/client.py", line 705, in _make_api_call
    raise error_class(parsed_response, operation_name)
fatal: [testhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "aws_access_key": "ASIA6CCDWXDOPPPI445H",
            "aws_ca_bundle": null,
            "aws_config": null,
            "aws_secret_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "debug_botocore_endpoint_logs": true,
            "ec2_url": null,
            "peer_owner_id": null,
            "peer_region": null,
            "peer_vpc_id": "vpc-0deec00ddeb3584bf",
            "peering_id": null,
            "profile": null,
            "region": "us-east-1",
            "security_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "state": "present",
            "tags": {
                "Name": "Peering connection for VPC vpc-018bc7cc64b0731f9 to VPC vpc-0deec00ddeb3584bf"
            },
            "validate_certs": true,
            "vpc_id": "vpc-018bc7cc64b0731f9",
            "wait": false
        }
    },
    "msg": "An error occurred (InvalidVpcPeeringConnectionID.NotFound) when calling the CreateTags operation: The vpcPeeringConnection ID 'pcx-06ed26ea8993aba5b' does not exist",
    "resource_actions": [
        "ec2:DeleteTags",
        "ec2:CreateTags",
        "ec2:CreateVpcPeeringConnection",
        "ec2:DescribeVpcPeeringConnections"
    ]
}

Reviewed-by: Alina Buzachis <None>
  • Loading branch information
ansible-zuul[bot] authored Jun 29, 2021
2 parents 6870398 + 85e99d3 commit 6fcbe0f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 48 deletions.
4 changes: 4 additions & 0 deletions changelogs/fragments/614-ec2_vpc_peer-tagging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
bugfixes:
- ec2_vpc_peer - automatically retry when attempting to tag freshly created peering connections (https://github.com/ansible-collections/community.aws/pull/614).
minor_changes:
- ec2_vpc_peer - use shared code for tagging peering connections (https://github.com/ansible-collections/community.aws/pull/614).
73 changes: 25 additions & 48 deletions plugins/modules/ec2_vpc_peer.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
- Dictionary of tags to look for and apply when creating a Peering Connection.
required: false
type: dict
purge_tags:
description:
- Remove tags not listed in I(tags).
type: bool
default: true
version_added: 2.0.0
state:
description:
- Create, delete, accept, reject a peering connection.
Expand Down Expand Up @@ -367,6 +373,8 @@
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import add_ec2_tags
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags


def wait_for_state(client, module, state, pcx_id):
Expand All @@ -385,26 +393,6 @@ def wait_for_state(client, module, state, pcx_id):
module.fail_json_aws(e, "Enable to describe Peerig Connection while waiting for state to change")


def tags_changed(pcx_id, client, module):
changed = False
tags = dict()
if module.params.get('tags'):
tags = module.params.get('tags')
peering_connection = get_peering_connection_by_id(pcx_id, client, module)
if peering_connection['Tags']:
pcx_values = [t.values() for t in peering_connection['Tags']]
pcx_tags = [item for sublist in pcx_values for item in sublist]
tag_values = [[key, str(value)] for key, value in tags.items()]
tags = [item for sublist in tag_values for item in sublist]
if sorted(pcx_tags) == sorted(tags):
changed = False
elif tags:
delete_tags(pcx_id, client, module)
create_tags(pcx_id, client, module)
changed = True
return changed


def describe_peering_connections(params, client):
peer_filter = {
'requester-vpc-info.vpc-id': params['VpcId'],
Expand Down Expand Up @@ -445,7 +433,10 @@ def create_peer_connection(client, module):
peering_conns = describe_peering_connections(params, client)
for peering_conn in peering_conns['VpcPeeringConnections']:
pcx_id = peering_conn['VpcPeeringConnectionId']
if tags_changed(pcx_id, client, module):
if ensure_ec2_tags(client, module, pcx_id,
purge_tags=module.params.get('purge_tags'),
tags=module.params.get('tags'),
):
changed = True
if is_active(peering_conn):
return (changed, peering_conn)
Expand All @@ -454,10 +445,14 @@ def create_peer_connection(client, module):
try:
peering_conn = client.create_vpc_peering_connection(aws_retry=True, **params)
pcx_id = peering_conn['VpcPeeringConnection']['VpcPeeringConnectionId']
if module.params.get('tags'):
# Once the minimum botocore version is bumped to > 1.17.24
# (hopefully community.aws 3.0.0) we can add the tags to the
# creation parameters
add_ec2_tags(client, module, pcx_id, module.params.get('tags'),
retry_codes=['InvalidVpcPeeringConnectionID.NotFound'])
if module.params.get('wait'):
wait_for_state(client, module, 'pending-acceptance', pcx_id)
if module.params.get('tags'):
create_tags(pcx_id, client, module)
changed = True
return (changed, peering_conn['VpcPeeringConnection'])
except botocore.exceptions.ClientError as e:
Expand Down Expand Up @@ -531,43 +526,24 @@ def accept_reject(state, client, module):
client.reject_vpc_peering_connection(aws_retry=True, **params)
target_state = 'rejected'
if module.params.get('tags'):
create_tags(peering_id, client, module)
add_ec2_tags(client, module, peering_id, module.params.get('tags'),
retry_codes=['InvalidVpcPeeringConnectionID.NotFound'])
changed = True
if module.params.get('wait'):
wait_for_state(client, module, target_state, peering_id)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
if tags_changed(peering_id, client, module):
if ensure_ec2_tags(client, module, peering_id,
purge_tags=module.params.get('purge_tags'),
tags=module.params.get('tags'),
):
changed = True

# Relaod peering conection infos to return latest state/params
vpc_peering_connection = get_peering_connection_by_id(peering_id, client, module)
return (changed, vpc_peering_connection)


def load_tags(module):
tags = []
if module.params.get('tags'):
for name, value in module.params.get('tags').items():
tags.append({'Key': name, 'Value': str(value)})
return tags


def create_tags(pcx_id, client, module):
try:
delete_tags(pcx_id, client, module)
client.create_tags(aws_retry=True, Resources=[pcx_id], Tags=load_tags(module))
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))


def delete_tags(pcx_id, client, module):
try:
client.delete_tags(aws_retry=True, Resources=[pcx_id])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))


def main():
argument_spec = dict(
vpc_id=dict(),
Expand All @@ -576,6 +552,7 @@ def main():
peering_id=dict(),
peer_owner_id=dict(),
tags=dict(required=False, type='dict'),
purge_tags=dict(default=True, type='bool'),
state=dict(default='present', choices=['present', 'absent', 'accept', 'reject']),
wait=dict(default=False, type='bool'),
)
Expand Down

0 comments on commit 6fcbe0f

Please sign in to comment.