Ejemplo n.º 1
0
def get_subnet_info(subnet):
    if 'Subnets' in subnet:
        return [get_subnet_info(s) for s in subnet['Subnets']]
    elif 'Subnet' in subnet:
        subnet = camel_dict_to_snake_dict(subnet['Subnet'])
    else:
        subnet = camel_dict_to_snake_dict(subnet)

    if 'tags' in subnet:
        subnet['tags'] = boto3_tag_list_to_ansible_dict(subnet['tags'])
    else:
        subnet['tags'] = dict()

    if 'subnet_id' in subnet:
        subnet['id'] = subnet['subnet_id']
        del subnet['subnet_id']

    subnet['ipv6_cidr_block'] = ''
    subnet['ipv6_association_id'] = ''
    ipv6set = subnet.get('ipv6_cidr_block_association_set')
    if ipv6set:
        for item in ipv6set:
            if item.get('ipv6_cidr_block_state', {}).get('state') in ('associated', 'associating'):
                subnet['ipv6_cidr_block'] = item['ipv6_cidr_block']
                subnet['ipv6_association_id'] = item['association_id']

    return subnet
def update_tags(module, connection, group, tags):
    changed = False
    existing_tags = connection.list_tags_for_resource(
        ResourceName=group['DBParameterGroupArn'])['TagList']
    to_update, to_delete = compare_aws_tags(
        boto3_tag_list_to_ansible_dict(existing_tags), tags,
        module.params['purge_tags'])
    if to_update:
        try:
            connection.add_tags_to_resource(
                ResourceName=group['DBParameterGroupArn'],
                Tags=ansible_dict_to_boto3_tag_list(to_update))
            changed = True
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't add tags to parameter group: %s" %
                             str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        except botocore.exceptions.ParamValidationError as e:
            # Usually a tag value has been passed as an int or bool, needs to be a string
            # The AWS exception message is reasonably ok for this purpose
            module.fail_json(msg="Couldn't add tags to parameter group: %s." %
                             str(e),
                             exception=traceback.format_exc())
    if to_delete:
        try:
            connection.remove_tags_from_resource(
                ResourceName=group['DBParameterGroupArn'], TagKeys=to_delete)
            changed = True
        except botocore.exceptions.ClientError as e:
            module.fail_json(
                msg="Couldn't remove tags from parameter group: %s" % str(e),
                exception=traceback.format_exc(),
                **camel_dict_to_snake_dict(e.response))
    return changed
