Exemple #1
0
def config_details(client, module):
    """
    Returns configuration details for one or all lambda functions.

    :param client: AWS API client reference (boto3)
    :param module: Ansible module reference
    :return dict:
    """

    lambda_info = dict()

    function_name = module.params.get('function_name')
    if function_name:
        try:
            lambda_info.update(client.get_function_configuration(aws_retry=True, FunctionName=function_name))
        except is_boto3_error_code('ResourceNotFoundException'):
            lambda_info.update(function={})
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
            module.fail_json_aws(e, msg="Trying to get {0} configuration".format(function_name))
    else:
        try:
            lambda_info.update(function_list=_paginate(client, 'list_functions')['Functions'])
        except is_boto3_error_code('ResourceNotFoundException'):
            lambda_info.update(function_list=[])
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) 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', []):
            func['tags'] = client.get_function(FunctionName=func['FunctionName']).get('Tags', {})
            functions[func['FunctionName']] = camel_dict_to_snake_dict(func)
        return functions

    return {function_name: camel_dict_to_snake_dict(lambda_info)}
Exemple #2
0
def setup_removal(client, module):
    params = dict()
    changed = False
    params['DryRun'] = module.check_mode
    if isinstance(module.params.get('vpc_endpoint_id'), string_types):
        params['VpcEndpointIds'] = [module.params.get('vpc_endpoint_id')]
    else:
        params['VpcEndpointIds'] = module.params.get('vpc_endpoint_id')
    try:
        result = client.delete_vpc_endpoints(**params)['Unsuccessful']
        if len(result) < len(params['VpcEndpointIds']):
            changed = True
        # For some reason delete_vpc_endpoints doesn't throw exceptions it
        # returns a list of failed 'results' instead.  Throw these so we can
        # catch them the way we expect
        for r in result:
            try:
                raise botocore.exceptions.ClientError(r, 'delete_vpc_endpoints')
            except is_boto3_error_code('InvalidVpcEndpoint.NotFound'):
                continue
    except is_boto3_error_code('DryRunOperation'):
        changed = True
        result = 'Would have deleted VPC Endpoint if not in check mode'
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, "Failed to delete VPC endpoint")
    return changed, result
