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

Return all infos of a VPC peering connection in ec2_vpc_peer module #355

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/355-ec2_vpc_peer_improvements.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ec2_vpc_peer - More return info added, also simplified module code a bit and extended tests (https://github.com/ansible-collections/community.aws/pull/355)
94 changes: 58 additions & 36 deletions plugins/modules/ec2_vpc_peer.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,27 @@

'''
RETURN = '''
task:
description: The result of the create, accept, reject or delete action.
peering_id:
description: The id of the VPC peering connection created/deleted.
returned: always
type: str
sample: pcx-034223d7c0aec3cde
vpc_peering_connection:
description: The details of the VPC peering connection as returned by Boto3 (snake cased).
returned: success
type: dict
type: complex
contains:
vpc_peering_connection_id:
type: str
sample: pcx-034223d7c0aec3cde
accepter_vpc_info:
type: dict
requester_vpc_info:
type: dict
tags:
type: dict
status:
type: dict
stefanhorning marked this conversation as resolved.
Show resolved Hide resolved
'''

try:
Expand All @@ -231,6 +248,8 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
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


def wait_for_state(client, module, state, pcx_id):
Expand All @@ -254,9 +273,9 @@ def tags_changed(pcx_id, client, module):
tags = dict()
if module.params.get('tags'):
tags = module.params.get('tags')
pcx = find_pcx_by_id(pcx_id, client, module)
if pcx['VpcPeeringConnections']:
pcx_values = [t.values() for t in pcx['VpcPeeringConnections'][0]['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]
Expand All @@ -283,6 +302,7 @@ def describe_peering_connections(params, client):
aws_retry=True,
Filters=ansible_dict_to_boto3_filter_list(peer_filter),
)

return result


Expand Down Expand Up @@ -311,9 +331,9 @@ def create_peer_connection(client, module):
if tags_changed(pcx_id, client, module):
changed = True
if is_active(peering_conn):
return (changed, peering_conn['VpcPeeringConnectionId'])
return (changed, peering_conn)
if is_pending(peering_conn):
return (changed, peering_conn['VpcPeeringConnectionId'])
return (changed, peering_conn)
try:
peering_conn = client.create_vpc_peering_connection(aws_retry=True, **params)
pcx_id = peering_conn['VpcPeeringConnection']['VpcPeeringConnectionId']
Expand All @@ -322,32 +342,32 @@ def create_peer_connection(client, module):
if module.params.get('tags'):
create_tags(pcx_id, client, module)
changed = True
return (changed, peering_conn['VpcPeeringConnection']['VpcPeeringConnectionId'])
return (changed, peering_conn['VpcPeeringConnection'])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))


def remove_peer_connection(client, module):
pcx_id = module.params.get('peering_id')
if pcx_id:
peering_conns = client.describe_vpc_peering_connections(aws_retry=True, VpcPeeringConnectionIds=[pcx_id])
peering_conn = get_peering_connection_by_id(pcx_id, client, module)
else:
params = dict()
params['VpcId'] = module.params.get('vpc_id')
params['PeerVpcId'] = module.params.get('peer_vpc_id')
params['PeerRegion'] = module.params.get('peer_region')
if module.params.get('peer_owner_id'):
params['PeerOwnerId'] = str(module.params.get('peer_owner_id'))
peering_conns = describe_peering_connections(params, client)
peering_conn = describe_peering_connections(params, client)['VpcPeeringConnections'][0]

if not peering_conns:
if not peering_conn:
module.exit_json(changed=False)
else:
pcx_id = pcx_id or peering_conns['VpcPeeringConnections'][0]['VpcPeeringConnectionId']
pcx_id = pcx_id or peering_conn['VpcPeeringConnectionId']

if peering_conns['VpcPeeringConnections'][0]['Status']['Code'] == 'deleted':
if peering_conn['Status']['Code'] == 'deleted':
module.exit_json(msg='Connection in deleted state.', changed=False)
if peering_conns['VpcPeeringConnections'][0]['Status']['Code'] == 'rejected':
if peering_conn['Status']['Code'] == 'rejected':
module.exit_json(msg='Connection has been rejected. State cannot be changed and will be removed automatically by AWS', changed=False)

try:
Expand All @@ -356,17 +376,17 @@ def remove_peer_connection(client, module):
client.delete_vpc_peering_connection(aws_retry=True, **params)
if module.params.get('wait'):
wait_for_state(client, module, 'deleted', pcx_id)
module.exit_json(changed=True)
module.exit_json(changed=True, peering_id=pcx_id)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))


def peer_status(client, module):
def get_peering_connection_by_id(peering_id, client, module):
params = dict()
params['VpcPeeringConnectionIds'] = [module.params.get('peering_id')]
params['VpcPeeringConnectionIds'] = [peering_id]
try:
vpc_peering_connection = client.describe_vpc_peering_connections(aws_retry=True, **params)
return vpc_peering_connection['VpcPeeringConnections'][0]['Status']['Code']
return vpc_peering_connection['VpcPeeringConnections'][0]
except is_boto3_error_code('InvalidVpcPeeringConnectionId.Malformed') as e:
module.fail_json_aws(e, msg='Malformed connection ID')
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
Expand All @@ -376,10 +396,12 @@ def peer_status(client, module):
def accept_reject(state, client, module):
changed = False
params = dict()
pcx_id = module.params.get('peering_id')
params['VpcPeeringConnectionId'] = pcx_id
current_state = peer_status(client, module)
if current_state not in ['active', 'rejected']:
peering_id = module.params.get('peering_id')
params['VpcPeeringConnectionId'] = peering_id
vpc_peering_connection = get_peering_connection_by_id(peering_id, client, module)
peering_status = vpc_peering_connection['Status']['Code']

if peering_status not in ['active', 'rejected']:
try:
if state == 'accept':
client.accept_vpc_peering_connection(aws_retry=True, **params)
Expand All @@ -388,15 +410,18 @@ 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(params['VpcPeeringConnectionId'], client, module)
create_tags(peering_id, client, module)
changed = True
if module.params.get('wait'):
wait_for_state(client, module, target_state, pcx_id)
wait_for_state(client, module, target_state, peering_id)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
if tags_changed(params['VpcPeeringConnectionId'], client, module):
if tags_changed(peering_id, client, module):
changed = True
return changed, params['VpcPeeringConnectionId']

# 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)
tremble marked this conversation as resolved.
Show resolved Hide resolved


def load_tags(module):
Expand All @@ -422,13 +447,6 @@ def delete_tags(pcx_id, client, module):
module.fail_json(msg=str(e))


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


def main():
argument_spec = dict(
vpc_id=dict(),
Expand Down Expand Up @@ -460,15 +478,19 @@ def main():

if state == 'present':
(changed, results) = create_peer_connection(client, module)
module.exit_json(changed=changed, peering_id=results)
elif state == 'absent':
if not peering_id and (not vpc_id or not peer_vpc_id):
module.fail_json(msg='state is absent but one of the following is missing: peering_id or [vpc_id, peer_vpc_id]')

remove_peer_connection(client, module)
else:
(changed, results) = accept_reject(state, client, module)
module.exit_json(changed=changed, peering_id=results)

formatted_results = camel_dict_to_snake_dict(results)
stefanhorning marked this conversation as resolved.
Show resolved Hide resolved
# Turn the resource tags from boto3 into an ansible friendly tag dictionary
formatted_results['tags'] = boto3_tag_list_to_ansible_dict(formatted_results.get('tags', []))

module.exit_json(changed=changed, vpc_peering_connection=formatted_results, peering_id=results['VpcPeeringConnectionId'])


if __name__ == '__main__':
Expand Down
25 changes: 22 additions & 3 deletions tests/integration/targets/ec2_vpc_peer/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,41 +65,60 @@
set_fact:
connection_name: 'Peering connection for VPC {{ vpc_1 }} to VPC {{ vpc_2 }}'

- name: Create local account VPC peering Connection
- name: Create local account VPC peering Connection request
ec2_vpc_peer:
vpc_id: '{{ vpc_1 }}'
peer_vpc_id: '{{ vpc_2 }}'
state: present
tags:
Name: 'Peering connection for VPC {{ vpc_1 }} to VPC {{ vpc_2 }}'
Name: '{{ connection_name }}'
register: vpc_peer

- name: Assert success
assert:
that:
- vpc_peer is changed
- vpc_peer is successful
- "'peering_id' in vpc_peer"
- vpc_peer.vpc_peering_connection.requester_vpc_info.cidr_block == vpc_1_cidr
- vpc_peer.peering_id.startswith('pcx-')

- name: Store Connection ID
set_fact:
peer_id_1: '{{ vpc_peer.peering_id }}'

- name: (re-) Create local account VPC peering Connection (idempotency)
- name: (re-) Create local account VPC peering Connection request (idempotency)
ec2_vpc_peer:
vpc_id: '{{ vpc_1 }}'
peer_vpc_id: '{{ vpc_2 }}'
state: present
tags:
Name: '{{ connection_name }}'
register: vpc_peer

- name: Assert success
assert:
that:
- vpc_peer is not changed
- vpc_peer is successful
- vpc_peer.peering_id == peer_id_1

- name: Accespt local VPC peering connection from destination VPC
tremble marked this conversation as resolved.
Show resolved Hide resolved
ec2_vpc_peer:
peering_id: '{{ vpc_peer.peering_id }}'
state: accept
tags:
Name: '{{ connection_name }}'
register: vpc_peer_accept

- name: Assert success
assert:
tath:
- vpc_peer_accept is successful
- vpc_peer_accept is changed
- vpc_peer_accept.peering_id == vpc_peer.peering_id
- vpc_peer_accept.vpc_peering_connection.accepter_vpc_info.cidr_block == vpc_2_cidr

- name: Get details on specific VPC peer
ec2_vpc_peering_info:
peer_connection_ids:
Expand Down