def test_non_throttle_error(): """Assert SWF error is evaluated as non-throttle error properly. """ exception = exceptions.ClientError( {'Error': { 'Code': 'ThrottlingException' }}, 'operationName') result = utils.non_throttle_error(exception) assert not utils.non_throttle_error(exception) exception = exceptions.ClientError({'Error': { 'Code': 'RateExceeded' }}, 'operationName') assert utils.non_throttle_error(exception)
def describe_stack(stack_name, session=None): """Performs describe_stack on the provided stack name http://boto3.readthedocs.io/en/latest/reference/services/cloudformation.html#CloudFormation.Client.describe_stacks Args: stack_name (str): Name of the stack to describe session (object, optional): boto3 session object Returns: dict: Standard AWS dictionary with stack details """ client = boto3_client(service='cloudformation', session=session) try: logger.info(f"Getting details about CloudFormation Stack:{stack_name}") response = client.describe_stacks(StackName=stack_name) return response except ex.ClientError as e: if str(e).endswith(" does not exist"): logger.warning(f"Stack, {stack_name} does not exist...") # return False else: raise ex.ClientError( f"Failed to lookup stack {stack_name}: {str(e)}") except Exception as e: logger.warning(f"describe_stack error:{str(e)}")
def describe_stack_events(stack_name, session=None): """Performs describe_stack_events on the provided stack name http://boto3.readthedocs.io/en/latest/reference/services/cloudformation.html#CloudFormation.Client.describe_stack_events Args: stack_name (str): Name of the stack to describe session (object, optional): boto3 session object Returns: dict: Standard AWS dictionary with stack event details """ client = boto3_client(service='cloudformation', session=session) try: response = client.describe_stack_events(StackName=stack_name) return response except ex.ClientError as e: if str(e).endswith(" does not exist"): raise ex.NotFoundException( f"Could not find stack with name {stack_name}") else: raise ex.ClientError( f"Failed to lookup stack events for {stack_name}: {str(e)}")
def test_bucket_exists_not_found(self): self.s3.client.head_bucket.side_effect = \ exceptions.ClientError({'Error': {'Code': '404'}}, 'HeadBucket') with self.assertRaises(S3BucketNotFoundException) as context: self.s3._bucket_exists() self.assertEqual('Bucket \"bucket\" does not exist.', str(context.exception))
def test_bucket_exists_exception(self): self.s3.client.head_bucket.side_effect = \ exceptions.ClientError({'Error': {'Code': ''}}, '') with self.assertRaises(S3BucketException) as context: self.s3._bucket_exists() self.assertEqual('An error occurred when accessing bucket \"bucket\".', str(context.exception))
def test_get_url_for_download_unknown_error(self): exc = boto_exc.ClientError(error_response={}, operation_name='foo') exc.response['Error'] = {'Code': 'UncaughtError'} self.manager.client.get_object_tagging.side_effect = exc self.assertRaises(exceptions.AssetError, self.manager.get_url_for_download, 'foo_asset_id', 50)
def roleback_policy(policy_name, iam_client=None, logger=None): if iam_client is None: iam_client = boto3.client('iam') if logger is None: logger = core.set_logger() policy = get_policy_arn_default_version(policy_name) if policy is not None: arn = policy['arn'] else: error_response = { "Error": { "Code": "404", "Message": "No policy with name %s found" % policy_name } } raise boto_exceptions.ClientError(error_response, "roleback_policy") response = iam_client.list_policy_versions(PolicyArn=arn) non_default_versions = [ version for version in response['Versions'] if version['IsDefaultVersion'] is not True ] non_default_versions_sorted = sorted(non_default_versions, key=lambda v: v['VersionId'], reverse=True) newest_non_default_version_id = non_default_versions_sorted[0]['VersionId'] logger.info("Rolling back policy %s to newest previous version %s" % (policy_name, newest_non_default_version_id)) iam_client.set_default_policy_version( PolicyArn=arn, VersionId=newest_non_default_version_id)
def test_bucket_exists_forbidden(self): self.s3.client.head_bucket.side_effect = \ exceptions.ClientError({'Error': {'Code': '403'}}, 'HeadBucket') with self.assertRaises(S3BucketForbiddenException) as context: self.s3._bucket_exists() self.assertEqual( 'Permissions are not granted to access bucket \"bucket\".', str(context.exception))
def test_timed_out(self, task, session_mock): """Task timed-out.""" exc = bc_exc.ClientError( {"Error": { "Code": "TaskTimedOut", "Message": "spambla42" }}, "sendTaskHeartbeat") task._send = mock.Mock(side_effect=exc) task._send_heartbeat() assert task._request_stop is True
def test_no_exist(self, task, session_mock): """Task doesn't exist.""" exc = bc_exc.ClientError({"Error": { "Code": "TaskDoesNotExist" }}, "sendTaskHeartbeat") task._send = mock.Mock(side_effect=exc) with pytest.raises(bc_exc.ClientError) as e: task._send_heartbeat() assert e.value is exc assert task._request_stop is True
def test_stack_exists_false(self): self.patch_stack_exists.stop() self.cfn.client.describe_stacks.side_effect = \ exceptions.ClientError( error_response={'Error': { 'Code': 'Code', 'Message': 'Message' }}, operation_name='Operation' ) self.assertFalse(self.cfn.stack_exists('stack_name'))
def test_retry_info_added_when_present(): response = { 'Error': {}, 'ResponseMetadata': { 'MaxAttemptsReached': True, 'RetryAttempts': 3, } } error_msg = str(exceptions.ClientError(response, 'operation')) if '(reached max retries: 3)' not in error_msg: raise AssertionError("retry information not inject into error " "message: %s" % error_msg)
def test_skunky_put_identity_dynamodb_false(self, session_mock): response = {'Error': {'Code': "ConditionalCheckFailedException"}} dynamodb_table_mock = Mock() dynamodb_table_mock.put_item.side_effect = exceptions.ClientError( response, 'put_item') testSkunky = Skunky(session_mock) testSkunky.dynamodb_table = dynamodb_table_mock self.assertFalse(testSkunky.put(TEST_IDENTITY_1_A_US_WEST_2))
def test_poll_for_activity_throttle_retry(monkeypatch, poll, boto_client): """Test that SWF throttles are retried during polling. """ current_activity = activity_run(monkeypatch, boto_client, poll) boto_client.poll_for_activity_task.side_effect = exceptions.ClientError( {'Error': { 'Code': 'ThrottlingException' }}, 'operation name') with pytest.raises(exceptions.ClientError): current_activity.poll_for_activity() assert boto_client.poll_for_activity_task.call_count == 5
def test_load_file_with_failing_ssm_request(mocker): mocked_client = mocker.Mock() mocked_client.get_parameter.side_effect = boto_exceptions.ClientError( {'Error': { 'Code': 'Unauthorised' }}, 'get') mocked_boto = mocker.patch('ssm_config.config.boto3') mocked_boto.client.return_value = mocked_client with pytest.raises(boto_exceptions.ClientError): load(""" prod: path: <%= SSM['/prod/unknown_param'] %> """)
def test_retry_info_not_added_if_retry_attempts_not_present(): response = { 'Error': {}, 'ResponseMetadata': { 'MaxAttemptsReached': True, } } # Because RetryAttempts is missing, retry info is not # in the error message. error_msg = str(exceptions.ClientError(response, 'operation')) if 'max retries' in error_msg: raise AssertionError("Retry information should not be in exception " "message when retry attempts not in response " "metadata: %s" % error_msg)
def test_can_handle_when_response_missing_error_key(): response = { 'ResponseMetadata': { 'HTTPHeaders': {}, 'HTTPStatusCode': 503, 'MaxAttemptsReached': True, 'RetryAttempts': 4 } } e = exceptions.ClientError(response, 'SomeOperation') if 'An error occurred (Unknown)' not in str(e): raise AssertionError("Error code should default to 'Unknown' " "when missing error response, instead got: %s" % str(e))
def test_load_file_with_invalid_ssm_value(mocker): mocked_client = mocker.Mock() mocked_client.get_parameter.side_effect = boto_exceptions.ClientError( {'Error': { 'Code': 'ParameterNotFound' }}, 'get') mocked_boto = mocker.patch('ssm_config.config.boto3') mocked_boto.client.return_value = mocked_client with pytest.raises(ValueError): load(""" prod: path: <%= SSM['/prod/unknown_param'] %> """)
def test_execute_error(self): @tools.screen_all_logs def do_check(ex, status, code, message): self.controller.reset_mock() self.controller.fake_action.side_effect = ex res = self.request.send(self.application) self.assertEqual(status, res.status_code) self.assertEqual('text/xml', res.content_type) expected_xml = fakes.XML_ERROR_TEMPLATE % { 'code': code, 'message': message, 'request_id': self.fake_context.request_id } self.assertThat(res.body.decode("utf-8"), matchers.XMLMatches(expected_xml)) self.controller.fake_action.assert_called_once_with( self.fake_context, param='fake_param') do_check(exception.EC2Exception('fake_msg'), 400, 'EC2Exception', 'fake_msg') do_check(KeyError('fake_msg'), 500, 'KeyError', 'Unknown error occurred.') do_check(exception.InvalidVpcIDNotFound('fake_msg'), 400, 'InvalidVpcID.NotFound', 'fake_msg') do_check(nova_exception.BadRequest(400, message='fake_msg'), 400, 'BadRequest', 'fake_msg') do_check(glance_exception.HTTPBadRequest(), 400, 'HTTPBadRequest', 'HTTP HTTPBadRequest') do_check(cinder_exception.BadRequest(400, message='fake_msg'), 400, 'BadRequest', 'fake_msg') do_check(neutron_exception.BadRequest(message='fake_msg'), 400, 'BadRequest', 'fake_msg') do_check(keystone_exception.BadRequest(message='fake_msg'), 400, 'BadRequest', 'fake_msg (HTTP 400)') do_check( botocore_exceptions.ClientError( { 'Error': { 'Code': '', 'Message': '' }, 'Code': 'FakeCode', 'Message': 'fake_msg' }, 'register_image'), 400, 'FakeCode', 'fake_msg')
def test_change_resource_record_sets_delete_failed_cert_not_found(self): self.mock_request.resource_properties = { 'CertificateArn': self.certificate_arn } self.mock_get_domain_validation_options.side_effect = \ exceptions.ClientError( error_response={'Error': { 'Code': 'ResourceNotFoundException', 'Message': 'Message' }}, operation_name='Operation' ) cv = CertificateValidator(self.mock_request, self.mock_response) cv.change_resource_record_sets(self.certificate_arn, Action.DELETE) self.mock_response.set_status.assert_called_with(success=True) self.mock_response.set_reason.assert_called_with( reason='Certificate not found.' )
def test_change_resource_record_sets_delete_failed(self): self.mock_request.resource_properties = { 'CertificateArn': self.certificate_arn } self.mock_get_domain_validation_options.side_effect = \ exceptions.ClientError( error_response={'Error': { 'Code': 'Code', 'Message': 'Message' }}, operation_name='Operation' ) cv = CertificateValidator(self.mock_request, self.mock_response) cv.change_resource_record_sets(self.certificate_arn, Action.DELETE) self.mock_response.set_status.assert_called_with(success=False) reason = \ 'An error occurred (Code) when calling the Operation operation: ' \ 'Message' self.mock_response.set_reason.assert_called_with(reason=reason)
def test_create_failed(self): c = Certificate(self.request, self.mock_response) self.mock_request_certificate.side_effect = exceptions.ClientError( error_response={'Error': { 'Code': 'Code', 'Message': 'Message' }}, operation_name='Operation' ) c.create() self.mock_request_certificate.assert_called_with( domain_name='certificate-validator.com', subject_alternative_names=['www.certificate-validator.com'], ) self.mock_response.set_status.assert_called_with(success=False) reason = \ 'An error occurred (Code) when calling the Operation operation: ' \ 'Message' self.mock_response.set_reason.assert_called_with(reason=reason)
def test_delete_failed(self): self.mock_request.physical_resource_id = \ 'arn:aws:acm:us-east-1:123:certificate/1337' c = Certificate(self.mock_request, self.mock_response) self.mock_delete_certificate.side_effect = exceptions.ClientError( error_response={'Error': { 'Code': 'Code', 'Message': 'Message' }}, operation_name='Operation' ) c.delete() self.mock_delete_certificate.assert_called_with( certificate_arn='arn:aws:acm:us-east-1:123:certificate/1337' ) self.mock_response.set_status.assert_called_with(success=False) reason = \ 'An error occurred (Code) when calling the Operation operation: ' \ 'Message' self.mock_response.set_reason.assert_called_with(reason=reason)
def test_delete_success_certificate_not_found(self): self.mock_request.physical_resource_id = \ 'arn:aws:acm:us-east-1:123:certificate/1337' self.mock_delete_certificate.side_effect = exceptions.ClientError( error_response={ 'Error': { 'Code': 'ResourceNotFoundException', 'Message': 'Message' } }, operation_name='Operation' ) c = Certificate(self.mock_request, self.mock_response) c.delete() self.mock_delete_certificate.assert_called_with( certificate_arn='arn:aws:acm:us-east-1:123:certificate/1337' ) self.mock_response.set_status.assert_called_with(success=True) self.mock_response.set_reason.assert_called_with( reason='Certificate not found.' )
def validate_template(template, session=None): """Performs template validation on the provided template body. http://boto3.readthedocs.io/en/latest/reference/services/cloudformation.html#CloudFormation.Client.validate_template Args: template (str): Body of a CFN template file, should already have been read in using helper.load_file(file) session (object, optional): boto3 session object Returns: dict: Standard AWS dictionary with validation results, raises exception if template is invalid """ logger.info("Validating CloudFormation Template") client = boto3_client(service='cloudformation', session=session) try: response = client.validate_template(TemplateBody=template) return response except ex.ClientError as e: raise ex.ClientError( f"CloudFormation template validation failed: {str(e)}")
def delete_all_versions_of_policy(policy_name, iam_client=None, logger=None): if iam_client is None: iam_client = boto3.client('iam') if logger is None: logger = core.set_logger() logger.info("Completely deleting poilcy %s and all its versions" % policy_name) policy = get_policy_arn_default_version(policy_name, iam_client) if policy['arn'] is not None: attached_to_roles = get_role_names_policy_attached_to( policy_name, iam_client) if attached_to_roles is not None: for role_name in attached_to_roles: logger.debug("Detatching policy %s from role %s" % (policy_name, role_name)) iam_client.detach_role_policy(RoleName=role_name, PolicyArn=policy['arn']) # Remove old versions response = iam_client.list_policy_versions(PolicyArn=policy['arn']) for version in response['Versions']: if version['IsDefaultVersion'] is not True: # TODO error handling needed around this call logger.debug("Deleting version %s of policy %s" % (version['VersionId'], policy_name)) iam_client.delete_policy_version( PolicyArn=policy['arn'], VersionId=version['VersionId']) # Delete policy as should now only have one version logger.debug( "Deleting policy %s now all its versions have been deleted" % policy_name) iam_client.delete_policy(PolicyArn=policy['arn']) else: error_response = { "Error": { "Code": "404", "Message": "No policy with name %s found" % policy_name } } raise boto_exceptions.ClientError(error_response, "delete_all_versions_of_policy")
def test_change_resource_record_sets_delete_failed_rrset_not_found(self): self.mock_request.resource_properties = { 'CertificateArn': self.certificate_arn } message = \ 'Tried to delete resource record set ' \ '[name=\'_x1.certificate-validator.com.\', type=\'CNAME\'] but ' \ 'it was not found' self.mock_get_domain_validation_options.side_effect = \ exceptions.ClientError( error_response={'Error': { 'Code': 'InvalidChangeBatch', 'Message': message }}, operation_name='Operation' ) cv = CertificateValidator(self.mock_request, self.mock_response) cv.change_resource_record_sets(self.certificate_arn, Action.DELETE) self.mock_response.set_status.assert_called_with(success=True) self.mock_response.set_reason.assert_called_with( reason='Resource Record Set not found.' )
def test_read_auth_profile_raises_exception_if_profile_dne(mocker): from botocore import exceptions # type: ignore req_params: typing.Dict = { "auth_profile": "testProfile", "iam_access_key_id": "testAccessKey", "iam_secret_key": "someSecretKey", "iam_session_token": "someToken", "info": RedshiftProperty(), } req_params["info"].put("region", "us-east-1") mock_redshift_client: MagicMock = MagicMock() mock_redshift_client.describe_authentication_profiles.side_effect = exceptions.ClientError( operation_name="ErrorOp", error_response=MagicMock()) mocker.patch("boto3.client", return_value=mock_redshift_client) with pytest.raises( InterfaceError, match= "Unable to retrieve contents of Redshift authentication profile from server" ): IamHelper.read_auth_profile(**req_params)
def test_update_upload_status_raise_not_found(self): exc = boto_exc.ClientError(error_response={}, operation_name='foo') exc.response['Error'] = {'Code': 'NoSuchKey'} self.manager.client.put_object_tagging.side_effect = exc self.assertRaises(exceptions.AssetNotFoundError, self.manager.update_upload_status, 'foo_asset_id')
def test_update_upload_status_raises(self): self.manager.client.put_object_tagging.side_effect = ( boto_exc.ClientError(error_response={}, operation_name='foo')) self.assertRaises(exceptions.AssetError, self.manager.update_upload_status, 'foo_asset_id')