Exemple #3
0
def await_stack_set_operation(module, cfn, stack_set_name, operation_id, max_wait):
    wait_start = datetime.datetime.now()
    operation = None
    for i in range(max_wait // 15):
        try:
            operation = cfn.describe_stack_set_operation(StackSetName=stack_set_name, OperationId=operation_id)
            if operation['StackSetOperation']['Status'] not in ('RUNNING', 'STOPPING'):
                # Stack set has completed operation
                break
        except is_boto3_error_code('StackSetNotFound'):  # pylint: disable=duplicate-except
            pass
        except is_boto3_error_code('OperationNotFound'):  # pylint: disable=duplicate-except
            pass
        time.sleep(15)

    if operation and operation['StackSetOperation']['Status'] not in ('FAILED', 'STOPPED'):
        await_stack_instance_completion(
            module, cfn,
            stack_set_name=stack_set_name,
            # subtract however long we waited already
            max_wait=int(max_wait - (datetime.datetime.now() - wait_start).total_seconds()),
        )
    elif operation and operation['StackSetOperation']['Status'] in ('FAILED', 'STOPPED'):
        pass
    else:
        module.warn(
            "Timed out waiting for operation {0} on stack set {1} after {2} seconds. Returning unfinished operation".format(
                operation_id, stack_set_name, max_wait
            )
        )
Exemple #4
0
def update_stack_set(module, stack_params, cfn):
    # if the state is present and the stack already exists, we try to update it.
    # AWS will tell us if the stack template and parameters are the same and
    # don't need to be updated.
    try:
        cfn.update_stack_set(**stack_params)
    except is_boto3_error_code('StackSetNotFound') as err:  # pylint: disable=duplicate-except
        module.fail_json_aws(err, msg="Failed to find stack set. Check the name & region.")
    except is_boto3_error_code('StackInstanceNotFound') as err:  # pylint: disable=duplicate-except
        module.fail_json_aws(err, msg="One or more stack instances were not found for this stack set. Double check "
                             "the `accounts` and `regions` parameters.")
    except is_boto3_error_code('OperationInProgressException') as err:  # pylint: disable=duplicate-except
        module.fail_json_aws(
            err, msg="Another operation is already in progress on this stack set - please try again later. When making "
            "multiple cloudformation_stack_set calls, it's best to enable `wait: yes` to avoid unfinished op errors.")
    except (ClientError, BotoCoreError) as err:  # pylint: disable=duplicate-except
        module.fail_json_aws(err, msg="Could not update stack set.")
    if module.params.get('wait'):
        await_stack_set_operation(
            module, cfn, operation_id=stack_params['OperationId'],
            stack_set_name=stack_params['StackSetName'],
            max_wait=module.params.get('wait_timeout'),
        )

    return True
def update_resource(client, module, params, result):
    current_params = client.describe_delivery_channels(
        DeliveryChannelNames=[params['name']],
        aws_retry=True,
    )

    if params != current_params['DeliveryChannels'][0]:
        try:
            retry_unavailable_iam_on_put_delivery(
                client.put_delivery_channel, )(DeliveryChannel=params, )
            result['changed'] = True
            result['channel'] = camel_dict_to_snake_dict(
                resource_exists(client, module, params))
            return result
        except is_boto3_error_code('InvalidS3KeyPrefixException') as e:
            module.fail_json_aws(
                e,
                msg=
                "The `s3_prefix` parameter was invalid. Try '/' for no prefix")
        except is_boto3_error_code('InsufficientDeliveryPolicyException') as e:  # pylint: disable=duplicate-except
            module.fail_json_aws(
                e,
                msg="The `s3_prefix` or `s3_bucket` parameter is invalid. "
                "Make sure the bucket exists and is available")
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
            module.fail_json_aws(
                e, msg="Couldn't create AWS Config delivery channel")
def create_eigw(module, conn, vpc_id):
    """
    Create EIGW.

    module       : AnsibleAWSModule object
    conn         : boto3 client connection object
    vpc_id       : ID of the VPC we are operating on
    """
    gateway_id = None
    changed = False

    try:
        response = conn.create_egress_only_internet_gateway(DryRun=module.check_mode, VpcId=vpc_id)
    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
        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:
        gateway = response.get('EgressOnlyInternetGateway', {})
        state = gateway.get('Attachments', [{}])[0].get('State')
        gateway_id = gateway.get('EgressOnlyInternetGatewayId')

        if gateway_id and state in ('attached', 'attaching'):
            changed = True
        else:
            # EIGW gave back a bad attachment state or an invalid response so we error out
            module.fail_json(msg='Unable to create and attach Egress Only Internet Gateway to VPCId: {0}. Bad or no state in response'.format(vpc_id),
                             **camel_dict_to_snake_dict(response))

    return changed, gateway_id
def existing_templates(module):
    ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
    matches = None
    try:
        if module.params.get('template_id'):
            matches = ec2.describe_launch_templates(LaunchTemplateIds=[module.params.get('template_id')], aws_retry=True)
        elif module.params.get('template_name'):
            matches = ec2.describe_launch_templates(LaunchTemplateNames=[module.params.get('template_name')], aws_retry=True)
    except is_boto3_error_code('InvalidLaunchTemplateName.NotFoundException') as e:
        # no named template was found, return nothing/empty versions
        return None, []
    except is_boto3_error_code('InvalidLaunchTemplateId.Malformed') as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg='Launch template with ID {0} is not a valid ID. It should start with `lt-....`'.format(
            module.params.get('launch_template_id')))
    except is_boto3_error_code('InvalidLaunchTemplateId.NotFoundException') as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(
            e, msg='Launch template with ID {0} could not be found, please supply a name '
            'instead so that a new template can be created'.format(module.params.get('launch_template_id')))
    except (ClientError, BotoCoreError, WaiterError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg='Could not check existing launch templates. This may be an IAM permission problem.')
    else:
        template = matches['LaunchTemplates'][0]
        template_id, template_version, template_default = template['LaunchTemplateId'], template['LatestVersionNumber'], template['DefaultVersionNumber']
        try:
            return template, ec2.describe_launch_template_versions(LaunchTemplateId=template_id, aws_retry=True)['LaunchTemplateVersions']
        except (ClientError, BotoCoreError, WaiterError) as e:
            module.fail_json_aws(e, msg='Could not find launch template versions for {0} (ID: {1}).'.format(template['LaunchTemplateName'], template_id))