def list_ec2_instances(connection, module):

    instance_ids = module.params.get("instance_ids")
    filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))

    try:
        reservations_paginator = connection.get_paginator('describe_instances')
        reservations = reservations_paginator.paginate(
            InstanceIds=instance_ids, Filters=filters).build_full_result()
    except ClientError as e:
        module.fail_json(msg=e.message,
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    # Get instances from reservations
    instances = []
    for reservation in reservations['Reservations']:
        instances = instances + reservation['Instances']

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_instances = [
        camel_dict_to_snake_dict(instance) for instance in instances
    ]

    # Turn the boto3 result in to ansible friendly tag dictionary
    for instance in snaked_instances:
        instance['tags'] = boto3_tag_list_to_ansible_dict(
            instance.get('tags', []), 'key', 'value')

    module.exit_json(instances=snaked_instances)
def find_clusters(conn, module, identifier=None, tags=None):

    try:
        cluster_paginator = conn.get_paginator('describe_clusters')
        clusters = cluster_paginator.paginate().build_full_result()
    except ClientError as e:
        module.fail_json(msg=e.message,
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    matched_clusters = []

    if identifier is not None:
        identifier_prog = re.compile('^' + identifier)

    for cluster in clusters['Clusters']:

        matched_identifier = True
        if identifier:
            matched_identifier = identifier_prog.search(
                cluster['ClusterIdentifier'])

        matched_tags = True
        if tags:
            matched_tags = match_tags(tags, cluster)

        if matched_identifier and matched_tags:
            matched_clusters.append(camel_dict_to_snake_dict(cluster))

    return matched_clusters
def ensure_present(module, connection):
    groupname = module.params['name']
    tags = module.params.get('tags')
    changed = False
    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(
                msg="Couldn't access parameter group information: %s" % str(e),
                exception=traceback.format_exc(),
                **camel_dict_to_snake_dict(e.response))
    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)
        try:
            response = connection.create_db_parameter_group(**params)
            changed = True
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't create parameter group: %s" %
                             str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    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(
            DBParameterGroupName=groupname)
        group = camel_dict_to_snake_dict(response['DBParameterGroups'][0])
    except botocore.exceptions.ClientError as e:
        module.fail_json(
            msg="Couldn't obtain parameter group information: %s" % str(e),
            exception=traceback.format_exc(),
            **camel_dict_to_snake_dict(e.response))
    try:
        tags = connection.list_tags_for_resource(
            ResourceName=group['db_parameter_group_arn'])['TagList']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't obtain parameter group tags: %s" %
                         str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    group['tags'] = boto3_tag_list_to_ansible_dict(tags)

    module.exit_json(changed=changed, errors=errors, **group)
def list_load_balancers(connection, module):

    load_balancer_arns = module.params.get("load_balancer_arns")
    names = module.params.get("names")

    try:
        load_balancer_paginator = connection.get_paginator(
            'describe_load_balancers')
        if not load_balancer_arns and not names:
            load_balancers = load_balancer_paginator.paginate(
            ).build_full_result()
        if load_balancer_arns:
            load_balancers = load_balancer_paginator.paginate(
                LoadBalancerArns=load_balancer_arns).build_full_result()
        if names:
            load_balancers = load_balancer_paginator.paginate(
                Names=names).build_full_result()
    except ClientError as e:
        if e.response['Error']['Code'] == 'LoadBalancerNotFound':
            module.exit_json(load_balancers=[])
        else:
            module.fail_json(msg=e.message,
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    except NoCredentialsError as e:
        module.fail_json(msg="AWS authentication problem. " + e.message,
                         exception=traceback.format_exc())

    for load_balancer in load_balancers['LoadBalancers']:
        # Get the attributes for each elb
        load_balancer.update(
            get_load_balancer_attributes(connection, module,
                                         load_balancer['LoadBalancerArn']))

        # Get the listeners for each elb
        load_balancer['listeners'] = get_elb_listeners(
            connection, module, load_balancer['LoadBalancerArn'])

        # For each listener, get listener rules
        for listener in load_balancer['listeners']:
            listener['rules'] = get_listener_rules(connection, module,
                                                   listener['ListenerArn'])

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_load_balancers = [
        camel_dict_to_snake_dict(load_balancer)
        for load_balancer in load_balancers['LoadBalancers']
    ]

    # Get tags for each load balancer
    for snaked_load_balancer in snaked_load_balancers:
        snaked_load_balancer['tags'] = get_load_balancer_tags(
            connection, module, snaked_load_balancer['load_balancer_arn'])

    module.exit_json(load_balancers=snaked_load_balancers)
def list_mfa_devices(connection, module):
    user_name = module.params.get('user_name')
    changed = False

    args = {}
    if user_name is not None:
        args['UserName'] = user_name
    try:
        response = connection.list_mfa_devices(**args)
    except ClientError as e:
        module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response))

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
def get_bucket_list(module, connection):
    """
    Return result of list_buckets json encoded
    :param module:
    :param connection:
    :return:
    """
    try:
        buckets = camel_dict_to_snake_dict(connection.list_buckets())['buckets']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=to_native(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

    return buckets
Ejemplo n.º 9
0
def ensure_ipv6_cidr_block(conn, module, subnet, ipv6_cidr, check_mode, start_time):
    wait = module.params['wait']
    changed = False

    if subnet['ipv6_association_id'] and not ipv6_cidr:
        if not check_mode:
            disassociate_ipv6_cidr(conn, module, subnet, start_time)
        changed = True

    if ipv6_cidr:
        filters = ansible_dict_to_boto3_filter_list({'ipv6-cidr-block-association.ipv6-cidr-block': ipv6_cidr,
                                                     'vpc-id': subnet['vpc_id']})

        try:
            check_subnets = get_subnet_info(describe_subnets_with_backoff(conn, Filters=filters))
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't get subnet info")

        if check_subnets and check_subnets[0]['ipv6_cidr_block']:
            module.fail_json(msg="The IPv6 CIDR '{0}' conflicts with another subnet".format(ipv6_cidr))

        if subnet['ipv6_association_id']:
            if not check_mode:
                disassociate_ipv6_cidr(conn, module, subnet, start_time)
            changed = True

        try:
            if not check_mode:
                associate_resp = conn.associate_subnet_cidr_block(SubnetId=subnet['id'], Ipv6CidrBlock=ipv6_cidr)
            changed = True
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't associate ipv6 cidr {0} to {1}".format(ipv6_cidr, subnet['id']))
        else:
            if not check_mode and wait:
                filters = ansible_dict_to_boto3_filter_list(
                    {'ipv6-cidr-block-association.state': ['associated'],
                     'vpc-id': subnet['vpc_id']}
                )
                handle_waiter(conn, module, 'subnet_exists',
                              {'SubnetIds': [subnet['id']], 'Filters': filters}, start_time)

        if associate_resp.get('Ipv6CidrBlockAssociation', {}).get('AssociationId'):
            subnet['ipv6_association_id'] = associate_resp['Ipv6CidrBlockAssociation']['AssociationId']
            subnet['ipv6_cidr_block'] = associate_resp['Ipv6CidrBlockAssociation']['Ipv6CidrBlock']
            if subnet['ipv6_cidr_block_association_set']:
                subnet['ipv6_cidr_block_association_set'][0] = camel_dict_to_snake_dict(associate_resp['Ipv6CidrBlockAssociation'])
            else:
                subnet['ipv6_cidr_block_association_set'].append(camel_dict_to_snake_dict(associate_resp['Ipv6CidrBlockAssociation']))

    return changed
def get_or_create_policy_version(module, iam, policy, policy_document):
    try:
        versions = iam.list_policy_versions(
            PolicyArn=policy['Arn'])['Versions']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't list policy versions: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    for v in versions:
        try:
            document = iam.get_policy_version(
                PolicyArn=policy['Arn'],
                VersionId=v['VersionId'])['PolicyVersion']['Document']
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't get policy version %s: %s" %
                             (v['VersionId'], str(e)),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        # If the current policy matches the existing one
        if not compare_policies(document, json.loads(
                to_native(policy_document))):
            return v, False

    # No existing version so create one
    # There is a service limit (typically 5) of policy versions.
    #
    # Rather than assume that it is 5, we'll try to create the policy
    # and if that doesn't work, delete the oldest non default policy version
    # and try again.
    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
        module.fail_json(msg="Couldn't create policy version: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
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 copy_image(module, ec2):
    """
    Copies an AMI

    module : AnsibleModule object
    ec2: ec2 connection object
    """

    image = None
    changed = False
    tags = module.params.get('tags')

    params = {
        'SourceRegion': module.params.get('source_region'),
        'SourceImageId': module.params.get('source_image_id'),
        'Name': module.params.get('name'),
        'Description': module.params.get('description'),
        'Encrypted': module.params.get('encrypted'),
    }
    if module.params.get('kms_key_id'):
        params['KmsKeyId'] = module.params.get('kms_key_id')

    try:
        if module.params.get('tag_equality'):
            filters = [{
                'Name': 'tag:%s' % k,
                'Values': [v]
            } for (k, v) in module.params.get('tags').items()]
            filters.append(dict(Name='state', Values=['available', 'pending']))
            images = ec2.describe_images(Filters=filters)
            if len(images['Images']) > 0:
                image = images['Images'][0]
        if not image:
            image = ec2.copy_image(**params)
            image_id = image['ImageId']
            if tags:
                ec2.create_tags(Resources=[image_id],
                                Tags=ansible_dict_to_boto3_tag_list(tags))
            changed = True

        if module.params.get('wait'):
            delay = 15
            max_attempts = module.params.get('wait_timeout') // delay
            image_id = image.get('ImageId')
            ec2.get_waiter('image_available').wait(ImageIds=[image_id],
                                                   WaiterConfig={
                                                       'Delay': delay,
                                                       'MaxAttempts':
                                                       max_attempts
                                                   })

        module.exit_json(changed=changed, **camel_dict_to_snake_dict(image))
    except WaiterError as e:
        module.fail_json_aws(
            e,
            msg='An error occurred waiting for the image to become available')
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Could not copy AMI")
    except Exception as e:
        module.fail_json(msg='Unhandled exception. (%s)' % to_native(e))
Ejemplo n.º 13
0
def remove_rule_set(client, module):
    name = module.params.get('name')
    check_mode = module.check_mode
    changed = False

    rule_sets = list_rule_sets(client, module)
    if rule_set_in(name, rule_sets):
        active = ruleset_active(client, module, name)
        if active and not module.params.get('force'):
            module.fail_json(
                msg=
                "Couldn't delete rule set {0} because it is currently active. Set force=true to delete an active ruleset."
                .format(name),
                error={
                    "code": "CannotDelete",
                    "message":
                    "Cannot delete active rule set: {0}".format(name),
                })
        if not check_mode:
            if active and module.params.get('force'):
                deactivate_rule_set(client, module)
            try:
                client.delete_receipt_rule_set(RuleSetName=name,
                                               aws_retry=True)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(
                    e, msg="Couldn't delete rule set {0}.".format(name))
        changed = True
        rule_sets = [x for x in rule_sets if x['Name'] != name]

    module.exit_json(
        changed=changed,
        rule_sets=[camel_dict_to_snake_dict(x) for x in rule_sets],
    )
Ejemplo n.º 14
0
def create_or_update_rule_set(client, module):
    name = module.params.get('name')
    check_mode = module.check_mode
    changed = False

    rule_sets = list_rule_sets(client, module)
    if not rule_set_in(name, rule_sets):
        if not check_mode:
            try:
                client.create_receipt_rule_set(RuleSetName=name,
                                               aws_retry=True)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(
                    e, msg="Couldn't create rule set {0}.".format(name))
        changed = True
        rule_sets = list(rule_sets)
        rule_sets.append({
            'Name': name,
        })

    (active_changed,
     active) = update_active_rule_set(client, module, name,
                                      module.params.get('active'))
    changed |= active_changed

    module.exit_json(
        changed=changed,
        active=active,
        rule_sets=[camel_dict_to_snake_dict(x) for x in rule_sets],
    )
def main():
    module = AnsibleAWSModule(
        argument_spec={},
        supports_check_mode=True,
    )
    if module._name == 'aws_caller_facts':
        module.deprecate(
            "The 'aws_caller_facts' module has been renamed to 'aws_caller_info'",
            version='2.13')

    client = module.client('sts')

    try:
        caller_info = client.get_caller_identity()
        caller_info.pop('ResponseMetadata', None)
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg='Failed to retrieve caller identity')

    iam_client = module.client('iam')

    try:
        # Although a list is returned by list_account_aliases AWS supports maximum one alias per account.
        # If an alias is defined it will be returned otherwise a blank string is filled in as account_alias.
        # see https://docs.aws.amazon.com/cli/latest/reference/iam/list-account-aliases.html#output
        response = iam_client.list_account_aliases()
        if response and response['AccountAliases']:
            caller_info['account_alias'] = response['AccountAliases'][0]
        else:
            caller_info['account_alias'] = ''
    except (BotoCoreError, ClientError) as e:
        # The iam:ListAccountAliases permission is required for this operation to succeed.
        # Lacking this permission is handled gracefully by not returning the account_alias.
        pass

    module.exit_json(changed=False, **camel_dict_to_snake_dict(caller_info))