def modify_elb_attributes(self): """ Update Application ELB attributes if required :return: """ update_attributes = [] if self.access_logs_enabled is not None and str(self.access_logs_enabled).lower() != self.elb_attributes['access_logs_s3_enabled']: update_attributes.append({'Key': 'access_logs.s3.enabled', 'Value': str(self.access_logs_enabled).lower()}) if self.access_logs_s3_bucket is not None and self.access_logs_s3_bucket != self.elb_attributes['access_logs_s3_bucket']: update_attributes.append({'Key': 'access_logs.s3.bucket', 'Value': self.access_logs_s3_bucket}) if self.access_logs_s3_prefix is not None and self.access_logs_s3_prefix != self.elb_attributes['access_logs_s3_prefix']: update_attributes.append({'Key': 'access_logs.s3.prefix', 'Value': self.access_logs_s3_prefix}) if self.deletion_protection is not None and str(self.deletion_protection).lower() != self.elb_attributes['deletion_protection_enabled']: update_attributes.append({'Key': 'deletion_protection.enabled', 'Value': str(self.deletion_protection).lower()}) if self.idle_timeout is not None and str(self.idle_timeout) != self.elb_attributes['idle_timeout_timeout_seconds']: update_attributes.append({'Key': 'idle_timeout.timeout_seconds', 'Value': str(self.idle_timeout)}) if self.http2 is not None and str(self.http2).lower() != self.elb_attributes['routing_http2_enabled']: update_attributes.append({'Key': 'routing.http2.enabled', 'Value': str(self.http2).lower()}) if update_attributes: try: AWSRetry.jittered_backoff()( self.connection.modify_load_balancer_attributes )(LoadBalancerArn=self.elb['LoadBalancerArn'], Attributes=update_attributes) self.changed = True except (BotoCoreError, ClientError) as e: # Something went wrong setting attributes. If this ELB was created during this task, delete it to leave a consistent state if self.new_load_balancer: AWSRetry.jittered_backoff()(self.connection.delete_load_balancer)(LoadBalancerArn=self.elb['LoadBalancerArn']) self.module.fail_json_aws(e)
def call_method(client, module, method_name, parameters): result = {} changed = True if not module.check_mode: wait = module.params['wait'] # TODO: stabilize by adding get_rds_method_attribute(method_name).extra_retry_codes method = getattr(client, method_name) try: if method_name == 'modify_db_instance': # check if instance is in an available state first, if possible if wait: wait_for_status(client, module, module.params['db_instance_identifier'], method_name) result = AWSRetry.jittered_backoff( catch_extra_error_codes=['InvalidDBInstanceState'])( method)(**parameters) else: result = AWSRetry.jittered_backoff()(method)(**parameters) except (BotoCoreError, ClientError) as e: changed = handle_errors(module, e, method_name, parameters) if wait and changed: identifier = get_final_identifier(method_name, module) wait_for_status(client, module, identifier, method_name) return result, changed
def modify_elb_attributes(self): """ Update Network ELB attributes if required :return: """ update_attributes = [] if self.cross_zone_load_balancing is not None and str(self.cross_zone_load_balancing).lower() != \ self.elb_attributes['load_balancing_cross_zone_enabled']: update_attributes.append({'Key': 'load_balancing.cross_zone.enabled', 'Value': str(self.cross_zone_load_balancing).lower()}) if self.deletion_protection is not None and str(self.deletion_protection).lower() != self.elb_attributes['deletion_protection_enabled']: update_attributes.append({'Key': 'deletion_protection.enabled', 'Value': str(self.deletion_protection).lower()}) if update_attributes: try: AWSRetry.jittered_backoff()( self.connection.modify_load_balancer_attributes )(LoadBalancerArn=self.elb['LoadBalancerArn'], Attributes=update_attributes) self.changed = True except (BotoCoreError, ClientError) as e: # Something went wrong setting attributes. If this ELB was created during this task, delete it to leave a consistent state if self.new_load_balancer: AWSRetry.jittered_backoff()(self.connection.delete_load_balancer)(LoadBalancerArn=self.elb['LoadBalancerArn']) self.module.fail_json_aws(e)
def get_account_info(module): """return the account information (account id and partition) we are currently working on get_account_info tries too find out the account that we are working on. It's not guaranteed that this will be easy so we try in several different ways. Giving either IAM or STS privileges to the account should be enough to permit this. """ account_id = None partition = None try: sts_client = module.client('sts', retry_decorator=AWSRetry.jittered_backoff()) caller_id = sts_client.get_caller_identity(aws_retry=True) account_id = caller_id.get('Account') partition = caller_id.get('Arn').split(':')[1] except (BotoCoreError, ClientError): try: iam_client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff()) arn, partition, service, reg, account_id, resource = iam_client.get_user(aws_retry=True)['User']['Arn'].split(':') except is_boto3_error_code('AccessDenied') as e: try: except_msg = to_native(e.message) except AttributeError: except_msg = to_native(e) m = re.search(r"arn:(aws(-([a-z\-]+))?):iam::([0-9]{12,32}):\w+/", except_msg) if m is None: module.fail_json_aws(e, msg="getting account information") account_id = m.group(4) partition = m.group(1) except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg="getting account information") return account_id, partition
def delete(self): """ Delete a listener rule :return: """ try: AWSRetry.jittered_backoff()(self.connection.delete_rule)(RuleArn=self.rule['RuleArn']) except (BotoCoreError, ClientError) as e: self.module.fail_json_aws(e) self.changed = True
def modify(self): try: # Rules is not a valid parameter for modify_listener if 'Rules' in self.listener: self.listener.pop('Rules') AWSRetry.jittered_backoff()(self.connection.modify_listener)(**self.listener) except (BotoCoreError, ClientError) as e: if '"Order", must be one of: Type, TargetGroupArn' in str(e): self.module.fail_json(msg="installed version of botocore does not support " "multiple actions, please upgrade botocore to version " "1.10.30 or higher") else: self.module.fail_json_aws(e)
def modify_security_groups(self): """ Modify elb security groups to match module parameters :return: """ try: AWSRetry.jittered_backoff()( self.connection.set_security_groups )(LoadBalancerArn=self.elb['LoadBalancerArn'], SecurityGroups=self.security_groups) except (BotoCoreError, ClientError) as e: self.module.fail_json_aws(e) self.changed = True
def delete(self): """ Delete elb :return: """ try: AWSRetry.jittered_backoff()( self.connection.delete_load_balancer )(LoadBalancerArn=self.elb['LoadBalancerArn']) except (BotoCoreError, ClientError) as e: self.module.fail_json_aws(e) self.changed = True
def delete_tags(self, tags_to_delete): """ Delete elb tags :return: """ try: AWSRetry.jittered_backoff()( self.connection.remove_tags )(ResourceArns=[self.elb['LoadBalancerArn']], TagKeys=tags_to_delete) except (BotoCoreError, ClientError) as e: self.module.fail_json_aws(e) self.changed = True
def modify_tags(self): """ Modify elb tags :return: """ try: AWSRetry.jittered_backoff()( self.connection.add_tags )(ResourceArns=[self.elb['LoadBalancerArn']], Tags=self.tags) except (BotoCoreError, ClientError) as e: self.module.fail_json_aws(e) self.changed = True
def attach_vgw(client, module, vpn_gateway_id): params = dict() params['VpcId'] = module.params.get('vpc_id') try: # Immediately after a detachment, the EC2 API sometimes will report the VpnGateways[0].State # as available several seconds before actually permitting a new attachment. # So we catch and retry that error. See https://github.com/ansible/ansible/issues/53185 response = AWSRetry.jittered_backoff( retries=5, catch_extra_error_codes=['InvalidParameterValue'])( client.attach_vpn_gateway)(VpnGatewayId=vpn_gateway_id, VpcId=params['VpcId']) except botocore.exceptions.ClientError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) status_achieved, vgw = wait_for_status(client, module, [vpn_gateway_id], 'attached') if not status_achieved: module.fail_json( msg= 'Error waiting for vpc to attach to vgw - please check the AWS console' ) result = response return result
def main(): global module global client argument_spec = dict( policy_name=dict(required=True), policy_description=dict(default=''), policy=dict(type='json'), make_default=dict(type='bool', default=True), only_version=dict(type='bool', default=False), fail_on_delete=dict(type='bool', removed_at_date='2022-06-01', removed_from_collection='community.aws'), state=dict(default='present', choices=['present', 'absent']), ) module = AnsibleAWSModule( argument_spec=argument_spec, required_if=[['state', 'present', ['policy']]], supports_check_mode=True ) name = module.params.get('policy_name') state = module.params.get('state') try: client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff()) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Failed to connect to AWS') existing_policy = get_policy_by_name(name) if state == 'present': create_or_update_policy(existing_policy) else: delete_policy(existing_policy)
def main(): argument_spec = dict(lookup=dict(default='tag', choices=['tag', 'id']), propagating_vgw_ids=dict(type='list', elements='str'), purge_routes=dict(default=True, type='bool'), purge_subnets=dict(default=True, type='bool'), purge_tags=dict(default=False, type='bool'), route_table_id=dict(), routes=dict(default=[], type='list', elements='dict'), state=dict(default='present', choices=['present', 'absent']), subnets=dict(type='list', elements='str'), tags=dict(type='dict', aliases=['resource_tags']), vpc_id=dict()) module = AnsibleAWSModule( argument_spec=argument_spec, required_if=[['lookup', 'id', ['route_table_id']], ['lookup', 'tag', ['vpc_id']], ['state', 'present', ['vpc_id']]], supports_check_mode=True) # The tests for RouteTable existing uses its own decorator, we can safely # retry on InvalidRouteTableID.NotFound retry_decorator = AWSRetry.jittered_backoff( retries=10, catch_extra_error_codes=['InvalidRouteTableID.NotFound']) connection = module.client('ec2', retry_decorator=retry_decorator) state = module.params.get('state') if state == 'present': result = ensure_route_table_present(connection, module) elif state == 'absent': result = ensure_route_table_absent(connection, module) module.exit_json(**result)
def delete_table(current_table): if not current_table: return False if module.check_mode: return True table_name = module.params.get('name') # If an index is mid-update then we have to wait for the update to complete # before deletion will succeed long_retry = AWSRetry.jittered_backoff( retries=45, delay=5, max_delay=30, catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException'], ) try: long_retry(client.delete_table)(TableName=table_name) except is_boto3_error_code('ResourceNotFoundException'): return False except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg='Failed to delete table') if module.params.get('wait'): wait_not_exists() return True
def main(): argument_spec = dict( name=dict(type='str', required=True), state=dict(type='str', default='present', choices=['present', 'absent']), active=dict(type='bool'), force=dict(type='bool', default=False), ) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) state = module.params.get('state') # SES APIs seem to have a much lower throttling threshold than most of the rest of the AWS APIs. # Docs say 1 call per second. This shouldn't actually be a big problem for normal usage, but # the ansible build runs multiple instances of the test in parallel that's caused throttling # failures so apply a jittered backoff to call SES calls. client = module.client('ses', retry_decorator=AWSRetry.jittered_backoff()) if state == 'absent': remove_rule_set(client, module) else: create_or_update_rule_set(client, module)
def main(): module = AnsibleAWSModule( argument_spec={ 'identity': dict(required=True, type='str'), 'state': dict(default='present', choices=['present', 'absent']), 'policy_name': dict(required=True, type='str'), 'policy': dict(type='json', default=None), }, required_if=[['state', 'present', ['policy']]], supports_check_mode=True, ) # SES APIs seem to have a much lower throttling threshold than most of the rest of the AWS APIs. # Docs say 1 call per second. This shouldn't actually be a big problem for normal usage, but # the ansible build runs multiple instances of the test in parallel that's caused throttling # failures so apply a jittered backoff to call SES calls. connection = module.client('ses', retry_decorator=AWSRetry.jittered_backoff()) state = module.params.get("state") if state == 'present': create_or_update_identity_policy(connection, module) else: delete_identity_policy(connection, module)
def main(): argument_spec = dict( db_snapshot_identifier=dict(aliases=['snapshot_name']), db_instance_identifier=dict(), db_cluster_identifier=dict(), db_cluster_snapshot_identifier=dict(), snapshot_type=dict( choices=['automated', 'manual', 'shared', 'public'])) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=[[ 'db_snapshot_identifier', 'db_instance_identifier', 'db_cluster_identifier', 'db_cluster_snapshot_identifier' ]]) if module._name == 'rds_snapshot_facts': module.deprecate( "The 'rds_snapshot_facts' module has been renamed to 'rds_snapshot_info'", date='2021-12-01', collection_name='community.aws') conn = module.client('rds', retry_decorator=AWSRetry.jittered_backoff(retries=10)) results = dict() if not module.params['db_cluster_identifier'] and not module.params[ 'db_cluster_snapshot_identifier']: results['snapshots'] = standalone_snapshot_info(module, conn) if not module.params['db_snapshot_identifier'] and not module.params[ 'db_instance_identifier']: results['cluster_snapshots'] = cluster_snapshot_info(module, conn) module.exit_json(changed=False, **results)
def main(): module = AnsibleAWSModule( argument_spec={ 'state': dict(type='str', choices=['present', 'absent'], default='present'), 'authorized_account_id': dict(type='str', required=True), 'authorized_aws_region': dict(type='str', required=True), }, supports_check_mode=False, ) result = {'changed': False} params = { 'AuthorizedAccountId': module.params.get('authorized_account_id'), 'AuthorizedAwsRegion': module.params.get('authorized_aws_region'), } client = module.client('config', retry_decorator=AWSRetry.jittered_backoff()) resource_status = resource_exists(client, module, params) if module.params.get('state') == 'present': if not resource_status: create_resource(client, module, params, result) else: update_resource(client, module, params, result) if module.params.get('state') == 'absent': if resource_status: delete_resource(client, module, params, result) module.exit_json(changed=result['changed'])
def main(): argument_spec = dict( state=dict(required=True, choices=['present', 'absent']), name=dict(required=True), engine=dict(), description=dict(), params=dict(aliases=['parameters'], type='dict'), immediate=dict(type='bool', aliases=['apply_immediately']), tags=dict(type='dict', default={}), purge_tags=dict(type='bool', default=False), ) module = AnsibleAWSModule( argument_spec=argument_spec, required_if=[['state', 'present', ['description', 'engine']]], supports_check_mode=True) try: conn = module.client('rds', retry_decorator=AWSRetry.jittered_backoff()) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Failed to connect to AWS') state = module.params.get('state') if state == 'present': ensure_present(module, conn) if state == 'absent': ensure_absent(module, conn)
def main(): argument_spec = dict( filters=dict(default={}, type='dict'), nat_gateway_ids=dict(default=[], type='list', elements='str'), ) module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ec2_vpc_nat_gateway_facts': module.deprecate( "The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", date='2021-12-01', collection_name='community.aws') try: connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Failed to connect to AWS') results = get_nat_gateways(connection, module) module.exit_json(result=results)
def main(): module = AnsibleAWSModule( argument_spec=dict( state=dict(choices=['present', 'absent'], default='present'), db_snapshot_identifier=dict(aliases=['id', 'snapshot_id'], required=True), db_instance_identifier=dict(aliases=['instance_id']), wait=dict(type='bool', default=False), wait_timeout=dict(type='int', default=300), tags=dict(type='dict'), purge_tags=dict(type='bool', default=True), ), required_if=[['state', 'present', ['db_instance_identifier']]]) client = module.client('rds', retry_decorator=AWSRetry.jittered_backoff( retries=10, catch_extra_error_codes=['DBSnapshotNotFound'])) if module.params['state'] == 'absent': ret_dict = ensure_snapshot_absent(client, module) else: ret_dict = ensure_snapshot_present(client, module) module.exit_json(**ret_dict)
def main(): argument_spec = dict(filters=dict(default={}, type='dict')) module = AnsibleAWSModule(argument_spec=argument_spec) if module._name == 'aws_az_facts': module.deprecate( "The 'aws_az_facts' module has been renamed to 'aws_az_info'", version='2.14') connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) # Replace filter key underscores with dashes, for compatibility sanitized_filters = dict((k.replace('_', '-'), v) for k, v in module.params.get('filters').items()) try: availability_zones = connection.describe_availability_zones( Filters=ansible_dict_to_boto3_filter_list(sanitized_filters)) except (BotoCoreError, ClientError) as e: module.fail_json_aws(e, msg="Unable to describe availability zones.") # Turn the boto3 result into ansible_friendly_snaked_names snaked_availability_zones = [ camel_dict_to_snake_dict(az) for az in availability_zones['AvailabilityZones'] ] module.exit_json(availability_zones=snaked_availability_zones)
def main(): argument_spec = dict( filters=dict(type='dict', default=dict()), internet_gateway_ids=dict(type='list', default=None, elements='str'), convert_tags=dict(type='bool'), ) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) if module._name == 'ec2_vpc_igw_facts': module.deprecate( "The 'ec2_vpc_igw_facts' module has been renamed to 'ec2_vpc_igw_info'", date='2021-12-01', collection_name='community.aws') if module.params.get('convert_tags') is None: module.deprecate( 'This module currently returns boto3 style tags by default. ' 'This default has been deprecated and the module will return a simple dictionary in future. ' 'This behaviour can be controlled through the convert_tags parameter.', date='2021-12-01', collection_name='community.aws') # Validate Requirements try: connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Failed to connect to AWS') # call your function here results = list_internet_gateways(connection, module) module.exit_json(internet_gateways=results)
def main(): global module global client argument_spec = dict( load_balancer_arn=dict(type='str'), target_group_arns=dict(type='list', elements='str'), names=dict(type='list', elements='str'), collect_targets_health=dict(default=False, type='bool', required=False), ) module = AnsibleAWSModule( argument_spec=argument_spec, mutually_exclusive=[[ 'load_balancer_arn', 'target_group_arns', 'names' ]], supports_check_mode=True, ) try: client = module.client( 'elbv2', retry_decorator=AWSRetry.jittered_backoff(retries=10)) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Failed to connect to AWS') list_target_groups()
def main(): argument_spec = dict(filters=dict(default={}, type='dict')) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) if module._name == 'aws_region_facts': module.deprecate( "The 'aws_region_facts' module has been renamed to 'aws_region_info'", date='2021-12-01', collection_name='community.aws') connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) # Replace filter key underscores with dashes, for compatibility sanitized_filters = dict(module.params.get('filters')) for k in module.params.get('filters').keys(): if "_" in k: sanitized_filters[k.replace('_', '-')] = sanitized_filters[k] del sanitized_filters[k] try: regions = connection.describe_regions( aws_retry=True, Filters=ansible_dict_to_boto3_filter_list(sanitized_filters)) except (BotoCoreError, ClientError) as e: module.fail_json_aws(e, msg="Unable to describe regions.") module.exit_json( regions=[camel_dict_to_snake_dict(r) for r in regions['Regions']])
def main(): argument_spec = dict( state=dict( type='str', required=True, choices=['started', 'cancelled'], ), name=dict(required=True), strategy=dict(type='str', default='Rolling', required=False), preferences=dict(type='dict', required=False, options=dict( min_healthy_percentage=dict(type='int', default=90), instance_warmup=dict(type='int'), )), ) module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=True, ) autoscaling = module.client( 'autoscaling', retry_decorator=AWSRetry.jittered_backoff( retries=10, catch_extra_error_codes=['InstanceRefreshInProgress'])) start_or_cancel_instance_refresh(autoscaling, module)
def main(): argument_spec = dict(vpc_id=dict(required=True), state=dict(default='present', choices=['present', 'absent'])) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) retry_decorator = AWSRetry.jittered_backoff(retries=10) connection = module.client('ec2', retry_decorator=retry_decorator) vpc_id = module.params.get('vpc_id') state = module.params.get('state') eigw_id = describe_eigws(module, connection, vpc_id) result = dict(gateway_id=eigw_id, vpc_id=vpc_id) changed = False if state == 'present' and not eigw_id: changed, result['gateway_id'] = create_eigw(module, connection, vpc_id) elif state == 'absent' and eigw_id: changed = delete_eigw(module, connection, eigw_id) module.exit_json(changed=changed, **result)
def main(): argument_spec = dict( state=dict(type='str', default='present', choices=['present', 'absent']), name=dict(type='str', required=True), queue_type=dict(type='str', default='standard', choices=['standard', 'fifo']), delay_seconds=dict(type='int', aliases=['delivery_delay']), maximum_message_size=dict(type='int'), message_retention_period=dict(type='int'), policy=dict(type='dict'), receive_message_wait_time_seconds=dict(type='int', aliases=['receive_message_wait_time']), redrive_policy=dict(type='dict'), visibility_timeout=dict(type='int', aliases=['default_visibility_timeout']), kms_master_key_id=dict(type='str'), kms_data_key_reuse_period_seconds=dict(type='int', aliases=['kms_data_key_reuse_period']), content_based_deduplication=dict(type='bool'), tags=dict(type='dict'), purge_tags=dict(type='bool', default=False), ) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) state = module.params.get('state') retry_decorator = AWSRetry.jittered_backoff(catch_extra_error_codes=['AWS.SimpleQueueService.NonExistentQueue']) try: client = module.client('sqs', retry_decorator=retry_decorator) if state == 'present': result = create_or_update_sqs_queue(client, module) elif state == 'absent': result = delete_sqs_queue(client, module) except (BotoCoreError, ClientError, ParamValidationError) as e: module.fail_json_aws(e, msg='Failed to control sqs queue') else: module.exit_json(**result)
def get_role_with_backoff(connection, module, name): try: return AWSRetry.jittered_backoff( catch_extra_error_codes=['NoSuchEntity'])( connection.get_role)(RoleName=name)['Role'] except (BotoCoreError, ClientError) as e: module.fail_json_aws(e, msg="Unable to get role {0}".format(name))
def delete_sqs_queue(client, module): is_fifo = (module.params.get('queue_type') == 'fifo') queue_name = get_queue_name(module, is_fifo) result = dict(name=queue_name, region=module.params.get('region'), changed=False) queue_url = get_queue_url(client, queue_name) if not queue_url: return result result['changed'] = bool(queue_url) if not module.check_mode: AWSRetry.jittered_backoff()(client.delete_queue)(QueueUrl=queue_url) return result