Exemple #8
0
 def get_parameter_value(self, client, ssm_dict, term, on_missing,
                         on_denied):
     ssm_dict["Name"] = term
     try:
         response = client.get_parameter(**ssm_dict)
         return response['Parameter']['Value']
     except is_boto3_error_code('ParameterNotFound'):
         if on_missing == 'error':
             raise AnsibleError(
                 "Failed to find SSM parameter %s (ResourceNotFound)" %
                 term)
         elif on_missing == 'warn':
             self._display.warning(
                 'Skipping, did not find SSM parameter %s' % term)
     except is_boto3_error_code('AccessDeniedException'):  # pylint: disable=duplicate-except
         if on_denied == 'error':
             raise AnsibleError(
                 "Failed to access SSM parameter %s (AccessDenied)" % term)
         elif on_denied == 'warn':
             self._display.warning(
                 'Skipping, access denied for SSM parameter %s' % term)
     except botocore.exceptions.ClientError as e:  # pylint: disable=duplicate-except
         raise AnsibleError("SSM lookup exception: {0}".format(
             to_native(e)))
     return None
Exemple #9
0
def delete_metrics_configuration(client, module):
    bucket_name = module.params.get('bucket_name')
    mc_id = module.params.get('id')

    try:
        client.get_bucket_metrics_configuration(aws_retry=True,
                                                Bucket=bucket_name,
                                                Id=mc_id)
    except is_boto3_error_code('NoSuchConfiguration'):
        module.exit_json(changed=False)
    except (BotoCoreError, ClientError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e,
                             msg="Failed to get bucket metrics configuration")

    if module.check_mode:
        module.exit_json(changed=True)

    try:
        client.delete_bucket_metrics_configuration(aws_retry=True,
                                                   Bucket=bucket_name,
                                                   Id=mc_id)
    except is_boto3_error_code('NoSuchConfiguration'):
        module.exit_json(changed=False)
    except (BotoCoreError, ClientError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(
            e,
            msg="Failed to delete bucket metrics configuration '%s'" % mc_id)

    module.exit_json(changed=True)
def _describe_nat_gateways(client, module, **params):
    try:
        paginator = client.get_paginator('describe_nat_gateways')
        return paginator.paginate(**params).build_full_result()['NatGateways']
    except is_boto3_error_code('InvalidNatGatewayID.NotFound'):
        module.exit_json(msg="NAT gateway not found.")
    except is_boto3_error_code('NatGatewayMalformed'):  # pylint: disable=duplicate-except
        module.fail_json_aws(msg="NAT gateway id is malformed.")
def get_dynamodb_table():
    table_name = module.params.get('name')
    try:
        table = _describe_table(TableName=table_name)
    except is_boto3_error_code('ResourceNotFoundException'):
        return None
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg='Failed to describe table')

    table = table['Table']
    try:
        tags = client.list_tags_of_resource(
            aws_retry=True, ResourceArn=table['TableArn'])['Tags']
    except is_boto3_error_code('AccessDeniedException'):
        module.warn('Permission denied when listing tags')
        tags = []
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg='Failed to list table tags')

    tags = boto3_tag_list_to_ansible_dict(tags)

    table = camel_dict_to_snake_dict(table)

    # Put some of the values into places people will expect them
    table['arn'] = table['table_arn']
    table['name'] = table['table_name']
    table['status'] = table['table_status']
    table['id'] = table['table_id']
    table['size'] = table['table_size_bytes']
    table['tags'] = tags

    if 'table_class_summary' in table:
        table['table_class'] = table['table_class_summary']['table_class']

    # billing_mode_summary doesn't always seem to be set but is always set for PAY_PER_REQUEST
    # and when updating the billing_mode
    if 'billing_mode_summary' in table:
        table['billing_mode'] = table['billing_mode_summary']['billing_mode']
    else:
        table['billing_mode'] = "PROVISIONED"

    # convert indexes into something we can easily search against
    attributes = table['attribute_definitions']
    global_index_map = dict()
    local_index_map = dict()
    for index in table.get('global_secondary_indexes', []):
        idx = _decode_index(index, attributes, type_prefix='global_')
        global_index_map[idx['name']] = idx
    for index in table.get('local_secondary_indexes', []):
        idx = _decode_index(index, attributes)
        local_index_map[idx['name']] = idx
    table['_global_index_map'] = global_index_map
    table['_local_index_map'] = local_index_map

    return table
