From 375d92f4e790367f39be6d00023c88414eb73d57 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Mon, 19 Oct 2020 17:05:22 +0200 Subject: [PATCH] Mass-migration over to is_boto3_error_code --- plugins/modules/aws_glue_connection.py | 8 +-- plugins/modules/aws_glue_job.py | 10 ++-- plugins/modules/aws_kms_info.py | 18 +++--- plugins/modules/aws_ssm_parameter_store.py | 7 ++- ..._step_functions_state_machine_execution.py | 9 +-- plugins/modules/aws_waf_condition.py | 7 ++- plugins/modules/cloudwatchevent_rule.py | 19 +++---- plugins/modules/data_pipeline.py | 6 +- plugins/modules/ec2_asg.py | 19 +++---- plugins/modules/ec2_asg_info.py | 10 ++-- plugins/modules/ec2_instance.py | 21 ++++--- plugins/modules/ec2_placement_group.py | 15 ++--- plugins/modules/ec2_transit_gateway_info.py | 9 ++- plugins/modules/ec2_vpc_egress_igw.py | 25 +++------ plugins/modules/ec2_vpc_nacl_info.py | 9 ++- plugins/modules/ec2_vpc_route_table.py | 8 +-- plugins/modules/ecs_ecr.py | 22 +++----- plugins/modules/ecs_service_info.py | 8 +-- plugins/modules/efs.py | 5 +- plugins/modules/elasticache.py | 14 ++--- plugins/modules/elasticache_info.py | 9 +-- plugins/modules/elasticache_snapshot.py | 29 +++++----- plugins/modules/execute_lambda.py | 13 +++-- plugins/modules/iam_group.py | 15 ++--- plugins/modules/iam_managed_policy.py | 19 +++---- plugins/modules/iam_password_policy.py | 10 ++-- plugins/modules/iam_policy_info.py | 7 ++- plugins/modules/iam_role.py | 19 +++---- plugins/modules/iam_role_info.py | 10 ++-- plugins/modules/iam_user.py | 30 +++++----- plugins/modules/lambda_alias.py | 21 ++++--- plugins/modules/lambda_facts.py | 55 +++++++++---------- plugins/modules/lambda_info.py | 55 +++++++++---------- plugins/modules/lambda_policy.py | 23 ++++---- plugins/modules/lightsail.py | 9 ++- plugins/modules/rds_param_group.py | 19 +++---- plugins/modules/s3_lifecycle.py | 19 +++---- plugins/modules/sqs_queue.py | 7 +-- 38 files changed, 275 insertions(+), 343 deletions(-) diff --git a/plugins/modules/aws_glue_connection.py b/plugins/modules/aws_glue_connection.py index 49011f9cb66..b0ad6c17fd4 100644 --- a/plugins/modules/aws_glue_connection.py +++ b/plugins/modules/aws_glue_connection.py @@ -131,6 +131,7 @@ ''' from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code 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 get_ec2_security_group_ids_from_names @@ -161,11 +162,8 @@ def _get_glue_connection(connection, module): try: return connection.get_connection(**params)['Connection'] - except (BotoCoreError, ClientError) as e: - if e.response['Error']['Code'] == 'EntityNotFoundException': - return None - else: - raise e + except is_boto3_error_code('EntityNotFoundException'): + return None def _compare_glue_connection_params(user_params, current_params): diff --git a/plugins/modules/aws_glue_job.py b/plugins/modules/aws_glue_job.py index 192969415e6..50336de29a1 100644 --- a/plugins/modules/aws_glue_job.py +++ b/plugins/modules/aws_glue_job.py @@ -193,6 +193,7 @@ pass # Handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -208,11 +209,10 @@ def _get_glue_job(connection, module, glue_job_name): try: return connection.get_job(JobName=glue_job_name)['Job'] - except (BotoCoreError, ClientError) as e: - if e.response['Error']['Code'] == 'EntityNotFoundException': - return None - else: - module.fail_json_aws(e) + except is_boto3_error_code('EntityNotFoundException'): + return None + except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e) def _compare_glue_job_params(user_params, current_params): diff --git a/plugins/modules/aws_kms_info.py b/plugins/modules/aws_kms_info.py index 1dee886af78..a62a8c5ed23 100644 --- a/plugins/modules/aws_kms_info.py +++ b/plugins/modules/aws_kms_info.py @@ -305,11 +305,10 @@ def get_kms_tags(connection, module, key_id): try: tag_response = get_kms_tags_with_backoff(connection, key_id, **kwargs) tags.extend(tag_response['Tags']) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] != 'AccessDeniedException': - module.fail_json_aws(e, msg="Failed to obtain key tags") - else: - tag_response = {} + except is_boto3_error_code('AccessDeniedException'): + tag_response = {} + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Failed to obtain key tags") if tag_response.get('NextMarker'): kwargs['Marker'] = tag_response['NextMarker'] else: @@ -322,11 +321,10 @@ def get_kms_policies(connection, module, key_id): policies = list_key_policies_with_backoff(connection, key_id)['PolicyNames'] return [get_key_policy_with_backoff(connection, key_id, policy)['Policy'] for policy in policies] - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] != 'AccessDeniedException': - module.fail_json_aws(e, msg="Failed to obtain key policies") - else: - return [] + except is_boto3_error_code('AccessDeniedException'): + return [] + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Failed to obtain key policies") def key_matches_filter(key, filtr): diff --git a/plugins/modules/aws_ssm_parameter_store.py b/plugins/modules/aws_ssm_parameter_store.py index 00ffe046046..0598cacf637 100644 --- a/plugins/modules/aws_ssm_parameter_store.py +++ b/plugins/modules/aws_ssm_parameter_store.py @@ -133,6 +133,7 @@ pass # Handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code def update_parameter(client, module, args): @@ -213,9 +214,9 @@ def delete_parameter(client, module): response = client.delete_parameter( Name=module.params.get('name') ) - except ClientError as e: - if e.response['Error']['Code'] == 'ParameterNotFound': - return False, {} + except is_boto3_error_code('ParameterNotFound'): + return False, {} + except ClientError as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="deleting parameter") return True, response diff --git a/plugins/modules/aws_step_functions_state_machine_execution.py b/plugins/modules/aws_step_functions_state_machine_execution.py index f9e1d3fa44c..4e1a7743ac9 100644 --- a/plugins/modules/aws_step_functions_state_machine_execution.py +++ b/plugins/modules/aws_step_functions_state_machine_execution.py @@ -90,6 +90,7 @@ from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict try: @@ -123,10 +124,10 @@ def start_execution(module, sfn_client): name=name, input=execution_input ) - except (ClientError, BotoCoreError) as e: - if e.response['Error']['Code'] == 'ExecutionAlreadyExists': - # this will never be executed anymore - module.exit_json(changed=False) + except is_boto3_error_code('ExecutionAlreadyExists'): + # this will never be executed anymore + module.exit_json(changed=False) + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Failed to start execution.") module.exit_json(changed=True, **camel_dict_to_snake_dict(res_execution)) diff --git a/plugins/modules/aws_waf_condition.py b/plugins/modules/aws_waf_condition.py index 3a3083dcd23..2de23cf12ff 100644 --- a/plugins/modules/aws_waf_condition.py +++ b/plugins/modules/aws_waf_condition.py @@ -403,6 +403,7 @@ pass # handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 camel_dict_to_snake_dict from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies @@ -545,9 +546,9 @@ def delete_unused_regex_pattern(self, regex_pattern_set_id): run_func_with_change_token_backoff(self.client, self.module, {'RegexPatternSetId': regex_pattern_set_id}, self.client.delete_regex_pattern_set, wait=True) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - if e.response['Error']['Code'] == 'WAFNonexistentItemException': - return + except is_boto3_error_code('WAFNonexistentItemException'): + return + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except self.module.fail_json_aws(e, msg='Could not delete regex pattern') def get_condition_by_name(self, name): diff --git a/plugins/modules/cloudwatchevent_rule.py b/plugins/modules/cloudwatchevent_rule.py index 0ba66909d25..7f4564ec1c0 100644 --- a/plugins/modules/cloudwatchevent_rule.py +++ b/plugins/modules/cloudwatchevent_rule.py @@ -155,6 +155,7 @@ pass # handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -174,12 +175,9 @@ def describe(self): """Returns the existing details of the rule in AWS""" try: rule_info = self.client.describe_rule(Name=self.name) - except botocore.exceptions.ClientError as e: - error_code = e.response.get('Error', {}).get('Code') - if error_code == 'ResourceNotFoundException': - return {} - self.module.fail_json_aws(e, msg="Could not describe rule %s" % self.name) - except botocore.exceptions.BotoCoreError as e: + except is_boto3_error_code('ResourceNotFoundException'): + return {} + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except self.module.fail_json_aws(e, msg="Could not describe rule %s" % self.name) return self._snakify(rule_info) @@ -237,12 +235,9 @@ def list_targets(self): """Lists the existing targets for the rule in AWS""" try: targets = self.client.list_targets_by_rule(Rule=self.name) - except botocore.exceptions.ClientError as e: - error_code = e.response.get('Error', {}).get('Code') - if error_code == 'ResourceNotFoundException': - return [] - self.module.fail_json_aws(e, msg="Could not find target for rule %s" % self.name) - except botocore.exceptions.BotoCoreError as e: + except is_boto3_error_code('ResourceNotFoundException'): + return [] + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except self.module.fail_json_aws(e, msg="Could not find target for rule %s" % self.name) return self._snakify(targets)['targets'] diff --git a/plugins/modules/data_pipeline.py b/plugins/modules/data_pipeline.py index 8393aa0a7e2..5811b35066b 100644 --- a/plugins/modules/data_pipeline.py +++ b/plugins/modules/data_pipeline.py @@ -210,6 +210,7 @@ from ansible.module_utils._text import to_text from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -361,9 +362,8 @@ def activate_pipeline(client, module): else: try: client.activate_pipeline(pipelineId=dp_id) - except ClientError as e: - if e.response["Error"]["Code"] == "InvalidRequestException": - module.fail_json(msg="You need to populate your pipeline before activation.") + except is_boto3_error_code('InvalidRequestException'): + module.fail_json(msg="You need to populate your pipeline before activation.") try: pipeline_status_timeout(client, dp_id, status=DP_ACTIVE_STATES, timeout=timeout) diff --git a/plugins/modules/ec2_asg.py b/plugins/modules/ec2_asg.py index 72b41e0baab..d9849a78217 100644 --- a/plugins/modules/ec2_asg.py +++ b/plugins/modules/ec2_asg.py @@ -534,6 +534,7 @@ from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 camel_dict_to_snake_dict @@ -851,12 +852,9 @@ def elb_healthy(asg_connection, elb_connection, group_name): # but has not yet show up in the ELB try: lb_instances = describe_instance_health(elb_connection, lb, instances) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'InvalidInstance': - return None - - module.fail_json_aws(e, msg="Failed to get load balancer.") - except botocore.exceptions.BotoCoreError as e: + except is_boto3_error_code('InvalidInstance'): + return None + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Failed to get load balancer.") for i in lb_instances.get('InstanceStates'): @@ -883,12 +881,9 @@ def tg_healthy(asg_connection, elbv2_connection, group_name): # but has not yet show up in the ELB try: tg_instances = describe_target_health(elbv2_connection, tg, instances) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'InvalidInstance': - return None - - module.fail_json_aws(e, msg="Failed to get target group.") - except botocore.exceptions.BotoCoreError as e: + except is_boto3_error_code('InvalidInstance'): + return None + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Failed to get target group.") for i in tg_instances.get('TargetHealthDescriptions'): diff --git a/plugins/modules/ec2_asg_info.py b/plugins/modules/ec2_asg_info.py index 07df498968a..15f6886c902 100644 --- a/plugins/modules/ec2_asg_info.py +++ b/plugins/modules/ec2_asg_info.py @@ -224,6 +224,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -373,12 +374,9 @@ def find_asgs(conn, module, name=None, tags=None): tg_paginator = elbv2.get_paginator('describe_target_groups') tg_result = tg_paginator.paginate(TargetGroupArns=asg['target_group_arns']).build_full_result() asg['target_group_names'] = [tg['TargetGroupName'] for tg in tg_result['TargetGroups']] - except ClientError as e: - if e.response['Error']['Code'] == 'TargetGroupNotFound': - asg['target_group_names'] = [] - else: - module.fail_json_aws(e, msg="Failed to describe Target Groups") - except BotoCoreError as e: + except is_boto3_error_code('TargetGroupNotFound'): + asg['target_group_names'] = [] + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Failed to describe Target Groups") else: asg['target_group_names'] = [] diff --git a/plugins/modules/ec2_instance.py b/plugins/modules/ec2_instance.py index 6a587aeeb96..a4fc9b5f367 100644 --- a/plugins/modules/ec2_instance.py +++ b/plugins/modules/ec2_instance.py @@ -814,6 +814,7 @@ import ansible_collections.amazon.aws.plugins.module_utils.ec2 as ec2_utils from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_message 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 @@ -1116,15 +1117,13 @@ def discover_security_groups(group, groups, parent_vpc_id=None, subnet_id=None, if subnet_id is not None: try: sub = ec2.describe_subnets(SubnetIds=[subnet_id]) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'InvalidGroup.NotFound': - module.fail_json( - "Could not find subnet {0} to associate security groups. Please check the vpc_subnet_id and security_groups parameters.".format( - subnet_id - ) + except is_boto3_error_code('InvalidGroup.NotFound'): + module.fail_json( + "Could not find subnet {0} to associate security groups. Please check the vpc_subnet_id and security_groups parameters.".format( + subnet_id ) - module.fail_json_aws(e, msg="Error while searching for subnet {0} parent VPC.".format(subnet_id)) - except botocore.exceptions.BotoCoreError as e: + ) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Error while searching for subnet {0} parent VPC.".format(subnet_id)) parent_vpc_id = sub['Subnets'][0]['VpcId'] @@ -1609,9 +1608,9 @@ def determine_iam_role(name_or_arn): try: role = iam.get_instance_profile(InstanceProfileName=name_or_arn, aws_retry=True) return role['InstanceProfile']['Arn'] - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - module.fail_json_aws(e, msg="Could not find instance_role {0}".format(name_or_arn)) + except is_boto3_error_code('NoSuchEntity'): + module.fail_json_aws(e, msg="Could not find instance_role {0}".format(name_or_arn)) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="An error occurred while searching for instance_role {0}. Please try supplying the full ARN.".format(name_or_arn)) diff --git a/plugins/modules/ec2_placement_group.py b/plugins/modules/ec2_placement_group.py index 17a701de016..b50e0ddbb08 100644 --- a/plugins/modules/ec2_placement_group.py +++ b/plugins/modules/ec2_placement_group.py @@ -93,6 +93,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 @@ -129,13 +130,13 @@ def create_placement_group(connection, module): try: connection.create_placement_group( GroupName=name, Strategy=strategy, DryRun=module.check_mode) - except (BotoCoreError, ClientError) as e: - if e.response['Error']['Code'] == "DryRunOperation": - module.exit_json(changed=True, placement_group={ - "name": name, - "state": 'DryRun', - "strategy": strategy, - }) + except is_boto3_error_code('DryRunOperation'): + module.exit_json(changed=True, placement_group={ + "name": name, + "state": 'DryRun', + "strategy": strategy, + }) + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws( e, msg="Couldn't create placement group [%s]" % name) diff --git a/plugins/modules/ec2_transit_gateway_info.py b/plugins/modules/ec2_transit_gateway_info.py index fb820ce62b6..d5ee359de8f 100644 --- a/plugins/modules/ec2_transit_gateway_info.py +++ b/plugins/modules/ec2_transit_gateway_info.py @@ -170,6 +170,7 @@ pass # handled by imported AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 @@ -206,11 +207,9 @@ def describe_transit_gateways(self): try: response = self._connection.describe_transit_gateways( TransitGatewayIds=transit_gateway_ids, Filters=filters) - except ClientError as e: - if e.response['Error']['Code'] == 'InvalidTransitGatewayID.NotFound': - self._results['transit_gateways'] = [] - return - raise + except is_boto3_error_code('InvalidTransitGatewayID.NotFound'): + self._results['transit_gateways'] = [] + return for transit_gateway in response['TransitGateways']: transit_gateway_info.append(camel_dict_to_snake_dict(transit_gateway, ignore_list=['Tags'])) diff --git a/plugins/modules/ec2_vpc_egress_igw.py b/plugins/modules/ec2_vpc_egress_igw.py index df1826e0219..a48b9b4744a 100644 --- a/plugins/modules/ec2_vpc_egress_igw.py +++ b/plugins/modules/ec2_vpc_egress_igw.py @@ -63,6 +63,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -78,14 +79,9 @@ def delete_eigw(module, conn, eigw_id): try: response = conn.delete_egress_only_internet_gateway(DryRun=module.check_mode, EgressOnlyInternetGatewayId=eigw_id) - except botocore.exceptions.ClientError as e: - # When boto3 method is run with DryRun=True it returns an error on success - # We need to catch the error and return something valid - if e.response.get('Error', {}).get('Code') == "DryRunOperation": - changed = True - else: - module.fail_json_aws(e, msg="Could not delete Egress-Only Internet Gateway {0} from VPC {1}".format(eigw_id, module.vpc_id)) - except botocore.exceptions.BotoCoreError as e: + except is_boto3_error_code('DryRunOperation'): + changed = True + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Could not delete Egress-Only Internet Gateway {0} from VPC {1}".format(eigw_id, module.vpc_id)) if not module.check_mode: @@ -107,16 +103,13 @@ def create_eigw(module, conn, vpc_id): try: response = conn.create_egress_only_internet_gateway(DryRun=module.check_mode, VpcId=vpc_id) - except botocore.exceptions.ClientError as e: + except is_boto3_error_code('DryRunOperation'): # When boto3 method is run with DryRun=True it returns an error on success # We need to catch the error and return something valid - if e.response.get('Error', {}).get('Code') == "DryRunOperation": - changed = True - elif e.response.get('Error', {}).get('Code') == "InvalidVpcID.NotFound": - module.fail_json_aws(e, msg="invalid vpc ID '{0}' provided".format(vpc_id)) - else: - module.fail_json_aws(e, msg="Could not create Egress-Only Internet Gateway for vpc ID {0}".format(vpc_id)) - except botocore.exceptions.BotoCoreError as e: + changed = True + except is_boto3_error_code('InvalidVpcID.NotFound') as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="invalid vpc ID '{0}' provided".format(vpc_id)) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Could not create Egress-Only Internet Gateway for vpc ID {0}".format(vpc_id)) if not module.check_mode: diff --git a/plugins/modules/ec2_vpc_nacl_info.py b/plugins/modules/ec2_vpc_nacl_info.py index adf0f2f8d07..67d394ad393 100644 --- a/plugins/modules/ec2_vpc_nacl_info.py +++ b/plugins/modules/ec2_vpc_nacl_info.py @@ -111,6 +111,7 @@ from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 camel_dict_to_snake_dict @@ -132,11 +133,9 @@ def list_ec2_vpc_nacls(connection, module): try: nacls = connection.describe_network_acls(aws_retry=True, NetworkAclIds=nacl_ids, Filters=filters) - except ClientError as e: - if e.response['Error']['Code'] == 'InvalidNetworkAclID.NotFound': - module.fail_json(msg='Unable to describe ACL. NetworkAcl does not exist') - module.fail_json_aws(e, msg="Unable to describe network ACLs {0}".format(nacl_ids)) - except BotoCoreError as e: + except is_boto3_error_code('InvalidNetworkAclID.NotFound'): + module.fail_json(msg='Unable to describe ACL. NetworkAcl does not exist') + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Unable to describe network ACLs {0}".format(nacl_ids)) # Turn the boto3 result in to ansible_friendly_snaked_names diff --git a/plugins/modules/ec2_vpc_route_table.py b/plugins/modules/ec2_vpc_route_table.py index ea5b3ddda35..8ed6fb4657f 100644 --- a/plugins/modules/ec2_vpc_route_table.py +++ b/plugins/modules/ec2_vpc_route_table.py @@ -233,6 +233,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code 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 ansible_dict_to_boto3_tag_list from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry @@ -373,11 +374,8 @@ def ensure_tags(connection=None, module=None, resource_id=None, tags=None, purge def describe_route_tables_with_backoff(connection, **params): try: return connection.describe_route_tables(**params)['RouteTables'] - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'InvalidRouteTableID.NotFound': - return None - else: - raise + except is_boto3_error_code('InvalidRouteTableID.NotFound'): + return None def get_route_table_by_id(connection, module, route_table_id): diff --git a/plugins/modules/ecs_ecr.py b/plugins/modules/ecs_ecr.py index 6ec2eaa06fd..3a7d595df62 100644 --- a/plugins/modules/ecs_ecr.py +++ b/plugins/modules/ecs_ecr.py @@ -195,6 +195,7 @@ from ansible.module_utils.six import string_types from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto_exception from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies from ansible_collections.amazon.aws.plugins.module_utils.ec2 import sort_json_policy_dict @@ -227,11 +228,8 @@ def get_repository(self, registry_id, name): repositoryNames=[name], **build_kwargs(registry_id)) repos = res.get('repositories') return repos and repos[0] - except ClientError as err: - code = err.response['Error'].get('Code', 'Unknown') - if code == 'RepositoryNotFoundException': - return None - raise + except is_boto3_error_code('RepositoryNotFoundException'): + return None def get_repository_policy(self, registry_id, name): try: @@ -239,11 +237,8 @@ def get_repository_policy(self, registry_id, name): repositoryName=name, **build_kwargs(registry_id)) text = res.get('policyText') return text and json.loads(text) - except ClientError as err: - code = err.response['Error'].get('Code', 'Unknown') - if code == 'RepositoryPolicyNotFoundException': - return None - raise + except is_boto3_error_code('RepositoryPolicyNotFoundException'): + return None def create_repository(self, registry_id, name, image_tag_mutability): if registry_id: @@ -330,11 +325,8 @@ def get_lifecycle_policy(self, registry_id, name): repositoryName=name, **build_kwargs(registry_id)) text = res.get('lifecyclePolicyText') return text and json.loads(text) - except ClientError as err: - code = err.response['Error'].get('Code', 'Unknown') - if code == 'LifecyclePolicyNotFoundException': - return None - raise + except is_boto3_error_code('LifecyclePolicyNotFoundException'): + return None def put_lifecycle_policy(self, registry_id, name, policy_text): if not self.check_mode: diff --git a/plugins/modules/ecs_service_info.py b/plugins/modules/ecs_service_info.py index d428dde8835..2d64a89e6dd 100644 --- a/plugins/modules/ecs_service_info.py +++ b/plugins/modules/ecs_service_info.py @@ -138,6 +138,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 @@ -153,11 +154,8 @@ def list_services_with_backoff(self, **kwargs): paginator = self.ecs.get_paginator('list_services') try: return paginator.paginate(**kwargs).build_full_result() - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'ClusterNotFoundException': - self.module.fail_json_aws(e, "Could not find cluster to list services") - else: - raise + except is_boto3_error_code('ClusterNotFoundException') as e: + self.module.fail_json_aws(e, "Could not find cluster to list services") @AWSRetry.backoff(tries=5, delay=5, backoff=2.0) def describe_services_with_backoff(self, **kwargs): diff --git a/plugins/modules/efs.py b/plugins/modules/efs.py index d1d2d14a8a2..be992b3f148 100644 --- a/plugins/modules/efs.py +++ b/plugins/modules/efs.py @@ -235,6 +235,7 @@ pass # Handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_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 @@ -623,8 +624,8 @@ def iterate_all(attr, map_method, **kwargs): args['Marker'] = data['Nextmarker'] continue break - except ClientError as e: - if e.response['Error']['Code'] == "ThrottlingException" and wait < 600: + except is_boto3_error_code('ThrottlingException'): + if wait < 600: sleep(wait) wait = wait * 2 continue diff --git a/plugins/modules/elasticache.py b/plugins/modules/elasticache.py index 9535147e72c..85ecae3b6a0 100644 --- a/plugins/modules/elasticache.py +++ b/plugins/modules/elasticache.py @@ -135,6 +135,7 @@ pass # Handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code 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 get_aws_connection_info @@ -441,13 +442,12 @@ def _refresh_data(self, cache_cluster_data=None): if cache_cluster_data is None: try: response = self.conn.describe_cache_clusters(CacheClusterId=self.name, ShowCacheNodeInfo=True) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'CacheClusterNotFound': - self.data = None - self.status = 'gone' - return - else: - self.module.fail_json_aws(e, msg="Failed to describe cache clusters") + except is_boto3_error_code('CacheClusterNotFound'): + self.data = None + self.status = 'gone' + return + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + self.module.fail_json_aws(e, msg="Failed to describe cache clusters") cache_cluster_data = response['CacheClusters'][0] self.data = cache_cluster_data self.status = self.data['CacheClusterStatus'] diff --git a/plugins/modules/elasticache_info.py b/plugins/modules/elasticache_info.py index 5b22c5cec1c..026337e3350 100644 --- a/plugins/modules/elasticache_info.py +++ b/plugins/modules/elasticache_info.py @@ -225,6 +225,7 @@ from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 boto3_tag_list_to_ansible_dict @@ -243,12 +244,8 @@ def describe_cache_clusters_with_backoff(client, cluster_id=None): params['CacheClusterId'] = cluster_id try: response = paginator.paginate(**params).build_full_result() - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'CacheClusterNotFound': - return [] - raise - except botocore.exceptions.BotoCoreError: - raise + except is_boto3_error_code('CacheClusterNotFound'): + return [] return response['CacheClusters'] diff --git a/plugins/modules/elasticache_snapshot.py b/plugins/modules/elasticache_snapshot.py index 6fcdc10b144..77c71e1cfb1 100644 --- a/plugins/modules/elasticache_snapshot.py +++ b/plugins/modules/elasticache_snapshot.py @@ -118,6 +118,7 @@ pass # Handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -128,12 +129,11 @@ def create(module, connection, replication_id, cluster_id, name): CacheClusterId=cluster_id, SnapshotName=name) changed = True - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == "SnapshotAlreadyExistsFault": - response = {} - changed = False - else: - module.fail_json_aws(e, msg="Unable to create the snapshot.") + except is_boto3_error_code('SnapshotAlreadyExistsFault'): + response = {} + changed = False + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Unable to create the snapshot.") return response, changed @@ -154,15 +154,14 @@ def delete(module, connection, name): try: response = connection.delete_snapshot(SnapshotName=name) changed = True - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == "SnapshotNotFoundFault": - response = {} - changed = False - elif e.response['Error']['Code'] == "InvalidSnapshotState": - module.fail_json(msg="Error: InvalidSnapshotState. The snapshot is not in an available state or failed state to allow deletion." - "You may need to wait a few minutes.") - else: - module.fail_json_aws(e, msg="Unable to delete the snapshot.") + except is_boto3_error_code('SnapshotNotFoundFault'): + response = {} + changed = False + except is_boto3_error_code('InvalidSnapshotState'): # pylint: disable=duplicate-except + module.fail_json(msg="Error: InvalidSnapshotState. The snapshot is not in an available state or failed state to allow deletion." + "You may need to wait a few minutes.") + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Unable to delete the snapshot.") return response, changed diff --git a/plugins/modules/execute_lambda.py b/plugins/modules/execute_lambda.py index f767ac929d1..ee4f7d2d6ea 100644 --- a/plugins/modules/execute_lambda.py +++ b/plugins/modules/execute_lambda.py @@ -138,6 +138,7 @@ from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code def main(): @@ -208,13 +209,13 @@ def main(): try: response = client.invoke(**invoke_params) - except botocore.exceptions.ClientError as ce: - if ce.response['Error']['Code'] == 'ResourceNotFoundException': - module.fail_json_aws(ce, msg="Could not find Lambda to execute. Make sure " - "the ARN is correct and your profile has " - "permissions to execute this function.") + except is_boto3_error_code('ResourceNotFoundException') as nfe: + module.fail_json_aws(nfe, msg="Could not find Lambda to execute. Make sure " + "the ARN is correct and your profile has " + "permissions to execute this function.") + except botocore.exceptions.ClientError as ce: # pylint: disable=duplicate-except module.fail_json_aws(ce, msg="Client-side error when invoking Lambda, check inputs and specific error") - except botocore.exceptions.ParamValidationError as ve: + except botocore.exceptions.ParamValidationError as ve: # pylint: disable=duplicate-except module.fail_json_aws(ve, msg="Parameters to `invoke` failed to validate") except Exception as e: module.fail_json_aws(e, msg="Unexpected failure while invoking Lambda function") diff --git a/plugins/modules/iam_group.py b/plugins/modules/iam_group.py index 45b6eb1d5ed..ec4af5f8cfb 100644 --- a/plugins/modules/iam_group.py +++ b/plugins/modules/iam_group.py @@ -183,6 +183,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code 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 AWSRetry @@ -386,11 +387,8 @@ def get_group(connection, module, name): try: paginator = connection.get_paginator('get_group') return paginator.paginate(GroupName=name).build_full_result() - except ClientError as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - return None - else: - raise + except is_boto3_error_code('NoSuchEntity'): + return None @AWSRetry.exponential_backoff() @@ -399,11 +397,8 @@ def get_attached_policy_list(connection, module, name): try: paginator = connection.get_paginator('list_attached_group_policies') return paginator.paginate(GroupName=name).build_full_result()['AttachedPolicies'] - except ClientError as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - return None - else: - raise + except is_boto3_error_code('NoSuchEntity'): + return None def main(): diff --git a/plugins/modules/iam_managed_policy.py b/plugins/modules/iam_managed_policy.py index 992732de6ef..00900d79ee0 100644 --- a/plugins/modules/iam_managed_policy.py +++ b/plugins/modules/iam_managed_policy.py @@ -139,6 +139,7 @@ from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 camel_dict_to_snake_dict from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies @@ -200,16 +201,14 @@ def get_or_create_policy_version(module, iam, policy, policy_document): try: version = iam.create_policy_version(PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion'] return version, True - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'LimitExceeded': - delete_oldest_non_default_version(module, iam, policy) - try: - version = iam.create_policy_version(PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion'] - return version, True - except botocore.exceptions.ClientError as second_e: - e = second_e - # Handle both when the exception isn't LimitExceeded or - # the second attempt still failed + except is_boto3_error_code('LimitExceeded'): + delete_oldest_non_default_version(module, iam, policy) + try: + version = iam.create_policy_version(PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion'] + return version, True + except botocore.exceptions.ClientError as second_e: + module.fail_json_aws(second_e, msg="Couldn't create policy version") + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Couldn't create policy version") diff --git a/plugins/modules/iam_password_policy.py b/plugins/modules/iam_password_policy.py index d654a846cfd..24b85768e8e 100644 --- a/plugins/modules/iam_password_policy.py +++ b/plugins/modules/iam_password_policy.py @@ -104,6 +104,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -169,11 +170,10 @@ def update_password_policy(self, module, policy): def delete_password_policy(self, policy): try: results = policy.delete() - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - self.module.exit_json(changed=False, task_status={'IAM': "Couldn't find IAM Password Policy"}) - else: - self.module.fail_json_aws(e, msg="Couldn't delete IAM Password Policy") + except is_boto3_error_code('NoSuchEntity'): + self.module.exit_json(changed=False, task_status={'IAM': "Couldn't find IAM Password Policy"}) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except + self.module.fail_json_aws(e, msg="Couldn't delete IAM Password Policy") return camel_dict_to_snake_dict(results) diff --git a/plugins/modules/iam_policy_info.py b/plugins/modules/iam_policy_info.py index 24bcb6928cf..f03928ad3e9 100644 --- a/plugins/modules/iam_policy_info.py +++ b/plugins/modules/iam_policy_info.py @@ -87,6 +87,7 @@ from ansible.module_utils.six import string_types from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code class PolicyError(Exception): @@ -205,9 +206,9 @@ def main(): policy = GroupPolicy(**args) module.exit_json(**(policy.run())) - except (BotoCoreError, ClientError) as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - module.exit_json(changed=False, msg=e.response['Error']['Message']) + except is_boto3_error_code('NoSuchEntity') as e: + module.exit_json(changed=False, msg=e.response['Error']['Message']) + except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e) except PolicyError as e: module.fail_json(msg=str(e)) diff --git a/plugins/modules/iam_role.py b/plugins/modules/iam_role.py index 089d6168e8e..b5e80ceac43 100644 --- a/plugins/modules/iam_role.py +++ b/plugins/modules/iam_role.py @@ -200,6 +200,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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_tag_list from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict @@ -470,14 +471,11 @@ def create_instance_profiles(connection, module, params, role): # Make sure an instance profile is created try: connection.create_instance_profile(InstanceProfileName=params['RoleName'], Path=params['Path'], aws_retry=True) - except ClientError as e: + except is_boto3_error_code('EntityAlreadyExists'): # If the profile already exists, no problem, move on. # Implies someone's changing things at the same time... - if e.response['Error']['Code'] == 'EntityAlreadyExists': - return False - else: - module.fail_json_aws(e, msg="Unable to create instance profile for role {0}".format(params['RoleName'])) - except BotoCoreError as e: + return False + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Unable to create instance profile for role {0}".format(params['RoleName'])) # And attach the role to the profile @@ -553,12 +551,9 @@ def get_role_with_backoff(connection, module, name): def get_role(connection, module, name): try: return connection.get_role(RoleName=name, aws_retry=True)['Role'] - except ClientError as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - return None - else: - module.fail_json_aws(e, msg="Unable to get role {0}".format(name)) - except BotoCoreError as e: + except is_boto3_error_code('NoSuchEntity'): + return None + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Unable to get role {0}".format(name)) diff --git a/plugins/modules/iam_role_info.py b/plugins/modules/iam_role_info.py index 197ef9149f5..a050204b6b1 100644 --- a/plugins/modules/iam_role_info.py +++ b/plugins/modules/iam_role_info.py @@ -153,6 +153,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 boto3_tag_list_to_ansible_dict from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -210,12 +211,9 @@ def describe_iam_roles(module, client): if name: try: roles = [client.get_role(RoleName=name)['Role']] - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - return [] - else: - module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name) - except botocore.exceptions.BotoCoreError as e: + except is_boto3_error_code('NoSuchEntity'): + return [] + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name) else: params = dict() diff --git a/plugins/modules/iam_user.py b/plugins/modules/iam_user.py index dd6a36b47d3..79cc40e6621 100644 --- a/plugins/modules/iam_user.py +++ b/plugins/modules/iam_user.py @@ -113,6 +113,7 @@ from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -304,34 +305,31 @@ def get_user(connection, module, name): try: return connection.get_user(**params) - except ClientError as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - return None - else: - module.fail_json(msg="Unable to get user {0}: {1}".format(name, to_native(e)), - **camel_dict_to_snake_dict(e.response)) + except is_boto3_error_code('NoSuchEntity'): + return None + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json(msg="Unable to get user {0}: {1}".format(name, to_native(e)), + **camel_dict_to_snake_dict(e.response)) def get_attached_policy_list(connection, module, name): try: return connection.list_attached_user_policies(UserName=name)['AttachedPolicies'] - except ClientError as e: - if e.response['Error']['Code'] == 'NoSuchEntity': - return None - else: - module.fail_json_aws(e, msg="Unable to get policies for user {0}".format(name)) + except is_boto3_error_code('NoSuchEntity'): + return None + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Unable to get policies for user {0}".format(name)) def delete_user_login_profile(connection, module, user_name): try: return connection.delete_login_profile(UserName=user_name) - except ClientError as e: - if e.response["Error"]["Code"] == "NoSuchEntity": - return None - else: - module.fail_json_aws(e, msg="Unable to delete login profile for user {0}".format(user_name)) + except is_boto3_error_code('NoSuchEntity'): + return None + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Unable to delete login profile for user {0}".format(user_name)) def main(): diff --git a/plugins/modules/lambda_alias.py b/plugins/modules/lambda_alias.py index bd547a41341..5df562a9c6b 100644 --- a/plugins/modules/lambda_alias.py +++ b/plugins/modules/lambda_alias.py @@ -145,11 +145,12 @@ try: import boto3 - from botocore.exceptions import ClientError, ParamValidationError, MissingParametersError + from botocore.exceptions import ClientError, BotoCoreError except ImportError: pass # Handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn 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 get_aws_connection_info @@ -183,7 +184,7 @@ def __init__(self, ansible_obj, resources, boto3_=True): if not self.region: self.region = self.resource_client['lambda'].meta.region_name - except (ClientError, ParamValidationError, MissingParametersError) as e: + except (ClientError, BotoCoreError) as e: ansible_obj.fail_json(msg="Unable to connect, authorize or access resource: {0}".format(e)) try: @@ -270,12 +271,10 @@ def get_lambda_alias(module, aws): # check if alias exists and get facts try: results = client.get_alias(**api_params) - - except (ClientError, ParamValidationError, MissingParametersError) as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - results = None - else: - module.fail_json(msg='Error retrieving function alias: {0}'.format(e)) + except is_boto3_error_code('ResourceNotFoundException'): + results = None + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg='Error retrieving function alias') return results @@ -315,7 +314,7 @@ def lambda_alias(module, aws): if not module.check_mode: try: results = client.update_alias(**api_params) - except (ClientError, ParamValidationError, MissingParametersError) as e: + except (ClientError, BotoCoreError) as e: module.fail_json(msg='Error updating function alias: {0}'.format(e)) else: @@ -326,7 +325,7 @@ def lambda_alias(module, aws): if not module.check_mode: results = client.create_alias(**api_params) changed = True - except (ClientError, ParamValidationError, MissingParametersError) as e: + except (ClientError, BotoCoreError) as e: module.fail_json(msg='Error creating function alias: {0}'.format(e)) else: # state = 'absent' @@ -338,7 +337,7 @@ def lambda_alias(module, aws): if not module.check_mode: results = client.delete_alias(**api_params) changed = True - except (ClientError, ParamValidationError, MissingParametersError) as e: + except (ClientError, BotoCoreError) as e: module.fail_json(msg='Error deleting function alias: {0}'.format(e)) return dict(changed=changed, **dict(results or facts)) diff --git a/plugins/modules/lambda_facts.py b/plugins/modules/lambda_facts.py index 599611531ff..4b591073a85 100644 --- a/plugins/modules/lambda_facts.py +++ b/plugins/modules/lambda_facts.py @@ -99,6 +99,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -146,11 +147,10 @@ def alias_details(client, module): params['Marker'] = module.params.get('next_marker') try: lambda_facts.update(aliases=client.list_aliases(FunctionName=function_name, **params)['Aliases']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_facts.update(aliases=[]) - else: - module.fail_json_aws(e, msg="Trying to get aliases") + except is_boto3_error_code('ResourceNotFoundException'): + lambda_facts.update(aliases=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get aliases") else: module.fail_json(msg='Parameter function_name required for query=aliases.') @@ -200,11 +200,10 @@ def config_details(client, module): if function_name: try: lambda_facts.update(client.get_function_configuration(FunctionName=function_name)) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_facts.update(function={}) - else: - module.fail_json_aws(e, msg="Trying to get {0} configuration".format(function_name)) + except is_boto3_error_code('ResourceNotFoundException'): + lambda_facts.update(function={}) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get {0} configuration".format(function_name)) else: params = dict() if module.params.get('max_items'): @@ -215,11 +214,10 @@ def config_details(client, module): try: lambda_facts.update(function_list=client.list_functions(**params)['Functions']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_facts.update(function_list=[]) - else: - module.fail_json_aws(e, msg="Trying to get function list") + except is_boto3_error_code('ResourceNotFoundException'): + lambda_facts.update(function_list=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get function list") functions = dict() for func in lambda_facts.pop('function_list', []): @@ -256,11 +254,10 @@ def mapping_details(client, module): try: lambda_facts.update(mappings=client.list_event_source_mappings(**params)['EventSourceMappings']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_facts.update(mappings=[]) - else: - module.fail_json_aws(e, msg="Trying to get source event mappings") + except is_boto3_error_code('ResourceNotFoundException'): + lambda_facts.update(mappings=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get source event mappings") if function_name: return {function_name: camel_dict_to_snake_dict(lambda_facts)} @@ -287,11 +284,10 @@ def policy_details(client, module): try: # get_policy returns a JSON string so must convert to dict before reassigning to its key lambda_facts.update(policy=json.loads(client.get_policy(FunctionName=function_name)['Policy'])) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_facts.update(policy={}) - else: - module.fail_json_aws(e, msg="Trying to get {0} policy".format(function_name)) + except is_boto3_error_code('ResourceNotFoundException'): + lambda_facts.update(policy={}) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get {0} policy".format(function_name)) else: module.fail_json(msg='Parameter function_name required for query=policy.') @@ -320,11 +316,10 @@ def version_details(client, module): try: lambda_facts.update(versions=client.list_versions_by_function(FunctionName=function_name, **params)['Versions']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_facts.update(versions=[]) - else: - module.fail_json_aws(e, msg="Trying to get {0} versions".format(function_name)) + except is_boto3_error_code('ResourceNotFoundException'): + lambda_facts.update(versions=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get {0} versions".format(function_name)) else: module.fail_json(msg='Parameter function_name required for query=versions.') diff --git a/plugins/modules/lambda_info.py b/plugins/modules/lambda_info.py index 59f3e98c0cc..9b39863d663 100644 --- a/plugins/modules/lambda_info.py +++ b/plugins/modules/lambda_info.py @@ -88,6 +88,7 @@ pass # caught by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -135,11 +136,10 @@ def alias_details(client, module): params['Marker'] = module.params.get('next_marker') try: lambda_info.update(aliases=client.list_aliases(FunctionName=function_name, **params)['Aliases']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_info.update(aliases=[]) - else: - module.fail_json_aws(e, msg="Trying to get aliases") + except is_boto3_error_code('ResourceNotFoundException'): + lambda_info.update(aliases=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get aliases") else: module.fail_json(msg='Parameter function_name required for query=aliases.') @@ -189,11 +189,10 @@ def config_details(client, module): if function_name: try: lambda_info.update(client.get_function_configuration(FunctionName=function_name)) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_info.update(function={}) - else: - module.fail_json_aws(e, msg="Trying to get {0} configuration".format(function_name)) + except is_boto3_error_code('ResourceNotFoundException'): + lambda_info.update(function={}) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get {0} configuration".format(function_name)) else: params = dict() if module.params.get('max_items'): @@ -204,11 +203,10 @@ def config_details(client, module): try: lambda_info.update(function_list=client.list_functions(**params)['Functions']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_info.update(function_list=[]) - else: - module.fail_json_aws(e, msg="Trying to get function list") + except is_boto3_error_code('ResourceNotFoundException'): + lambda_info.update(function_list=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get function list") functions = dict() for func in lambda_info.pop('function_list', []): @@ -245,11 +243,10 @@ def mapping_details(client, module): try: lambda_info.update(mappings=client.list_event_source_mappings(**params)['EventSourceMappings']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_info.update(mappings=[]) - else: - module.fail_json_aws(e, msg="Trying to get source event mappings") + except is_boto3_error_code('ResourceNotFoundException'): + lambda_info.update(mappings=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get source event mappings") if function_name: return {function_name: camel_dict_to_snake_dict(lambda_info)} @@ -276,11 +273,10 @@ def policy_details(client, module): try: # get_policy returns a JSON string so must convert to dict before reassigning to its key lambda_info.update(policy=json.loads(client.get_policy(FunctionName=function_name)['Policy'])) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_info.update(policy={}) - else: - module.fail_json_aws(e, msg="Trying to get {0} policy".format(function_name)) + except is_boto3_error_code('ResourceNotFoundException'): + lambda_info.update(policy={}) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get {0} policy".format(function_name)) else: module.fail_json(msg='Parameter function_name required for query=policy.') @@ -309,11 +305,10 @@ def version_details(client, module): try: lambda_info.update(versions=client.list_versions_by_function(FunctionName=function_name, **params)['Versions']) - except ClientError as e: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - lambda_info.update(versions=[]) - else: - module.fail_json_aws(e, msg="Trying to get {0} versions".format(function_name)) + except is_boto3_error_code('ResourceNotFoundException'): + lambda_info.update(versions=[]) + except ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Trying to get {0} versions".format(function_name)) else: module.fail_json(msg='Parameter function_name required for query=versions.') diff --git a/plugins/modules/lambda_policy.py b/plugins/modules/lambda_policy.py index 2fb4b4ddead..6f17ce34519 100644 --- a/plugins/modules/lambda_policy.py +++ b/plugins/modules/lambda_policy.py @@ -134,14 +134,16 @@ import json import re -from ansible.module_utils._text import to_native -from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule try: - from botocore.exceptions import ClientError + from botocore.exceptions import ClientError, BotoCoreError except ImportError: pass # caught by AnsibleAWSModule +from ansible.module_utils._text import to_native +from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code + def pc(key): """ @@ -285,14 +287,9 @@ def get_policy_statement(module, client): # check if function policy exists try: policy_results = client.get_policy(**api_params) - except ClientError as e: - try: - if e.response['Error']['Code'] == 'ResourceNotFoundException': - return {} - except AttributeError: # catches ClientErrors without response, e.g. fail before connect - pass - module.fail_json_aws(e, msg="retrieving function policy") - except Exception as e: + except is_boto3_error_code('ResourceNotFoundException'): + return {} + except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="retrieving function policy") # get_policy returns a JSON string so must convert to dict before reassigning to its key @@ -328,7 +325,7 @@ def add_policy_permission(module, client): if not module.check_mode: try: client.add_permission(**api_params) - except Exception as e: + except (ClientError, BotoCoreError) as e: module.fail_json_aws(e, msg="adding permission to policy") changed = True @@ -356,7 +353,7 @@ def remove_policy_permission(module, client): if not module.check_mode: client.remove_permission(**api_params) changed = True - except Exception as e: + except (ClientError, BotoCoreError) as e: module.fail_json_aws(e, msg="removing permission from policy") return changed diff --git a/plugins/modules/lightsail.py b/plugins/modules/lightsail.py index 4be2fc3f458..699582b857d 100644 --- a/plugins/modules/lightsail.py +++ b/plugins/modules/lightsail.py @@ -161,6 +161,7 @@ pass from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -168,9 +169,11 @@ def find_instance_info(module, client, instance_name, fail_if_not_found=False): try: res = client.get_instance(instanceName=instance_name) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'NotFoundException' and not fail_if_not_found: - return None + except is_boto3_error_code('NotFoundException') as e: + if fail_if_not_found: + module.fail_json_aws(e) + return None + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except module.fail_json_aws(e) return res['instance'] diff --git a/plugins/modules/rds_param_group.py b/plugins/modules/rds_param_group.py index 0cec5252d9f..77f7cd7a307 100644 --- a/plugins/modules/rds_param_group.py +++ b/plugins/modules/rds_param_group.py @@ -123,6 +123,7 @@ from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code 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 compare_aws_tags from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list @@ -234,11 +235,10 @@ def ensure_present(module, connection): errors = [] try: response = connection.describe_db_parameter_groups(DBParameterGroupName=groupname) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'DBParameterGroupNotFound': - response = None - else: - module.fail_json_aws(e, msg="Couldn't access parameter group information") + except is_boto3_error_code('DBParameterGroupNotFound'): + response = None + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Couldn't access parameter group information") if not response: params = dict(DBParameterGroupName=groupname, DBParameterGroupFamily=module.params['engine'], @@ -277,11 +277,10 @@ def ensure_absent(module, connection): group = module.params['name'] try: response = connection.describe_db_parameter_groups(DBParameterGroupName=group) - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'DBParameterGroupNotFound': - module.exit_json(changed=False) - else: - module.fail_json_aws(e, msg="Couldn't access parameter group information") + except is_boto3_error_code('DBParameterGroupNotFound'): + module.exit_json(changed=False) + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Couldn't access parameter group information") try: response = connection.delete_db_parameter_group(DBParameterGroupName=group) module.exit_json(changed=True) diff --git a/plugins/modules/s3_lifecycle.py b/plugins/modules/s3_lifecycle.py index a2518a88570..0319d78ce12 100644 --- a/plugins/modules/s3_lifecycle.py +++ b/plugins/modules/s3_lifecycle.py @@ -207,6 +207,7 @@ pass # handled by AnsibleAwsModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code def create_lifecycle_rule(client, module): @@ -232,12 +233,9 @@ def create_lifecycle_rule(client, module): try: current_lifecycle = client.get_bucket_lifecycle_configuration(Bucket=name) current_lifecycle_rules = current_lifecycle['Rules'] - except ClientError as e: - if e.response['Error']['Code'] == 'NoSuchLifecycleConfiguration': - current_lifecycle_rules = [] - else: - module.fail_json_aws(e) - except BotoCoreError as e: + except is_boto3_error_code('NoSuchLifecycleConfiguration'): + current_lifecycle_rules = [] + except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e) rule = dict(Filter=dict(Prefix=prefix), Status=status.title()) @@ -396,12 +394,9 @@ def destroy_lifecycle_rule(client, module): # Get the bucket's current lifecycle rules try: current_lifecycle_rules = client.get_bucket_lifecycle_configuration(Bucket=name)['Rules'] - except ClientError as e: - if e.response['Error']['Code'] == 'NoSuchLifecycleConfiguration': - current_lifecycle_rules = [] - else: - module.fail_json_aws(e) - except BotoCoreError as e: + except is_boto3_error_code('NoSuchLifecycleConfiguration'): + current_lifecycle_rules = [] + except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e) # Create lifecycle diff --git a/plugins/modules/sqs_queue.py b/plugins/modules/sqs_queue.py index 4c2911a5c38..bb714c498a8 100644 --- a/plugins/modules/sqs_queue.py +++ b/plugins/modules/sqs_queue.py @@ -226,6 +226,7 @@ pass # handled by AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +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 camel_dict_to_snake_dict from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags @@ -245,10 +246,8 @@ def get_queue_name(module, is_fifo=False): def get_queue_url(client, name): try: return client.get_queue_url(QueueName=name)['QueueUrl'] - except ClientError as e: - if e.response['Error']['Code'] == 'AWS.SimpleQueueService.NonExistentQueue': - return None - raise + except is_boto3_error_code('AWS.SimpleQueueService.NonExistentQueue'): + return None def describe_queue(client, queue_url):