From 6b84c403688ca2ede0cdbe7dab558077b3e1a42e Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Wed, 26 Apr 2023 19:26:07 +0200 Subject: [PATCH] Big Black PR (#1784) * Black prep * Black * changelog * Fix pylint unused-import in tests * Split SSM connection plugin changes * disable glue tests - bucket's missing * Disable s3_logging and s3_sync tests This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/2c4575c248776c65d66b06cd60fa09b0dae1cd6f --- plugins/module_utils/transitgateway.py | 169 ++++++++++-------- .../ec2_transit_gateway_vpc_attachment.py | 98 +++++----- ...ec2_transit_gateway_vpc_attachment_info.py | 40 +++-- 3 files changed, 174 insertions(+), 133 deletions(-) diff --git a/plugins/module_utils/transitgateway.py b/plugins/module_utils/transitgateway.py index fff2ce63ffe..5f0e934d1f2 100644 --- a/plugins/module_utils/transitgateway.py +++ b/plugins/module_utils/transitgateway.py @@ -21,21 +21,43 @@ def _waiter_model_data(self): # split the TGW waiters so we can keep them close to everything else. tgw_data = dict( tgw_attachment_available=dict( - operation='DescribeTransitGatewayAttachments', - delay=5, maxAttempts=120, + operation="DescribeTransitGatewayAttachments", + delay=5, + maxAttempts=120, acceptors=[ - dict(state='success', matcher='pathAll', expected='available', argument='TransitGatewayAttachments[].State'), - ] + dict( + state="success", + matcher="pathAll", + expected="available", + argument="TransitGatewayAttachments[].State", + ), + ], ), tgw_attachment_deleted=dict( - operation='DescribeTransitGatewayAttachments', - delay=5, maxAttempts=120, + operation="DescribeTransitGatewayAttachments", + delay=5, + maxAttempts=120, acceptors=[ - dict(state='retry', matcher='pathAll', expected='deleting', argument='TransitGatewayAttachments[].State'), - dict(state='success', matcher='pathAll', expected='deleted', argument='TransitGatewayAttachments[].State'), - dict(state='success', matcher='path', expected=True, argument='length(TransitGatewayAttachments[]) == `0`'), - dict(state='success', matcher='error', expected='InvalidRouteTableID.NotFound'), - ] + dict( + state="retry", + matcher="pathAll", + expected="deleting", + argument="TransitGatewayAttachments[].State", + ), + dict( + state="success", + matcher="pathAll", + expected="deleted", + argument="TransitGatewayAttachments[].State", + ), + dict( + state="success", + matcher="path", + expected=True, + argument="length(TransitGatewayAttachments[]) == `0`", + ), + dict(state="success", matcher="error", expected="InvalidRouteTableID.NotFound"), + ], ), ) data.update(tgw_data) @@ -51,40 +73,40 @@ def __init__(self, module, **kwargs): # retry - retries the full fetch, but better than simply giving up. @AWSRetry.jittered_backoff() def _paginated_describe_transit_gateway_vpc_attachments(self, **params): - paginator = self.client.get_paginator('describe_transit_gateway_vpc_attachments') + paginator = self.client.get_paginator("describe_transit_gateway_vpc_attachments") return paginator.paginate(**params).build_full_result() - @Boto3Mixin.aws_error_handler('describe transit gateway attachments') + @Boto3Mixin.aws_error_handler("describe transit gateway attachments") def _describe_vpc_attachments(self, **params): result = self._paginated_describe_transit_gateway_vpc_attachments(**params) - return result.get('TransitGatewayVpcAttachments', None) + return result.get("TransitGatewayVpcAttachments", None) - @Boto3Mixin.aws_error_handler('create transit gateway attachment') + @Boto3Mixin.aws_error_handler("create transit gateway attachment") def _create_vpc_attachment(self, **params): result = self.client.create_transit_gateway_vpc_attachment(aws_retry=True, **params) - return result.get('TransitGatewayVpcAttachment', None) + return result.get("TransitGatewayVpcAttachment", None) - @Boto3Mixin.aws_error_handler('modify transit gateway attachment') + @Boto3Mixin.aws_error_handler("modify transit gateway attachment") def _modify_vpc_attachment(self, **params): result = self.client.modify_transit_gateway_vpc_attachment(aws_retry=True, **params) - return result.get('TransitGatewayVpcAttachment', None) + return result.get("TransitGatewayVpcAttachment", None) - @Boto3Mixin.aws_error_handler('delete transit gateway attachment') + @Boto3Mixin.aws_error_handler("delete transit gateway attachment") def _delete_vpc_attachment(self, **params): try: result = self.client.delete_transit_gateway_vpc_attachment(aws_retry=True, **params) - except is_boto3_error_code('ResourceNotFoundException'): + except is_boto3_error_code("ResourceNotFoundException"): return None - return result.get('TransitGatewayVpcAttachment', None) + return result.get("TransitGatewayVpcAttachment", None) - @Boto3Mixin.aws_error_handler('transit gateway attachment to finish deleting') + @Boto3Mixin.aws_error_handler("transit gateway attachment to finish deleting") def _wait_tgw_attachment_deleted(self, **params): - waiter = self.tgw_waiter_factory.get_waiter('tgw_attachment_deleted') + waiter = self.tgw_waiter_factory.get_waiter("tgw_attachment_deleted") waiter.wait(**params) - @Boto3Mixin.aws_error_handler('transit gateway attachment to become available') + @Boto3Mixin.aws_error_handler("transit gateway attachment to become available") def _wait_tgw_attachment_available(self, **params): - waiter = self.tgw_waiter_factory.get_waiter('tgw_attachment_available') + waiter = self.tgw_waiter_factory.get_waiter("tgw_attachment_available") waiter.wait(**params) def _normalize_tgw_attachment(self, rtb): @@ -103,11 +125,10 @@ def _get_tgw_vpc_attachment(self, **params): class BaseTGWManager(BaseEc2Manager): - - @Boto3Mixin.aws_error_handler('connect to AWS') - def _create_client(self, client_name='ec2'): - if client_name == 'ec2': - error_codes = ['IncorrectState'] + @Boto3Mixin.aws_error_handler("connect to AWS") + def _create_client(self, client_name="ec2"): + if client_name == "ec2": + error_codes = ["IncorrectState"] else: error_codes = [] @@ -119,8 +140,7 @@ def _create_client(self, client_name='ec2'): class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager): - - TAG_RESOURCE_TYPE = 'transit-gateway-attachment' + TAG_RESOURCE_TYPE = "transit-gateway-attachment" def __init__(self, module, id=None): self._subnet_updates = dict() @@ -131,7 +151,7 @@ def _get_id_params(self, id=None, id_list=False): id = self.resource_id if not id: # Users should never see this, but let's cover ourself - self.module.fail_json(msg='Attachment identifier parameter missing') + self.module.fail_json(msg="Attachment identifier parameter missing") if id_list: return dict(TransitGatewayAttachmentIds=[id]) @@ -140,18 +160,18 @@ def _get_id_params(self, id=None, id_list=False): def _extra_error_output(self): output = super(TransitGatewayVpcAttachmentManager, self)._extra_error_output() if self.resource_id: - output['TransitGatewayAttachmentId'] = self.resource_id + output["TransitGatewayAttachmentId"] = self.resource_id return output def _filter_immutable_resource_attributes(self, resource): resource = super(TransitGatewayVpcAttachmentManager, self)._filter_immutable_resource_attributes(resource) - resource.pop('TransitGatewayId', None) - resource.pop('VpcId', None) - resource.pop('VpcOwnerId', None) - resource.pop('State', None) - resource.pop('SubnetIds', None) - resource.pop('CreationTime', None) - resource.pop('Tags', None) + resource.pop("TransitGatewayId", None) + resource.pop("VpcId", None) + resource.pop("VpcOwnerId", None) + resource.pop("State", None) + resource.pop("SubnetIds", None) + resource.pop("CreationTime", None) + resource.pop("Tags", None) return resource def _set_option(self, name, value): @@ -159,36 +179,36 @@ def _set_option(self, name, value): return False # For now VPC Attachment options are all enable/disable if value: - value = 'enable' + value = "enable" else: - value = 'disable' + value = "disable" - options = deepcopy(self._preupdate_resource.get('Options', dict())) - options.update(self._resource_updates.get('Options', dict())) + options = deepcopy(self._preupdate_resource.get("Options", dict())) + options.update(self._resource_updates.get("Options", dict())) options[name] = value - return self._set_resource_value('Options', options) + return self._set_resource_value("Options", options) def set_dns_support(self, value): - return self._set_option('DnsSupport', value) + return self._set_option("DnsSupport", value) def set_ipv6_support(self, value): - return self._set_option('Ipv6Support', value) + return self._set_option("Ipv6Support", value) def set_appliance_mode_support(self, value): - return self._set_option('ApplianceModeSupport', value) + return self._set_option("ApplianceModeSupport", value) def set_transit_gateway(self, tgw_id): - return self._set_resource_value('TransitGatewayId', tgw_id) + return self._set_resource_value("TransitGatewayId", tgw_id) def set_vpc(self, vpc_id): - return self._set_resource_value('VpcId', vpc_id) + return self._set_resource_value("VpcId", vpc_id) def set_subnets(self, subnets=None, purge=True): if subnets is None: return False - current_subnets = set(self._preupdate_resource.get('SubnetIds', [])) + current_subnets = set(self._preupdate_resource.get("SubnetIds", [])) desired_subnets = set(subnets) if not purge: desired_subnets = desired_subnets.union(current_subnets) @@ -197,21 +217,23 @@ def set_subnets(self, subnets=None, purge=True): # information we 'know'. subnet_details = self._describe_subnets(SubnetIds=list(desired_subnets)) vpc_id = self.subnets_to_vpc(desired_subnets, subnet_details) - self._set_resource_value('VpcId', vpc_id, immutable=True) + self._set_resource_value("VpcId", vpc_id, immutable=True) # Only one subnet per-AZ is permitted - azs = [s.get('AvailabilityZoneId') for s in subnet_details] + azs = [s.get("AvailabilityZoneId") for s in subnet_details] if len(azs) != len(set(azs)): self.module.fail_json( - msg='Only one attachment subnet per availability zone may be set.', - availability_zones=azs, subnets=subnet_details) + msg="Only one attachment subnet per availability zone may be set.", + availability_zones=azs, + subnets=subnet_details, + ) subnets_to_add = list(desired_subnets.difference(current_subnets)) subnets_to_remove = list(current_subnets.difference(desired_subnets)) if not subnets_to_remove and not subnets_to_add: return False self._subnet_updates = dict(add=subnets_to_add, remove=subnets_to_remove) - self._set_resource_value('SubnetIds', list(desired_subnets)) + self._set_resource_value("SubnetIds", list(desired_subnets)) return True def subnets_to_vpc(self, subnets, subnet_details=None): @@ -221,11 +243,13 @@ def subnets_to_vpc(self, subnets, subnet_details=None): if subnet_details is None: subnet_details = self._describe_subnets(SubnetIds=list(subnets)) - vpcs = [s.get('VpcId') for s in subnet_details] + vpcs = [s.get("VpcId") for s in subnet_details] if len(set(vpcs)) > 1: self.module.fail_json( - msg='Attachment subnets may only be in one VPC, multiple VPCs found', - vpcs=list(set(vpcs)), subnets=subnet_details) + msg="Attachment subnets may only be in one VPC, multiple VPCs found", + vpcs=list(set(vpcs)), + subnets=subnet_details, + ) return vpcs[0] @@ -248,26 +272,25 @@ def _do_create_resource(self): params = self._merge_resource_changes(filter_immutable=False, creation=True) response = self._create_vpc_attachment(**params) if response: - self.resource_id = response.get('TransitGatewayAttachmentId', None) + self.resource_id = response.get("TransitGatewayAttachmentId", None) return response def _do_update_resource(self): - if self._preupdate_resource.get('State', None) == 'pending': + if self._preupdate_resource.get("State", None) == "pending": # Resources generally don't like it if you try to update before creation # is complete. If things are in a 'pending' state they'll often throw # exceptions. self._wait_for_creation() - elif self._preupdate_resource.get('State', None) == 'deleting': - self.module.fail_json(msg='Deletion in progress, unable to update', - route_tables=[self.original_resource]) + elif self._preupdate_resource.get("State", None) == "deleting": + self.module.fail_json(msg="Deletion in progress, unable to update", route_tables=[self.original_resource]) updates = self._filter_immutable_resource_attributes(self._resource_updates) - subnets_to_add = self._subnet_updates.get('add', []) - subnets_to_remove = self._subnet_updates.get('remove', []) + subnets_to_add = self._subnet_updates.get("add", []) + subnets_to_remove = self._subnet_updates.get("remove", []) if subnets_to_add: - updates['AddSubnetIds'] = subnets_to_add + updates["AddSubnetIds"] = subnets_to_add if subnets_to_remove: - updates['RemoveSubnetIds'] = subnets_to_remove + updates["RemoveSubnetIds"] = subnets_to_remove if not updates: return False @@ -283,7 +306,6 @@ def get_resource(self): return self.get_attachment() def delete(self, id=None): - if id: id_params = self._get_id_params(id=id, id_list=True) result = self._get_tgw_vpc_attachment(**id_params) @@ -295,7 +317,7 @@ def delete(self, id=None): if not result: return False - if result.get('State') == 'deleting': + if result.get("State") == "deleting": self._wait_for_deletion() return False @@ -315,9 +337,9 @@ def delete(self, id=None): def list(self, filters=None, id=None): params = dict() if id: - params['TransitGatewayAttachmentIds'] = [id] + params["TransitGatewayAttachmentIds"] = [id] if filters: - params['Filters'] = ansible_dict_to_boto3_filter_list(filters) + params["Filters"] = ansible_dict_to_boto3_filter_list(filters) attachments = self._describe_vpc_attachments(**params) if not attachments: return list() @@ -325,7 +347,6 @@ def list(self, filters=None, id=None): return [self._normalize_tgw_attachment(a) for a in attachments] def get_attachment(self, id=None): - # RouteTable needs a list, Association/Propagation needs a single ID id_params = self._get_id_params(id=id, id_list=True) id_param = self._get_id_params(id=id, id_list=False) diff --git a/plugins/modules/ec2_transit_gateway_vpc_attachment.py b/plugins/modules/ec2_transit_gateway_vpc_attachment.py index 2878fbf9129..301fefb0513 100644 --- a/plugins/modules/ec2_transit_gateway_vpc_attachment.py +++ b/plugins/modules/ec2_transit_gateway_vpc_attachment.py @@ -221,25 +221,24 @@ def main(): - argument_spec = dict( - state=dict(type='str', required=False, default='present', choices=['absent', 'present']), - transit_gateway=dict(type='str', required=False, aliases=['transit_gateway_id']), - id=dict(type='str', required=False, aliases=['attachment_id']), - name=dict(type='str', required=False), - subnets=dict(type='list', elements='str', required=False), - purge_subnets=dict(type='bool', required=False, default=True), - tags=dict(type='dict', required=False, aliases=['resource_tags']), - purge_tags=dict(type='bool', required=False, default=True), - appliance_mode_support=dict(type='bool', required=False), - dns_support=dict(type='bool', required=False), - ipv6_support=dict(type='bool', required=False), - wait=dict(type='bool', required=False, default=True), - wait_timeout=dict(type='int', required=False), + state=dict(type="str", required=False, default="present", choices=["absent", "present"]), + transit_gateway=dict(type="str", required=False, aliases=["transit_gateway_id"]), + id=dict(type="str", required=False, aliases=["attachment_id"]), + name=dict(type="str", required=False), + subnets=dict(type="list", elements="str", required=False), + purge_subnets=dict(type="bool", required=False, default=True), + tags=dict(type="dict", required=False, aliases=["resource_tags"]), + purge_tags=dict(type="bool", required=False, default=True), + appliance_mode_support=dict(type="bool", required=False), + dns_support=dict(type="bool", required=False), + ipv6_support=dict(type="bool", required=False), + wait=dict(type="bool", required=False, default=True), + wait_timeout=dict(type="int", required=False), ) one_of = [ - ['id', 'transit_gateway', 'name'], + ["id", "transit_gateway", "name"], ] module = AnsibleAWSModule( @@ -248,55 +247,68 @@ def main(): required_one_of=one_of, ) - attach_id = module.params.get('id', None) - tgw = module.params.get('transit_gateway', None) - name = module.params.get('name', None) - tags = module.params.get('tags', None) - purge_tags = module.params.get('purge_tags') - state = module.params.get('state') - subnets = module.params.get('subnets', None) - purge_subnets = module.params.get('purge_subnets') + attach_id = module.params.get("id", None) + tgw = module.params.get("transit_gateway", None) + name = module.params.get("name", None) + tags = module.params.get("tags", None) + purge_tags = module.params.get("purge_tags") + state = module.params.get("state") + subnets = module.params.get("subnets", None) + purge_subnets = module.params.get("purge_subnets") # When not provided with an ID see if one exists. if not attach_id: search_manager = TransitGatewayVpcAttachmentManager(module=module) filters = dict() if tgw: - filters['transit-gateway-id'] = tgw + filters["transit-gateway-id"] = tgw if name: - filters['tag:Name'] = name + filters["tag:Name"] = name if subnets: vpc_id = search_manager.subnets_to_vpc(subnets) - filters['vpc-id'] = vpc_id + filters["vpc-id"] = vpc_id # Attachments lurk in a 'deleted' state, for a while, ignore them so we # can reuse the names - filters['state'] = [ - 'available', 'deleting', 'failed', 'failing', 'initiatingRequest', 'modifying', - 'pendingAcceptance', 'pending', 'rollingBack', 'rejected', 'rejecting' + filters["state"] = [ + "available", + "deleting", + "failed", + "failing", + "initiatingRequest", + "modifying", + "pendingAcceptance", + "pending", + "rollingBack", + "rejected", + "rejecting", ] attachments = search_manager.list(filters=filters) if len(attachments) > 1: - module.fail_json('Multiple matching attachments found, provide an ID', attachments=attachments) + module.fail_json("Multiple matching attachments found, provide an ID", attachments=attachments) # If we find a match then we'll modify it by ID, otherwise we'll be # creating a new RTB. if attachments: - attach_id = attachments[0]['transit_gateway_attachment_id'] + attach_id = attachments[0]["transit_gateway_attachment_id"] manager = TransitGatewayVpcAttachmentManager(module=module, id=attach_id) - manager.set_wait(module.params.get('wait', None)) - manager.set_wait_timeout(module.params.get('wait_timeout', None)) + manager.set_wait(module.params.get("wait", None)) + manager.set_wait_timeout(module.params.get("wait_timeout", None)) - if state == 'absent': + if state == "absent": manager.delete() else: if not attach_id: if not tgw: - module.fail_json('No existing attachment found. To create a new attachment' - ' the `transit_gateway` parameter must be provided.') + module.fail_json( + "No existing attachment found. To create a new attachment" + " the `transit_gateway` parameter must be provided." + ) if not subnets: - module.fail_json('No existing attachment found. To create a new attachment' - ' the `subnets` parameter must be provided.') + module.fail_json( + "No existing attachment found. To create a new attachment" + " the `subnets` parameter must be provided." + ) # name is just a special case of tags. if name: @@ -310,9 +322,9 @@ def main(): manager.set_transit_gateway(tgw) manager.set_subnets(subnets, purge_subnets) manager.set_tags(tags, purge_tags) - manager.set_dns_support(module.params.get('dns_support', None)) - manager.set_ipv6_support(module.params.get('ipv6_support', None)) - manager.set_appliance_mode_support(module.params.get('appliance_mode_support', None)) + manager.set_dns_support(module.params.get("dns_support", None)) + manager.set_ipv6_support(module.params.get("ipv6_support", None)) + manager.set_appliance_mode_support(module.params.get("appliance_mode_support", None)) manager.flush_changes() results = dict( @@ -320,7 +332,7 @@ def main(): attachments=[manager.updated_resource], ) if manager.changed: - results['diff'] = dict( + results["diff"] = dict( before=manager.original_resource, after=manager.updated_resource, ) @@ -328,5 +340,5 @@ def main(): module.exit_json(**results) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py b/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py index 49c03ff432c..a665e4080cc 100644 --- a/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py +++ b/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py @@ -147,17 +147,16 @@ def main(): - argument_spec = dict( - id=dict(type='str', required=False, aliases=['attachment_id']), - name=dict(type='str', required=False), - filters=dict(type='dict', required=False), - include_deleted=dict(type='bool', required=False, default=False) + id=dict(type="str", required=False, aliases=["attachment_id"]), + name=dict(type="str", required=False), + filters=dict(type="dict", required=False), + include_deleted=dict(type="bool", required=False, default=False), ) mutually_exclusive = [ - ['id', 'name'], - ['id', 'filters'], + ["id", "name"], + ["id", "filters"], ] module = AnsibleAWSModule( @@ -165,22 +164,31 @@ def main(): supports_check_mode=True, ) - name = module.params.get('name', None) - id = module.params.get('id', None) - opt_filters = module.params.get('filters', None) + name = module.params.get("name", None) + id = module.params.get("id", None) + opt_filters = module.params.get("filters", None) search_manager = TransitGatewayVpcAttachmentManager(module=module) filters = dict() if name: - filters['tag:Name'] = name + filters["tag:Name"] = name - if not module.params.get('include_deleted'): + if not module.params.get("include_deleted"): # Attachments lurk in a 'deleted' state, for a while, ignore them so we # can reuse the names - filters['state'] = [ - 'available', 'deleting', 'failed', 'failing', 'initiatingRequest', 'modifying', - 'pendingAcceptance', 'pending', 'rollingBack', 'rejected', 'rejecting' + filters["state"] = [ + "available", + "deleting", + "failed", + "failing", + "initiatingRequest", + "modifying", + "pendingAcceptance", + "pending", + "rollingBack", + "rejected", + "rejecting", ] if opt_filters: @@ -191,5 +199,5 @@ def main(): module.exit_json(changed=False, attachments=attachments, filters=filters) -if __name__ == '__main__': +if __name__ == "__main__": main()