Exemple #12
0
def create_vpc_endpoint(client, module):
    params = dict()
    changed = False
    token_provided = False
    params['VpcId'] = module.params.get('vpc_id')
    params['VpcEndpointType'] = module.params.get('vpc_endpoint_type')
    params['ServiceName'] = module.params.get('service')
    params['DryRun'] = module.check_mode

    if module.params.get('route_table_ids'):
        params['RouteTableIds'] = module.params.get('route_table_ids')

    if module.params.get('client_token'):
        token_provided = True
        request_time = datetime.datetime.utcnow()
        params['ClientToken'] = module.params.get('client_token')

    policy = None
    if module.params.get('policy'):
        try:
            policy = json.loads(module.params.get('policy'))
        except ValueError as e:
            module.fail_json(msg=str(e), exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))

    elif module.params.get('policy_file'):
        try:
            with open(module.params.get('policy_file'), 'r') as json_data:
                policy = json.load(json_data)
        except Exception as e:
            module.fail_json(msg=str(e), exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))

    if policy:
        params['PolicyDocument'] = json.dumps(policy)

    try:
        changed = True
        result = camel_dict_to_snake_dict(client.create_vpc_endpoint(**params)['VpcEndpoint'])
        if token_provided and (request_time > result['creation_timestamp'].replace(tzinfo=None)):
            changed = False
        elif module.params.get('wait') and not module.check_mode:
            status_achieved, result = wait_for_status(client, module, result['vpc_endpoint_id'], 'available')
            if not status_achieved:
                module.fail_json(msg='Error waiting for vpc endpoint to become available - please check the AWS console')
    except is_boto3_error_code('DryRunOperation'):
        changed = True
        result = 'Would have created VPC Endpoint if not in check mode'
    except is_boto3_error_code('IdempotentParameterMismatch'):  # pylint: disable=duplicate-except
        module.fail_json(msg="IdempotentParameterMismatch - updates of endpoints are not allowed by the API")
    except is_boto3_error_code('RouteAlreadyExists'):  # pylint: disable=duplicate-except
        module.fail_json(msg="RouteAlreadyExists for one of the route tables - update is not allowed by the API")
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg="Failed to create VPC.")

    return changed, result
def ensure_present(module, connection):
    groupname = module.params['name']
    tags = module.params.get('tags')
    changed = False
    errors = []
    try:
        response = connection.describe_db_parameter_groups(
            aws_retry=True, DBParameterGroupName=groupname)
    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'],
                      Description=module.params['description'])
        if tags:
            params['Tags'] = ansible_dict_to_boto3_tag_list(tags)
        if not module.check_mode:
            try:
                response = connection.create_db_parameter_group(aws_retry=True,
                                                                **params)
                changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Couldn't create parameter group")
    else:
        group = response['DBParameterGroups'][0]
        if tags:
            changed = update_tags(module, connection, group, tags)

    if module.params.get('params'):
        params_changed, errors = update_parameters(module, connection)
        changed = changed or params_changed

    try:
        response = connection.describe_db_parameter_groups(
            aws_retry=True, DBParameterGroupName=groupname)
        group = camel_dict_to_snake_dict(response['DBParameterGroups'][0])
    except is_boto3_error_code('DBParameterGroupNotFound'):
        module.exit_json(changed=True, errors=errors)
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e,
                             msg="Couldn't obtain parameter group information")
    try:
        tags = connection.list_tags_for_resource(
            aws_retry=True,
            ResourceName=group['db_parameter_group_arn'])['TagList']
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't obtain parameter group tags")
    group['tags'] = boto3_tag_list_to_ansible_dict(tags)

    module.exit_json(changed=changed, errors=errors, **group)
def get_eip_allocation_id_by_address(client, module, eip_address):
    """Release an EIP from your EIP Pool
    Args:
        client (botocore.client.EC2): Boto3 client
        module: AnsibleAWSModule class instance
        eip_address (str): The Elastic IP Address of the EIP.

    Basic Usage:
        >>> client = boto3.client('ec2')
        >>> module = AnsibleAWSModule(...)
        >>> eip_address = '52.87.29.36'
        >>> get_eip_allocation_id_by_address(client, module, eip_address)
        'eipalloc-36014da3'

    Returns:
        Tuple (str, str)
    """

    params = {
        'PublicIps': [eip_address],
    }
    allocation_id = None
    msg = ''

    try:
        allocations = client.describe_addresses(aws_retry=True,
                                                **params)['Addresses']

        if len(allocations) == 1:
            allocation = allocations[0]
        else:
            allocation = None

        if allocation:
            if allocation.get('Domain') != 'vpc':
                msg = (
                    "EIP {0} is a non-VPC EIP, please allocate a VPC scoped EIP"
                    .format(eip_address))
            else:
                allocation_id = allocation.get('AllocationId')

    except is_boto3_error_code('InvalidAddress.Malformed') as e:
        module.fail_json(msg='EIP address {0} is invalid.'.format(eip_address))
    except is_boto3_error_code('InvalidAddress.NotFound') as e:  # pylint: disable=duplicate-except
        msg = ("EIP {0} does not exist".format(eip_address))
        allocation_id = None
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e)

    return allocation_id, msg
def delete(module, connection, name):
    """ Delete an ElastiCache backup. """
    try:
        response = connection.delete_snapshot(SnapshotName=name)
        changed = True
    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
def create_or_update_metrics_configuration(client, module):
    bucket_name = module.params.get('bucket_name')
    mc_id = module.params.get('id')
    filter_prefix = module.params.get('filter_prefix')
    filter_tags = module.params.get('filter_tags')

    try:
        response = client.get_bucket_metrics_configuration(aws_retry=True, Bucket=bucket_name, Id=mc_id)
        metrics_configuration = response['MetricsConfiguration']
    except is_boto3_error_code('NoSuchConfiguration'):
        metrics_configuration = None
    except (BotoCoreError, ClientError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg="Failed to get bucket metrics configuration")

    new_configuration = _create_metrics_configuration(mc_id, filter_prefix, filter_tags)

    if metrics_configuration:
        if metrics_configuration == new_configuration:
            module.exit_json(changed=False)

    if module.check_mode:
        module.exit_json(changed=True)

    try:
        client.put_bucket_metrics_configuration(
            aws_retry=True,
            Bucket=bucket_name,
            Id=mc_id,
            MetricsConfiguration=new_configuration
        )
    except (BotoCoreError, ClientError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg="Failed to put bucket metrics configuration '%s'" % mc_id)

    module.exit_json(changed=True)
Exemple #17
0
def instance_info(module, conn):
    instance_name = module.params.get('db_instance_identifier')
    filters = module.params.get('filters')

    params = dict()
    if instance_name:
        params['DBInstanceIdentifier'] = instance_name
    if filters:
        params['Filters'] = ansible_dict_to_boto3_filter_list(filters)

    paginator = conn.get_paginator('describe_db_instances')
    try:
        results = paginator.paginate(**params).build_full_result()['DBInstances']
    except is_boto3_error_code('DBInstanceNotFound'):
        results = []
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, "Couldn't get instance information")

    for instance in results:
        try:
            instance['Tags'] = boto3_tag_list_to_ansible_dict(conn.list_tags_for_resource(ResourceName=instance['DBInstanceArn'],
                                                                                          aws_retry=True)['TagList'])
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, "Couldn't get tags for instance %s" % instance['DBInstanceIdentifier'])

    return dict(changed=False, instances=[camel_dict_to_snake_dict(instance, ignore_list=['Tags']) for instance in results])
Exemple #18
0
def get_subnet_group(name):
    try:
        groups = client.describe_cache_subnet_groups(
            aws_retry=True,
            CacheSubnetGroupName=name,
        )['CacheSubnetGroups']
    except is_boto3_error_code('CacheSubnetGroupNotFoundFault'):
        return None
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg="Failed to describe subnet group")

    if not groups:
        return None

    if len(groups) > 1:
        module.fail_aws(
            msg="Found multiple matches for subnet group",
            cache_subnet_groups=camel_dict_to_snake_dict(groups),
        )

    subnet_group = camel_dict_to_snake_dict(groups[0])

    subnet_group['name'] = subnet_group['cache_subnet_group_name']
    subnet_group['description'] = subnet_group['cache_subnet_group_description']

    subnet_ids = list(s['subnet_identifier'] for s in subnet_group['subnets'])
    subnet_group['subnet_ids'] = subnet_ids

    return subnet_group
    def describe_transit_gateways(self):
        """
        Describe transit gateways.

        module  : AnsibleAWSModule object
        connection  : boto3 client connection object
        """
        # collect parameters
        filters = ansible_dict_to_boto3_filter_list(
            self._module.params['filters'])
        transit_gateway_ids = self._module.params['transit_gateway_ids']

        # init empty list for return vars
        transit_gateway_info = list()

        # Get the basic transit gateway info
        try:
            response = self._connection.describe_transit_gateways(
                TransitGatewayIds=transit_gateway_ids, Filters=filters)
        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']))
            # convert tag list to ansible dict
            transit_gateway_info[-1]['tags'] = boto3_tag_list_to_ansible_dict(
                transit_gateway.get('Tags', []))

        self._results['transit_gateways'] = transit_gateway_info
        return
Exemple #20
0
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
Exemple #21
0
def find_address(ec2, module, public_ip, device_id, is_instance=True):
    """ Find an existing Elastic IP address """
    filters = []
    kwargs = {}

    if public_ip:
        kwargs["PublicIps"] = [public_ip]
    elif device_id:
        if is_instance:
            filters.append({"Name": 'instance-id', "Values": [device_id]})
        else:
            filters.append({'Name': 'network-interface-id', "Values": [device_id]})

    if len(filters) > 0:
        kwargs["Filters"] = filters
    elif len(filters) == 0 and public_ip is None:
        return None

    try:
        addresses = ec2.describe_addresses(**kwargs)
    except is_boto3_error_code('InvalidAddress.NotFound') as e:
        # If we're releasing and we can't find it, it's already gone...
        if module.params.get('state') == 'absent':
            module.exit_json(changed=False)
        module.fail_json_aws(e, msg="Couldn't obtain list of existing Elastic IP addresses")

    addresses = addresses["Addresses"]
    if len(addresses) == 1:
        return addresses[0]
    elif len(addresses) > 1:
        msg = "Found more than one address using args {0}".format(kwargs)
        msg += "Addresses found: {0}".format(addresses)
        module.fail_json_aws(botocore.exceptions.ClientError, msg=msg)
Exemple #22
0
def version_details(client, module):
    """
    Returns all lambda function versions.

    :param client: AWS API client reference (boto3)
    :param module: Ansible module reference
    :return dict:
    """

    lambda_info = dict()

    function_name = module.params.get('function_name')
    if function_name:
        params = dict()
        if module.params.get('max_items'):
            params['MaxItems'] = module.params.get('max_items')

        if module.params.get('next_marker'):
            params['Marker'] = module.params.get('next_marker')

        try:
            lambda_info.update(versions=client.list_versions_by_function(
                FunctionName=function_name, **params)['Versions'])
        except is_boto3_error_code('ResourceNotFoundException'):
            lambda_info.update(versions=[])
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) 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.')

    return {function_name: camel_dict_to_snake_dict(lambda_info)}
Exemple #23
0
    def delete_unused_regex_pattern(self, regex_pattern_set_id):
        try:
            regex_pattern_set = self.client.get_regex_pattern_set(
                RegexPatternSetId=regex_pattern_set_id)['RegexPatternSet']
            updates = list()
            for regex_pattern_string in regex_pattern_set[
                    'RegexPatternStrings']:
                updates.append({
                    'Action': 'DELETE',
                    'RegexPatternString': regex_pattern_string
                })
            run_func_with_change_token_backoff(
                self.client, self.module, {
                    'RegexPatternSetId': regex_pattern_set_id,
                    'Updates': updates
                }, self.client.update_regex_pattern_set)

            run_func_with_change_token_backoff(
                self.client,
                self.module, {'RegexPatternSetId': regex_pattern_set_id},
                self.client.delete_regex_pattern_set,
                wait=True)
        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 delete_eigw(module, connection, eigw_id):
    """
    Delete EIGW.

    module     : AnsibleAWSModule object
    connection : boto3 client connection object
    eigw_id    : ID of the EIGW to delete
    """
    changed = False

    try:
        response = connection.delete_egress_only_internet_gateway(
            aws_retry=True,
            DryRun=module.check_mode,
            EgressOnlyInternetGatewayId=eigw_id)
    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:
        changed = response.get('ReturnCode', False)

    return changed
Exemple #25
0
 def list_services_with_backoff(self, **kwargs):
     paginator = self.ecs.get_paginator('list_services')
     try:
         return paginator.paginate(**kwargs).build_full_result()
     except is_boto3_error_code('ClusterNotFoundException') as e:
         self.module.fail_json_aws(
             e, "Could not find cluster to list services")
Exemple #26
0
def policy_details(client, module):
    """
    Returns policy attached to a lambda function.

    :param client: AWS API client reference (boto3)
    :param module: Ansible module reference
    :return dict:
    """

    if module.params.get('max_items') or module.params.get('next_marker'):
        module.fail_json(
            msg='Cannot specify max_items nor next_marker for query=policy.')

    lambda_info = dict()

    function_name = module.params.get('function_name')
    if function_name:
        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 is_boto3_error_code('ResourceNotFoundException'):
            lambda_info.update(policy={})
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) 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.')

    return {function_name: camel_dict_to_snake_dict(lambda_info)}
Exemple #27
0
def get_policy_statement(module, client):
    """Checks that policy exists and if so, that statement ID is present or absent.

    :param module:
    :param client:
    :return:
    """
    sid = module.params['statement_id']

    # set API parameters
    api_params = set_api_params(module, ('function_name', ))
    qualifier = get_qualifier(module)
    if qualifier:
        api_params.update(Qualifier=qualifier)

    policy_results = None
    # check if function policy exists
    try:
        policy_results = client.get_policy(**api_params)
    except is_boto3_error_code('ResourceNotFoundException'):
        return {}
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) 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
    policy = json.loads(policy_results.get('Policy', '{}'))
    return extract_statement(policy, sid)
def get_subnet_group(name):
    try:
        groups = client.describe_cluster_subnet_groups(
            aws_retry=True,
            ClusterSubnetGroupName=name,
        )['ClusterSubnetGroups']
    except is_boto3_error_code('ClusterSubnetGroupNotFoundFault'):
        return None
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, msg="Failed to describe subnet group")

    if not groups:
        return None

    if len(groups) > 1:
        module.fail_aws(
            msg="Found multiple matches for subnet group",
            cluster_subnet_groups=camel_dict_to_snake_dict(groups),
        )

    # No support for managing tags yet, but make sure that we don't need to
    # change the return value structure after it's been available in a release.
    tags = boto3_tag_list_to_ansible_dict(groups[0]['Tags'])

    subnet_group = camel_dict_to_snake_dict(groups[0])

    subnet_group['tags'] = tags
    subnet_group['name'] = subnet_group['cluster_subnet_group_name']

    subnet_ids = list(s['subnet_identifier'] for s in subnet_group['subnets'])
    subnet_group['subnet_ids'] = subnet_ids

    return subnet_group
def common_snapshot_info(module, conn, method, prefix, params):
    paginator = conn.get_paginator(method)
    try:
        results = paginator.paginate(**params).build_full_result()['%ss' %
                                                                   prefix]
    except is_boto3_error_code('%sNotFound' % prefix):
        results = []
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:  # pylint: disable=duplicate-except
        module.fail_json_aws(e, "trying to get snapshot information")

    for snapshot in results:
        try:
            if snapshot['SnapshotType'] != 'shared':
                snapshot['Tags'] = boto3_tag_list_to_ansible_dict(
                    conn.list_tags_for_resource(ResourceName=snapshot['%sArn' %
                                                                      prefix],
                                                aws_retry=True)['TagList'])
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(
                e, "Couldn't get tags for snapshot %s" %
                snapshot['%sIdentifier' % prefix])

    return [
        camel_dict_to_snake_dict(snapshot, ignore_list=['Tags'])
        for snapshot in results
    ]
Exemple #30
0
def get_enable_key_rotation_with_backoff(connection, key_id):
    try:
        current_rotation_status = connection.get_key_rotation_status(KeyId=key_id)
    except is_boto3_error_code('AccessDeniedException') as e:
        return None

    return current_rotation_status.get('KeyRotationEnabled')