def find_subnets(connection, module, vpc_id, identified_subnets):
    """
    Finds a list of subnets, each identified either by a raw ID, a unique
    'Name' tag, or a CIDR such as 10.0.0.0/8.

    Note that this function is duplicated in other ec2 modules, and should
    potentially be moved into a shared module_utils
    """
    subnet_ids = []
    subnet_names = []
    subnet_cidrs = []
    for subnet in (identified_subnets or []):
        if re.match(SUBNET_RE, subnet):
            subnet_ids.append(subnet)
        elif re.match(CIDR_RE, subnet):
            subnet_cidrs.append(subnet)
        else:
            subnet_names.append(subnet)

    subnets_by_id = []
    if subnet_ids:
        filters = ansible_dict_to_boto3_filter_list({'vpc-id': vpc_id})
        try:
            subnets_by_id = describe_subnets_with_backoff(connection, SubnetIds=subnet_ids, Filters=filters)
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't find subnet with id %s" % subnet_ids)

    subnets_by_cidr = []
    if subnet_cidrs:
        filters = ansible_dict_to_boto3_filter_list({'vpc-id': vpc_id, 'cidr': subnet_cidrs})
        try:
            subnets_by_cidr = describe_subnets_with_backoff(connection, Filters=filters)
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't find subnet with cidr %s" % subnet_cidrs)

    subnets_by_name = []
    if subnet_names:
        filters = ansible_dict_to_boto3_filter_list({'vpc-id': vpc_id, 'tag:Name': subnet_names})
        try:
            subnets_by_name = describe_subnets_with_backoff(connection, Filters=filters)
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't find subnet with names %s" % subnet_names)

        for name in subnet_names:
            matching_count = len([1 for s in subnets_by_name for t in s.get('Tags', []) if t['Key'] == 'Name' and t['Value'] == name])
            if matching_count == 0:
                module.fail_json(msg='Subnet named "{0}" does not exist'.format(name))
            elif matching_count > 1:
                module.fail_json(msg='Multiple subnets named "{0}"'.format(name))

    return subnets_by_id + subnets_by_cidr + subnets_by_name
Beispiel #2
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
Beispiel #3
0
def get_matching_subnet(conn, vpc_id, cidr):
    filters = ansible_dict_to_boto3_filter_list({'vpc-id': vpc_id, 'cidr-block': cidr})
    subnets = get_subnet_info(conn.describe_subnets(Filters=filters))
    if len(subnets) > 0:
        return subnets[0]
    else:
        return None
def ensure_subnet_association(connection=None, module=None, vpc_id=None, route_table_id=None, subnet_id=None,
                              check_mode=None):
    filters = ansible_dict_to_boto3_filter_list({'association.subnet-id': subnet_id, 'vpc-id': vpc_id})
    try:
        route_tables = describe_route_tables_with_backoff(connection, Filters=filters)
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't get route tables")
    for route_table in route_tables:
        if route_table['RouteTableId'] is None:
            continue
        for a in route_table['Associations']:
            if a['Main']:
                continue
            if a['SubnetId'] == subnet_id:
                if route_table['RouteTableId'] == route_table_id:
                    return {'changed': False, 'association_id': a['RouteTableAssociationId']}
                else:
                    if check_mode:
                        return {'changed': True}
                    try:
                        connection.disassociate_route_table(AssociationId=a['RouteTableAssociationId'])
                    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                        module.fail_json_aws(e, msg="Couldn't disassociate subnet from route table")

    try:
        association_id = connection.associate_route_table(RouteTableId=route_table_id, SubnetId=subnet_id)
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't associate subnet with route table")
    return {'changed': True, 'association_id': association_id}
def describe_subnets(connection, module):
    """
    Describe Subnets.

    module  : AnsibleModule object
    connection  : boto3 client connection object
    """
    # collect parameters
    filters = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    subnet_ids = module.params.get('subnet_ids')

    if subnet_ids is None:
        # Set subnet_ids to empty list if it is None
        subnet_ids = []

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

    # Get the basic VPC info
    try:
        response = describe_subnets_with_backoff(connection, subnet_ids, filters)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

    for subnet in response['Subnets']:
        # for backwards compatibility
        subnet['id'] = subnet['SubnetId']
        subnet_info.append(camel_dict_to_snake_dict(subnet))
        # convert tag list to ansible dict
        subnet_info[-1]['tags'] = boto3_tag_list_to_ansible_dict(subnet.get('Tags', []))

    module.exit_json(subnets=subnet_info)
Beispiel #6
0
def subnet_exists(conn, subnet_id):
    filters = ansible_dict_to_boto3_filter_list({'subnet-id': subnet_id})
    subnets = get_subnet_info(conn.describe_subnets(Filters=filters))
    if len(subnets) > 0 and 'state' in subnets[0] and subnets[0]['state'] == "available":
        return subnets[0]
    else:
        return False
Beispiel #7
0
def get_matching_subnet(conn, module, vpc_id, cidr):
    filters = ansible_dict_to_boto3_filter_list({'vpc-id': vpc_id, 'cidr-block': cidr})
    try:
        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 matching subnet")

    if subnets:
        return subnets[0]

    return None
def get_vpc_peers(client, module):
    params = dict()
    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    if module.params.get('peer_connection_ids'):
        params['VpcPeeringConnectionIds'] = module.params.get('peer_connection_ids')
    try:
        result = json.loads(json.dumps(client.describe_vpc_peering_connections(**params), default=date_handler))
    except Exception as e:
        module.fail_json(msg=str(e.message))

    return result['VpcPeeringConnections']
def get_nat_gateways(client, module, nat_gateway_id=None):
    params = dict()

    params['Filter'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    params['NatGatewayIds'] = module.params.get('nat_gateway_ids')

    try:
        result = json.loads(json.dumps(client.describe_nat_gateways(**params), default=date_handler))
    except Exception as e:
        module.fail_json(msg=str(e.message))

    return [camel_dict_to_snake_dict(gateway) for gateway in result['NatGateways']]
Beispiel #10
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            filters=dict(default={}, type='dict')
        )
    )

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)

    if region:
        connection = boto3_conn(
            module,
            conn_type='client',
            resource='ec2',
            region=region,
            endpoint=ec2_url,
            **aws_connect_params
        )
    else:
        module.fail_json(msg="region must be specified")

    # Replace filter key underscores with dashes, for compatibility, except if we're dealing with tags
    sanitized_filters = module.params.get("filters")
    for key in sanitized_filters:
        if not key.startswith("tag:"):
            sanitized_filters[key.replace("_", "-")] = sanitized_filters.pop(key)

    try:
        security_groups = connection.describe_security_groups(
            Filters=ansible_dict_to_boto3_filter_list(sanitized_filters)
        )
    except ClientError as e:
        module.fail_json(msg=e.message, exception=traceback.format_exc())

    snaked_security_groups = []
    for security_group in security_groups['SecurityGroups']:
        # Modify boto3 tags list to be ansible friendly dict
        # but don't camel case tags
        security_group = camel_dict_to_snake_dict(security_group)
        security_group['tags'] = boto3_tag_list_to_ansible_dict(security_group.get('tags', {}), tag_name_key_name='key', tag_value_key_name='value')
        snaked_security_groups.append(security_group)

    module.exit_json(security_groups=snaked_security_groups)
Beispiel #11
0
def ensure_subnet_association(connection=None,
                              module=None,
                              vpc_id=None,
                              route_table_id=None,
                              subnet_id=None,
                              check_mode=None):
    filters = ansible_dict_to_boto3_filter_list({
        'association.subnet-id': subnet_id,
        'vpc-id': vpc_id
    })
    try:
        route_tables = describe_route_tables_with_backoff(connection,
                                                          Filters=filters)
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't get route tables")
    for route_table in route_tables:
        if route_table['RouteTableId'] is None:
            continue
        for a in route_table['Associations']:
            if a['Main']:
                continue
            if a['SubnetId'] == subnet_id:
                if route_table['RouteTableId'] == route_table_id:
                    return {
                        'changed': False,
                        'association_id': a['RouteTableAssociationId']
                    }
                else:
                    if check_mode:
                        return {'changed': True}
                    try:
                        connection.disassociate_route_table(
                            AssociationId=a['RouteTableAssociationId'])
                    except (botocore.exceptions.ClientError,
                            botocore.exceptions.BotoCoreError) as e:
                        module.fail_json_aws(
                            e,
                            msg="Couldn't disassociate subnet from route table"
                        )

    try:
        association_id = connection.associate_route_table(
            RouteTableId=route_table_id, SubnetId=subnet_id)
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e,
                             msg="Couldn't associate subnet with route table")
    return {'changed': True, 'association_id': association_id}
Beispiel #12
0
def list_ec2_vpc_nacls(connection, module):

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

    if nacl_ids is None:
        nacl_ids = []

    try:
        nacls = connection.describe_network_acls(NetworkAclIds=nacl_ids,
                                                 Filters=filters)
    except ClientError as e:
        module.fail_json(msg="Unable to describe network ACLs {0}: {1}".format(
            nacl_ids, to_native(e)),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    except BotoCoreError as e:
        module.fail_json(msg="Unable to describe network ACLs {0}: {1}".format(
            nacl_ids, to_native(e)),
                         exception=traceback.format_exc())

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_nacls = []
    for nacl in nacls['NetworkAcls']:
        snaked_nacls.append(camel_dict_to_snake_dict(nacl))

    # Turn the boto3 result in to ansible friendly tag dictionary
    for nacl in snaked_nacls:
        if 'tags' in nacl:
            nacl['tags'] = boto3_tag_list_to_ansible_dict(
                nacl['tags'], 'key', 'value')
        if 'entries' in nacl:
            nacl['egress'] = [
                nacl_entry_to_list(entry) for entry in nacl['entries']
                if entry['rule_number'] < 32767 and entry['egress']
            ]
            nacl['ingress'] = [
                nacl_entry_to_list(entry) for entry in nacl['entries']
                if entry['rule_number'] < 32767 and not entry['egress']
            ]
            del nacl['entries']
        if 'associations' in nacl:
            nacl['subnets'] = [a['subnet_id'] for a in nacl['associations']]
            del nacl['associations']
        if 'network_acl_id' in nacl:
            nacl['nacl_id'] = nacl['network_acl_id']
            del nacl['network_acl_id']

    module.exit_json(nacls=snaked_nacls)
def get_vpc_peers(client, module):
    params = dict()
    params['Filters'] = ansible_dict_to_boto3_filter_list(
        module.params.get('filters'))
    if module.params.get('peer_connection_ids'):
        params['VpcPeeringConnectionIds'] = module.params.get(
            'peer_connection_ids')
    try:
        result = json.loads(
            json.dumps(client.describe_vpc_peering_connections(**params),
                       default=date_handler))
    except Exception as e:
        module.fail_json(msg=str(e.message))

    return result['VpcPeeringConnections']
Beispiel #14
0
def get_nat_gateways(client, module, nat_gateway_id=None):
    params = dict()

    params['Filter'] = ansible_dict_to_boto3_filter_list(
        module.params.get('filters'))
    params['NatGatewayIds'] = module.params.get('nat_gateway_ids')

    try:
        result = json.loads(
            json.dumps(client.describe_nat_gateways(**params),
                       default=date_handler))
    except Exception as e:
        module.fail_json(msg=str(e.message))

    return result['NatGateways']
Beispiel #15
0
def find_igw(connection, module, vpc_id):
    """
    Finds the Internet gateway for the given VPC ID.
    """
    filters = ansible_dict_to_boto3_filter_list({'attachment.vpc-id': vpc_id})
    try:
        igw = connection.describe_internet_gateways(Filters=filters)['InternetGateways']
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg='No IGW found for VPC {0}'.format(vpc_id))
    if len(igw) == 1:
        return igw[0]['InternetGatewayId']
    elif len(igw) == 0:
        module.fail_json(msg='No IGWs found for VPC {0}'.format(vpc_id))
    else:
        module.fail_json(msg='Multiple IGWs found for VPC {0}'.format(vpc_id))
Beispiel #16
0
def list_internet_gateways(client, module):
    params = dict()

    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))

    if module.params.get("internet_gateway_ids"):
        params['InternetGatewayIds'] = module.params.get("internet_gateway_ids")

    try:
        all_internet_gateways = client.describe_internet_gateways(**params)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=str(e))

    return [camel_dict_to_snake_dict(get_internet_gateway_info(igw))
            for igw in all_internet_gateways['InternetGateways']]
Beispiel #17
0
def allocate_address(ec2,
                     module,
                     domain,
                     reuse_existing_ip_allowed,
                     check_mode,
                     tag_dict=None,
                     public_ipv4_pool=None):
    """ Allocate a new elastic IP address (when needed) and return it """
    if reuse_existing_ip_allowed:
        filters = []
        if not domain:
            domain = 'standard'
        filters.append({'Name': 'domain', "Values": [domain]})

        if tag_dict is not None:
            filters += ansible_dict_to_boto3_filter_list(tag_dict)

        try:
            all_addresses = ec2.describe_addresses(Filters=filters,
                                                   aws_retry=True)
        except (botocore.exceptions.BotoCoreError,
                botocore.exceptions.ClientError) as e:
            module.fail_json_aws(
                e, msg="Couldn't obtain list of existing Elastic IP addresses")

        all_addresses = all_addresses["Addresses"]

        if domain == 'vpc':
            unassociated_addresses = [
                a for a in all_addresses if not a.get('AssociationId', None)
            ]
        else:
            unassociated_addresses = [
                a for a in all_addresses if not a['InstanceId']
            ]
        if unassociated_addresses:
            return unassociated_addresses[0], False

    if public_ipv4_pool:
        return allocate_address_from_pool(ec2, module, domain, check_mode,
                                          public_ipv4_pool), True

    try:
        result = ec2.allocate_address(Domain=domain, aws_retry=True), True
    except (botocore.exceptions.BotoCoreError,
            botocore.exceptions.ClientError) as e:
        module.fail_json_aws(e, msg="Couldn't allocate Elastic IP address")
    return result
Beispiel #18
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(filters=dict(default={}, type='dict')))

    module = AnsibleModule(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')

    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    region, ec2_url, aws_connect_params = get_aws_connection_info(module,
                                                                  boto3=True)
    connection = boto3_conn(module,
                            conn_type='client',
                            resource='ec2',
                            region=region,
                            endpoint=ec2_url,
                            **aws_connect_params)

    # 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 ClientError as e:
        module.fail_json(
            msg="Unable to describe availability zones: {0}".format(
                to_native(e)),
            exception=traceback.format_exc(),
            **camel_dict_to_snake_dict(e.response))
    except BotoCoreError as e:
        module.fail_json(
            msg="Unable to describe availability zones: {0}".format(
                to_native(e)),
            exception=traceback.format_exc())

    # 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)
Beispiel #19
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(filters=dict(default={}, type='dict')))

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    region, ec2_url, aws_connect_params = get_aws_connection_info(module,
                                                                  boto3=True)

    if region:
        connection = boto3_conn(module,
                                conn_type='client',
                                resource='ec2',
                                region=region,
                                endpoint=ec2_url,
                                **aws_connect_params)
    else:
        module.fail_json(msg="region must be specified")

    # Replace filter key underscores with dashes, for compatibility, except if we're dealing with tags
    sanitized_filters = module.params.get("filters")
    for key in sanitized_filters:
        if not key.startswith("tag:"):
            sanitized_filters[key.replace("_",
                                          "-")] = sanitized_filters.pop(key)

    try:
        security_groups = connection.describe_security_groups(
            Filters=ansible_dict_to_boto3_filter_list(sanitized_filters))
    except ClientError as e:
        module.fail_json(msg=e.message, exception=traceback.format_exc())

    snaked_security_groups = []
    for security_group in security_groups['SecurityGroups']:
        # Modify boto3 tags list to be ansible friendly dict
        # but don't camel case tags
        security_group = camel_dict_to_snake_dict(security_group)
        security_group['tags'] = boto3_tag_list_to_ansible_dict(
            security_group['tags'],
            tag_name_key_name='key',
            tag_value_key_name='value')
        snaked_security_groups.append(security_group)

    module.exit_json(security_groups=snaked_security_groups)
Beispiel #20
0
def get_matching_subnet(conn, module, vpc_id, cidr):
    filters = ansible_dict_to_boto3_filter_list({
        'vpc-id': vpc_id,
        'cidr-block': cidr
    })
    try:
        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 matching subnet")

    if subnets:
        return subnets[0]

    return None
Beispiel #21
0
def list_virtual_gateways(client, module):
    params = dict()

    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    params['DryRun'] = module.check_mode

    if module.params.get("vpn_gateway_ids"):
        params['VpnGatewayIds'] = module.params.get("vpn_gateway_ids")

    try:
        all_virtual_gateways = client.describe_vpn_gateways(**params)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=str(e), exception=traceback.format_exc())

    return [camel_dict_to_snake_dict(get_virtual_gateway_info(vgw))
            for vgw in all_virtual_gateways['VpnGateways']]
Beispiel #22
0
def ensure_tags(conn, module, subnet, tags, purge_tags, start_time):
    changed = False

    filters = ansible_dict_to_boto3_filter_list({'resource-id': subnet['id'], 'resource-type': 'subnet'})
    try:
        cur_tags = conn.describe_tags(Filters=filters)
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't describe tags")

    to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(cur_tags.get('Tags')), tags, purge_tags)

    if to_update:
        try:
            if not module.check_mode:
                AWSRetry.exponential_backoff(
                    catch_extra_error_codes=['InvalidSubnetID.NotFound']
                )(conn.create_tags)(
                    Resources=[subnet['id']],
                    Tags=ansible_dict_to_boto3_tag_list(to_update)
                )

            changed = True
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't create tags")

    if to_delete:
        try:
            if not module.check_mode:
                tags_list = []
                for key in to_delete:
                    tags_list.append({'Key': key})

                AWSRetry.exponential_backoff(
                    catch_extra_error_codes=['InvalidSubnetID.NotFound']
                )(conn.delete_tags)(Resources=[subnet['id']], Tags=tags_list)

            changed = True
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't delete tags")

    if module.params['wait'] and not module.check_mode:
        # Wait for tags to be updated
        filters = [{'Name': 'tag:{0}'.format(k), 'Values': [v]} for k, v in tags.items()]
        handle_waiter(conn, module, 'subnet_exists',
                      {'SubnetIds': [subnet['id']], 'Filters': filters}, start_time)

    return changed
def ensure_tags(conn, module, subnet, tags, purge_tags, start_time):
    changed = False

    filters = ansible_dict_to_boto3_filter_list({'resource-id': subnet['id'], 'resource-type': 'subnet'})
    try:
        cur_tags = conn.describe_tags(Filters=filters)
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't describe tags")

    to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(cur_tags.get('Tags')), tags, purge_tags)

    if to_update:
        try:
            if not module.check_mode:
                AWSRetry.exponential_backoff(
                    catch_extra_error_codes=['InvalidSubnetID.NotFound']
                )(conn.create_tags)(
                    Resources=[subnet['id']],
                    Tags=ansible_dict_to_boto3_tag_list(to_update)
                )

            changed = True
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't create tags")

    if to_delete:
        try:
            if not module.check_mode:
                tags_list = []
                for key in to_delete:
                    tags_list.append({'Key': key})

                AWSRetry.exponential_backoff(
                    catch_extra_error_codes=['InvalidSubnetID.NotFound']
                )(conn.delete_tags)(Resources=[subnet['id']], Tags=tags_list)

            changed = True
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't delete tags")

    if module.params['wait'] and not module.check_mode:
        # Wait for tags to be updated
        filters = [{'Name': 'tag:{0}'.format(k), 'Values': [v]} for k, v in tags.items()]
        handle_waiter(conn, module, 'subnet_exists',
                      {'SubnetIds': [subnet['id']], 'Filters': filters}, start_time)

    return changed
Beispiel #24
0
def get_eips_details(module):
    connection = module.client('ec2')
    filters = module.params.get("filters")
    try:
        response = connection.describe_addresses(
            Filters=ansible_dict_to_boto3_filter_list(filters)
        )
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(
            e,
            msg="Error retrieving EIPs")

    addresses = camel_dict_to_snake_dict(response)['addresses']
    for address in addresses:
        if 'tags' in address:
            address['tags'] = boto3_tag_list_to_ansible_dict(address['tags'])
    return addresses
Beispiel #25
0
def list_vpn_connections(connection, module):
    params = dict()

    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    params['VpnConnectionIds'] = module.params.get('vpn_connection_ids')

    try:
        result = json.loads(json.dumps(connection.describe_vpn_connections(**params), default=date_handler))
    except ValueError as e:
        module.fail_json_aws(e, msg="Cannot validate JSON data")
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Could not describe customer gateways")
    snaked_vpn_connections = [camel_dict_to_snake_dict(vpn_connection) for vpn_connection in result['VpnConnections']]
    if snaked_vpn_connections:
        for vpn_connection in snaked_vpn_connections:
            vpn_connection['tags'] = boto3_tag_list_to_ansible_dict(vpn_connection.get('tags', []))
    module.exit_json(changed=False, vpn_connections=snaked_vpn_connections)
Beispiel #26
0
def list_internet_gateways(client, module):
    params = dict()

    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))

    if module.params.get("internet_gateway_ids"):
        params['InternetGatewayIds'] = module.params.get("internet_gateway_ids")

    try:
        all_internet_gateways = client.describe_internet_gateways(**params)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=str(e))

    snaked_internet_gateways = [camel_dict_to_snake_dict(get_internet_gateway_info(igw))
                                for igw in all_internet_gateways['InternetGateways']]

    module.exit_json(internet_gateways=snaked_internet_gateways)
def list_dhcp_options(client, module):
    params = dict(Filters=ansible_dict_to_boto3_filter_list(module.params.get('filters')))

    if module.params.get("dry_run"):
        params['DryRun'] = True

    if module.params.get("dhcp_options_ids"):
        params['DhcpOptionsIds'] = module.params.get("dhcp_options_ids")

    try:
        all_dhcp_options = client.describe_dhcp_options(**params)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=str(e), exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    return [camel_dict_to_snake_dict(get_dhcp_options_info(option))
            for option in all_dhcp_options['DhcpOptions']]
Beispiel #28
0
def get_eips_details(module):
    connection = module.client('ec2')
    filters = module.params.get("filters")
    try:
        response = connection.describe_addresses(
            Filters=ansible_dict_to_boto3_filter_list(filters)
        )
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(
            e,
            msg="Error retrieving EIPs")

    addresses = camel_dict_to_snake_dict(response)['addresses']
    for address in addresses:
        if 'tags' in address:
            address['tags'] = boto3_tag_list_to_ansible_dict(address['tags'])
    return addresses
Beispiel #29
0
def list_ec2_images(ec2_client, module):

    image_ids = module.params.get("image_ids")
    owners = module.params.get("owners")
    executable_users = module.params.get("executable_users")
    filters = module.params.get("filters")
    owner_param = []

    # describe_images is *very* slow if you pass the `Owners`
    # param (unless it's self), for some reason.
    # Converting the owners to filters and removing from the
    # owners param greatly speeds things up.
    # Implementation based on aioue's suggestion in #24886
    for owner in owners:
        if owner.isdigit():
            if 'owner-id' not in filters:
                filters['owner-id'] = list()
            filters['owner-id'].append(owner)
        elif owner == 'self':
            # self not a valid owner-alias filter (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html)
            owner_param.append(owner)
        else:
            if 'owner-alias' not in filters:
                filters['owner-alias'] = list()
            filters['owner-alias'].append(owner)

    filters = ansible_dict_to_boto3_filter_list(filters)

    try:
        images = ec2_client.describe_images(ImageIds=image_ids, Filters=filters, Owners=owner_param, ExecutableUsers=executable_users)
        images = [camel_dict_to_snake_dict(image) for image in images["Images"]]
    except (ClientError, BotoCoreError) as err:
        module.fail_json_aws(err, msg="error describing images")
    for image in images:
        try:
            image['tags'] = boto3_tag_list_to_ansible_dict(image.get('tags', []))
            if module.params.get("describe_image_attributes"):
                launch_permissions = ec2_client.describe_image_attribute(Attribute='launchPermission', ImageId=image['image_id'])['LaunchPermissions']
                image['launch_permissions'] = [camel_dict_to_snake_dict(perm) for perm in launch_permissions]
        except (ClientError, BotoCoreError) as err:
            # describing launch permissions of images owned by others is not permitted, but shouldn't cause failures
            pass

    images.sort(key=lambda e: e.get('creation_date', ''))  # it may be possible that creation_date does not always exist
    module.exit_json(images=images)
def disassociate_ipv6_cidr(conn, module, subnet, start_time):
    if subnet.get('assign_ipv6_address_on_creation'):
        ensure_assign_ipv6_on_create(conn, module, subnet, False, False, start_time)

    try:
        conn.disassociate_subnet_cidr_block(AssociationId=subnet['ipv6_association_id'])
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't disassociate ipv6 cidr block id {0} from subnet {1}"
                             .format(subnet['ipv6_association_id'], subnet['id']))

    # Wait for cidr block to be disassociated
    if module.params['wait']:
        filters = ansible_dict_to_boto3_filter_list(
            {'ipv6-cidr-block-association.state': ['disassociated'],
             'vpc-id': subnet['vpc_id']}
        )
        handle_waiter(conn, module, 'subnet_exists',
                      {'SubnetIds': [subnet['id']], 'Filters': filters}, start_time)
Beispiel #31
0
def disassociate_ipv6_cidr(conn, module, subnet, start_time):
    if subnet.get('assign_ipv6_address_on_creation'):
        ensure_assign_ipv6_on_create(conn, module, subnet, False, False, start_time)

    try:
        conn.disassociate_subnet_cidr_block(AssociationId=subnet['ipv6_association_id'])
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't disassociate ipv6 cidr block id {0} from subnet {1}"
                             .format(subnet['ipv6_association_id'], subnet['id']))

    # Wait for cidr block to be disassociated
    if module.params['wait']:
        filters = ansible_dict_to_boto3_filter_list(
            {'ipv6-cidr-block-association.state': ['disassociated'],
             'vpc-id': subnet['vpc_id']}
        )
        handle_waiter(conn, module, 'subnet_exists',
                      {'SubnetIds': [subnet['id']], 'Filters': filters}, start_time)
Beispiel #32
0
def list_ec2_snapshots_boto3(connection, module):

    if module.params.get("filters") is None:
        filters = []
    else:
        filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))

    try:
        network_interfaces_result = connection.describe_network_interfaces(Filters=filters)
    except (ClientError, NoCredentialsError) as e:
        module.fail_json(msg=e.message)

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_network_interfaces_result = camel_dict_to_snake_dict(network_interfaces_result)
    for network_interfaces in snaked_network_interfaces_result['network_interfaces']:
        network_interfaces['tag_set'] = boto3_tag_list_to_ansible_dict(network_interfaces['tag_set'])

    module.exit_json(**snaked_network_interfaces_result)
def get_endpoints(client, module):
    results = list()
    params = dict()
    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    if module.params.get('vpc_endpoint_ids'):
        params['VpcEndpointIds'] = module.params.get('vpc_endpoint_ids')
    while True:
        response = client.describe_vpc_endpoints(**params)
        results.extend(response['VpcEndpoints'])
        if 'NextToken' in response:
            params['NextToken'] = response['NextToken']
        else:
            break
    try:
        results = json.loads(json.dumps(results, default=date_handler))
    except Exception as e:
        module.fail_json(msg=str(e.message))
    return dict(vpc_endpoints=[camel_dict_to_snake_dict(result) for result in results])
Beispiel #34
0
def get_route_table_by_tags(connection, module, vpc_id, tags):
    count = 0
    route_table = None
    filters = ansible_dict_to_boto3_filter_list({'vpc-id': vpc_id})
    try:
        route_tables = describe_route_tables_with_backoff(connection, Filters=filters)
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't get route table")
    for table in route_tables:
        this_tags = describe_tags_with_backoff(connection, table['RouteTableId'])
        if tags_match(tags, this_tags):
            route_table = table
            count += 1

    if count > 1:
        module.fail_json(msg="Tags provided do not identify a unique route table")
    else:
        return route_table
def list_customer_gateways(connection, module):
    params = dict()

    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    params['CustomerGatewayIds'] = module.params.get('customer_gateway_ids')

    try:
        result = json.loads(json.dumps(connection.describe_customer_gateways(**params), default=date_handler))
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Could not describe customer gateways")
    snaked_customer_gateways = [camel_dict_to_snake_dict(gateway) for gateway in result['CustomerGateways']]
    if snaked_customer_gateways:
        for customer_gateway in snaked_customer_gateways:
            customer_gateway['tags'] = boto3_tag_list_to_ansible_dict(customer_gateway.get('tags', []))
            customer_gateway_name = customer_gateway['tags'].get('Name')
            if customer_gateway_name:
                customer_gateway['customer_gateway_name'] = customer_gateway_name
    module.exit_json(changed=False, customer_gateways=snaked_customer_gateways)
Beispiel #36
0
def list_virtual_gateways(client, module):
    params = dict()

    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    params['DryRun'] = module.check_mode

    if module.params.get("vpn_gateway_ids"):
        params['VpnGatewayIds'] = module.params.get("vpn_gateway_ids")

    try:
        all_virtual_gateways = client.describe_vpn_gateways(**params)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=str(e),exception=traceback.format_exc())

    snaked_vgws = [camel_dict_to_snake_dict(get_virtual_gateway_info(vgw))
                                for vgw in all_virtual_gateways['VpnGateways']]

    module.exit_json(virtual_gateways=snaked_vgws)
def get_endpoints(client, module):
    results = list()
    params = dict()
    params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    if module.params.get('vpc_endpoint_ids'):
        params['VpcEndpointIds'] = module.params.get('vpc_endpoint_ids')
    while True:
        response = client.describe_vpc_endpoints(**params)
        results.extend(response['VpcEndpoints'])
        if 'NextToken' in response:
            params['NextToken'] = response['NextToken']
        else:
            break
    try:
        results = json.loads(json.dumps(results, default=date_handler))
    except Exception as e:
        module.fail_json(msg=str(e.message))
    return dict(vpc_endpoints=[camel_dict_to_snake_dict(result) for result in results])
Beispiel #38
0
def list_ec2_images(ec2_client, module):

    image_ids = module.params.get("image_ids")
    owners = module.params.get("owners")
    executable_users = module.params.get("executable_users")
    filters = module.params.get("filters")
    owner_param = []

    # describe_images is *very* slow if you pass the `Owners`
    # param (unless it's self), for some reason.
    # Converting the owners to filters and removing from the
    # owners param greatly speeds things up.
    # Implementation based on aioue's suggestion in #24886
    for owner in owners:
        if owner.isdigit():
            if 'owner-id' not in filters:
                filters['owner-id'] = list()
            filters['owner-id'].append(owner)
        elif owner == 'self':
            # self not a valid owner-alias filter (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html)
            owner_param.append(owner)
        else:
            if 'owner-alias' not in filters:
                filters['owner-alias'] = list()
            filters['owner-alias'].append(owner)

    filters = ansible_dict_to_boto3_filter_list(filters)

    try:
        images = ec2_client.describe_images(ImageIds=image_ids, Filters=filters, Owners=owner_param, ExecutableUsers=executable_users)
        images = [camel_dict_to_snake_dict(image) for image in images["Images"]]
    except (ClientError, BotoCoreError) as err:
        module.fail_json_aws(err, msg="error describing images")
    for image in images:
        try:
            image['tags'] = boto3_tag_list_to_ansible_dict(image.get('tags', []))
            if module.params.get("describe_image_attributes"):
                launch_permissions = ec2_client.describe_image_attribute(Attribute='launchPermission', ImageId=image['image_id'])['LaunchPermissions']
                image['launch_permissions'] = [camel_dict_to_snake_dict(perm) for perm in launch_permissions]
        except (ClientError, BotoCoreError) as err:
            # describing launch permissions of images owned by others is not permitted, but shouldn't cause failures
            pass

    module.exit_json(images=images)
Beispiel #39
0
def ensure_tags(conn, module, subnet, tags, purge_tags):
    changed = False

    filters = ansible_dict_to_boto3_filter_list({
        'resource-id': subnet['id'],
        'resource-type': 'subnet'
    })
    try:
        cur_tags = conn.describe_tags(Filters=filters)
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg="Couldn't describe tags")

    to_update, to_delete = compare_aws_tags(
        boto3_tag_list_to_ansible_dict(cur_tags.get('Tags')), tags, purge_tags)

    if to_update:
        try:
            if not module.check_mode:
                conn.create_tags(
                    Resources=[subnet['id']],
                    Tags=ansible_dict_to_boto3_tag_list(to_update))

            changed = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't create tags")

    if to_delete:
        try:
            if not module.check_mode:
                tags_list = []
                for key in to_delete:
                    tags_list.append({'Key': key})

                conn.delete_tags(Resources=[subnet['id']], Tags=tags_list)

            changed = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't delete tags")

    return changed
Beispiel #40
0
def list_ec2_eni_boto3(connection, module):

    if module.params.get("filters") is None:
        filters = []
    else:
        filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))

    try:
        network_interfaces_result = connection.describe_network_interfaces(Filters=filters)['NetworkInterfaces']
    except (ClientError, NoCredentialsError) as e:
        module.fail_json(msg=e.message)

    # Modify boto3 tags list to be ansible friendly dict and then camel_case
    camel_network_interfaces = []
    for network_interface in network_interfaces_result:
        network_interface['TagSet'] = boto3_tag_list_to_ansible_dict(network_interface['TagSet'])
        camel_network_interfaces.append(camel_dict_to_snake_dict(network_interface))

    module.exit_json(network_interfaces=camel_network_interfaces)
def list_dhcp_options(client, module):
    params = dict(Filters=ansible_dict_to_boto3_filter_list(module.params.get('filters')))

    if module.params.get("dry_run"):
        params['DryRun'] = True

    if module.params.get("dhcp_options_ids"):
        params['DhcpOptionsIds'] = module.params.get("dhcp_options_ids")

    try:
        all_dhcp_options = client.describe_dhcp_options(**params)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=str(e), exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    results = [camel_dict_to_snake_dict(get_dhcp_options_info(option))
               for option in all_dhcp_options['DhcpOptions']]

    module.exit_json(dhcp_options=results)
Beispiel #42
0
def list_ec2_images(ec2_client, module):

    image_ids = module.params.get("image_ids")
    filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
    owners = module.params.get("owners")
    executable_users = module.params.get("executable_users")

    try:
        images = ec2_client.describe_images(ImageIds=image_ids, Filters=filters, Owners=owners, ExecutableUsers=executable_users)
        images = [camel_dict_to_snake_dict(image) for image in images["Images"]]
        for image in images:
            launch_permissions = ec2_client.describe_image_attribute(Attribute='launchPermission', ImageId=image['image_id'])['LaunchPermissions']
            image['launch_permissions'] = [camel_dict_to_snake_dict(perm) for perm in launch_permissions]
    except (ClientError, BotoCoreError) as err:
        module.fail_json_aws(err, msg="error describing images")

    for image in images:
        image['tags'] = boto3_tag_list_to_ansible_dict(image.get('tags', []), 'key', 'value')

    module.exit_json(images=images)
Beispiel #43
0
def list_ec2_volumes(connection, module, region):

    # Replace filter key underscores with dashes, for compatibility, except if we're dealing with tags
    sanitized_filters = module.params.get("filters")
    for key in list(sanitized_filters):
        if not key.startswith("tag:"):
            sanitized_filters[key.replace("_",
                                          "-")] = sanitized_filters.pop(key)
    volume_dict_array = []

    try:
        all_volumes = describe_volumes_with_backoff(
            connection, ansible_dict_to_boto3_filter_list(sanitized_filters))
    except ClientError as e:
        module.fail_json(msg=e.response, exception=traceback.format_exc())

    for volume in all_volumes["Volumes"]:
        volume = camel_dict_to_snake_dict(volume, ignore_list=['Tags'])
        volume_dict_array.append(get_volume_info(volume, region))
    module.exit_json(volumes=volume_dict_array)
    def get_matching_tgw(self, tgw_id, description=None, skip_deleted=True):
        """ search for  an existing tgw by either tgw_id or description
        :param tgw_id:  The AWS id of the transit gateway
        :param description:  The description of the transit gateway.
        :param skip_deleted: ignore deleted transit gateways
        :return dict: transit gateway object
        """
        filters = []
        if tgw_id:
            filters = ansible_dict_to_boto3_filter_list(
                {'transit-gateway-id': tgw_id})

        try:
            response = self._connection.describe_transit_gateways(
                Filters=filters)
        except (ClientError, BotoCoreError) as e:
            self._module.fail_json_aws(e)

        tgw = None
        tgws = []

        if len(response.get('TransitGateways', [])) == 1 and tgw_id:
            if (response['TransitGateways'][0]['State'] !=
                    'deleted') or not skip_deleted:
                tgws.extend(response['TransitGateways'])

        for gateway in response.get('TransitGateways', []):
            if description == gateway[
                    'Description'] and gateway['State'] != 'deleted':
                tgws.append(gateway)

        if len(tgws) > 1:
            self._module.fail_json(
                msg=
                'EC2 returned more than one transit Gateway for description {0}, aborting'
                .format(description))
        elif tgws:
            tgw = camel_dict_to_snake_dict(tgws[0], ignore_list=['Tags'])
            tgw['tags'] = boto3_tag_list_to_ansible_dict(tgws[0]['Tags'])

        return tgw
Beispiel #45
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            filters=dict(default={}, type='dict')
        )
    )

    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
    connection = boto3_conn(
        module,
        conn_type='client',
        resource='ec2',
        region=region,
        endpoint=ec2_url,
        **aws_connect_params
    )

    # 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 ClientError as e:
        module.fail_json(msg="Unable to describe availability zones: {0}".format(to_native(e)),
                         exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
    except BotoCoreError as e:
        module.fail_json(msg="Unable to describe availability zones: {0}".format(to_native(e)),
                         exception=traceback.format_exc())

    # 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)
Beispiel #46
0
    def parse(self, inventory, loader, path, cache=True):

        super(InventoryModule, self).parse(inventory, loader, path)

        self._read_config_data(path)

        if self.get_option('use_contrib_script_compatible_sanitization'):
            self._sanitize_group_name = self._legacy_script_compatible_group_sanitization

        self._set_credentials()

        # get user specifications
        regions = self.get_option('regions')
        filters = ansible_dict_to_boto3_filter_list(self.get_option('filters'))
        hostnames = self.get_option('hostnames')
        strict_permissions = self.get_option('strict_permissions')

        cache_key = self.get_cache_key(path)
        # false when refresh_cache or --flush-cache is used
        if cache:
            # get the user-specified directive
            cache = self.get_option('cache')

        # Generate inventory
        cache_needs_update = False
        if cache:
            try:
                results = self.cache.get(cache_key)
            except KeyError:
                # if cache expires or cache file doesn't exist
                cache_needs_update = True

        if not cache or cache_needs_update:
            results = self._query(regions, filters, strict_permissions)

        self._populate(results, hostnames)

        # If the cache has expired/doesn't exist or if refresh_inventory/flush cache is used
        # when the user is using caching, update the cached inventory
        if cache_needs_update or (not cache and self.get_option('cache')):
            self.cache.set(cache_key, results)
Beispiel #47
0
def list_eni(connection, module):

    if module.params.get("filters") is None:
        filters = []
    else:
        filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))

    try:
        network_interfaces_result = connection.describe_network_interfaces(Filters=filters)['NetworkInterfaces']
    except (ClientError, NoCredentialsError) as e:
        module.fail_json(msg=e.message)

    # Modify boto3 tags list to be ansible friendly dict and then camel_case
    camel_network_interfaces = []
    for network_interface in network_interfaces_result:
        network_interface['TagSet'] = boto3_tag_list_to_ansible_dict(network_interface['TagSet'])
        # Added id to interface info to be compatible with return values of ec2_eni module:
        network_interface['Id'] = network_interface['NetworkInterfaceId']
        camel_network_interfaces.append(camel_dict_to_snake_dict(network_interface))

    module.exit_json(network_interfaces=camel_network_interfaces)
Beispiel #48
0
def list_ec2_vpc_nacls(connection, module):

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

    if nacl_ids is None:
        nacl_ids = []

    try:
        nacls = connection.describe_network_acls(aws_retry=True, NetworkAclIds=nacl_ids, Filters=filters)
    except ClientError as e:
        if e.response['Error']['Code'] == 'InvalidNetworkAclID.NotFound':
            module.fail_json(msg='Unable to describe ACL.  NetworkAcl does not exist')
        module.fail_json_aws(e, msg="Unable to describe network ACLs {0}".format(nacl_ids))
    except BotoCoreError as e:
        module.fail_json_aws(e, msg="Unable to describe network ACLs {0}".format(nacl_ids))

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_nacls = []
    for nacl in nacls['NetworkAcls']:
        snaked_nacls.append(camel_dict_to_snake_dict(nacl))

    # Turn the boto3 result in to ansible friendly tag dictionary
    for nacl in snaked_nacls:
        if 'tags' in nacl:
            nacl['tags'] = boto3_tag_list_to_ansible_dict(nacl['tags'], 'key', 'value')
        if 'entries' in nacl:
            nacl['egress'] = [nacl_entry_to_list(entry) for entry in nacl['entries']
                              if entry['rule_number'] < 32767 and entry['egress']]
            nacl['ingress'] = [nacl_entry_to_list(entry) for entry in nacl['entries']
                               if entry['rule_number'] < 32767 and not entry['egress']]
            del nacl['entries']
        if 'associations' in nacl:
            nacl['subnets'] = [a['subnet_id'] for a in nacl['associations']]
            del nacl['associations']
        if 'network_acl_id' in nacl:
            nacl['nacl_id'] = nacl['network_acl_id']
            del nacl['network_acl_id']

    module.exit_json(nacls=snaked_nacls)
def list_ec2_vpc_nacls(connection, module):

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

    if nacl_ids is None:
        nacl_ids = []

    try:
        nacls = connection.describe_network_acls(NetworkAclIds=nacl_ids, Filters=filters)
    except ClientError as e:
        module.fail_json(msg="Unable to describe network ACLs {0}: {1}".format(nacl_ids, to_native(e)),
                         exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
    except BotoCoreError as e:
        module.fail_json(msg="Unable to describe network ACLs {0}: {1}".format(nacl_ids, to_native(e)),
                         exception=traceback.format_exc())

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_nacls = []
    for nacl in nacls['NetworkAcls']:
        snaked_nacls.append(camel_dict_to_snake_dict(nacl))

    # Turn the boto3 result in to ansible friendly tag dictionary
    for nacl in snaked_nacls:
        if 'tags' in nacl:
            nacl['tags'] = boto3_tag_list_to_ansible_dict(nacl['tags'], 'key', 'value')
        if 'entries' in nacl:
            nacl['egress'] = [nacl_entry_to_list(entry) for entry in nacl['entries']
                              if entry['rule_number'] < 32767 and entry['egress']]
            nacl['ingress'] = [nacl_entry_to_list(entry) for entry in nacl['entries']
                               if entry['rule_number'] < 32767 and not entry['egress']]
            del nacl['entries']
        if 'associations' in nacl:
            nacl['subnets'] = [a['subnet_id'] for a in nacl['associations']]
            del nacl['associations']
        if 'network_acl_id' in nacl:
            nacl['nacl_id'] = nacl['network_acl_id']
            del nacl['network_acl_id']

    module.exit_json(nacls=snaked_nacls)
Beispiel #50
0
    def _get_query_options(self, config_data):
        '''
            :param config_data: contents of the inventory config file
            :return A list of regions to query,
                    a list of boto3 filter dicts,
                    a list of possible hostnames in order of preference
                    a boolean to indicate whether to fail on permission errors
        '''
        options = {
            'regions': {
                'type_to_be': list,
                'value': config_data.get('regions', [])
            },
            'filters': {
                'type_to_be': dict,
                'value': config_data.get('filters', {})
            },
            'hostnames': {
                'type_to_be': list,
                'value': config_data.get('hostnames', [])
            },
            'strict_permissions': {
                'type_to_be': bool,
                'value': config_data.get('strict_permissions', True)
            }
        }

        # validate the options
        for name in options:
            options[name]['value'] = self._validate_option(
                name, options[name]['type_to_be'], options[name]['value'])

        regions = options['regions']['value']
        filters = ansible_dict_to_boto3_filter_list(
            options['filters']['value'])
        hostnames = options['hostnames']['value']
        strict_permissions = options['strict_permissions']['value']

        return regions, filters, hostnames, strict_permissions
Beispiel #51
0
def list_ec2_vpc_nacls(connection, module):

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

    try:
        nacls = connection.describe_network_acls(NetworkAclIds=nacl_ids,
                                                 Filters=filters)
    except (ClientError, NoCredentialsError) as e:
        module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response))

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_nacls = []
    for nacl in nacls['NetworkAcls']:
        snaked_nacls.append(camel_dict_to_snake_dict(nacl))

    # Turn the boto3 result in to ansible friendly tag dictionary
    for nacl in snaked_nacls:
        if 'tags' in nacl:
            nacl['tags'] = boto3_tag_list_to_ansible_dict(
                nacl['tags'], 'key', 'value')
        if 'entries' in nacl:
            nacl['egress'] = [
                nacl_entry_to_list(entry) for entry in nacl['entries']
                if entry['rule_number'] != 32767 and entry['egress']
            ]
            nacl['ingress'] = [
                nacl_entry_to_list(entry) for entry in nacl['entries']
                if entry['rule_number'] != 32767 and not entry['egress']
            ]
            del nacl['entries']
        if 'associations' in nacl:
            nacl['subnets'] = [a['subnet_id'] for a in nacl['associations']]
            del nacl['associations']
        if 'network_acl_id' in nacl:
            nacl['nacl_id'] = nacl['network_acl_id']
            del nacl['network_acl_id']

    module.exit_json(nacls=snaked_nacls)
Beispiel #52
0
    def get_matching_igw(self, vpc_id):
        filters = ansible_dict_to_boto3_filter_list(
            {'attachment.vpc-id': vpc_id})
        igws = []
        try:
            response = self._connection.describe_internet_gateways(
                Filters=filters)
            igws = response.get('InternetGateways', [])
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            self._module.fail_json_aws(e)

        igw = None
        if len(igws) > 1:
            self._module.fail_json(
                msg=
                'EC2 returned more than one Internet Gateway for VPC {0}, aborting'
                .format(vpc_id))
        elif igws:
            igw = camel_dict_to_snake_dict(igws[0])

        return igw
Beispiel #53
0
def list_ec2_snapshots(connection, module):

    snapshot_ids = module.params.get("snapshot_ids")
    owner_ids = map(str, module.params.get("owner_ids"))
    restorable_by_user_ids = module.params.get("restorable_by_user_ids")
    filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))

    try:
        snapshots = connection.describe_snapshots(SnapshotIds=snapshot_ids, OwnerIds=owner_ids, RestorableByUserIds=restorable_by_user_ids, Filters=filters)
    except ClientError as e:
        module.fail_json(msg=e.message)

    # Turn the boto3 result in to ansible_friendly_snaked_names
    snaked_snapshots = []
    for snapshot in snapshots['Snapshots']:
        snaked_snapshots.append(camel_dict_to_snake_dict(snapshot))

    # Turn the boto3 result in to ansible friendly tag dictionary
    for snapshot in snaked_snapshots:
        if 'tags' in snapshot:
            snapshot['tags'] = boto3_tag_list_to_ansible_dict(snapshot['tags'], 'key', 'value')

    module.exit_json(snapshots=snaked_snapshots)
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 describe_vpcs(connection, module):
    """
    Describe VPCs.

    connection  : boto3 client connection object
    module  : AnsibleModule object
    """
    # collect parameters
    filters = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    vpc_ids = module.params.get('vpc_ids')

    # init empty list for return vars
    vpc_info = list()
    vpc_list = list()

    # Get the basic VPC info
    try:
        response = connection.describe_vpcs(VpcIds=vpc_ids, Filters=filters)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Unable to describe VPCs {0}: {1}".format(vpc_ids, to_native(e)),
                         exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
    except botocore.exceptions.BotoCoreError as e:
        module.fail_json(msg="Unable to describe VPCs {0}: {1}".format(vpc_ids, to_native(e)),
                         exception=traceback.format_exc())

    # Loop through results and create a list of VPC IDs
    for vpc in response['Vpcs']:
        vpc_list.append(vpc['VpcId'])

    # We can get these results in bulk but still needs two separate calls to the API
    try:
        cl_enabled = connection.describe_vpc_classic_link(VpcIds=vpc_list)
    except botocore.exceptions.ClientError as e:
        if e.response["Error"]["Message"] == "The functionality you requested is not available in this region.":
            cl_enabled = {'Vpcs': [{'VpcId': vpc_id, 'ClassicLinkEnabled': False} for vpc_id in vpc_list]}
        else:
            module.fail_json(msg="Unable to describe if ClassicLink is enabled: {0}".format(to_native(e)),
                             exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
    except botocore.exceptions.BotoCoreError as e:
        module.fail_json(msg="Unable to describe if ClassicLink is enabled: {0}".format(to_native(e)),
                         exception=traceback.format_exc())

    try:
        cl_dns_support = connection.describe_vpc_classic_link_dns_support(VpcIds=vpc_list)
    except botocore.exceptions.ClientError as e:
        if e.response["Error"]["Message"] == "The functionality you requested is not available in this region.":
            cl_dns_support = {'Vpcs': [{'VpcId': vpc_id, 'ClassicLinkDnsSupported': False} for vpc_id in vpc_list]}
        else:
            module.fail_json(msg="Unable to describe if ClassicLinkDns is supported: {0}".format(to_native(e)),
                             exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
    except botocore.exceptions.BotoCoreError as e:
        module.fail_json(msg="Unable to describe if ClassicLinkDns is supported: {0}".format(to_native(e)),
                         exception=traceback.format_exc())

    # Loop through the results and add the other VPC attributes we gathered
    for vpc in response['Vpcs']:
        error_message = "Unable to describe VPC attribute {0}: {1}"
        # We have to make two separate calls per VPC to get these attributes.
        try:
            dns_support = describe_vpc_attr_with_backoff(connection, vpc['VpcId'], 'enableDnsSupport')
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg=error_message.format('enableDnsSupport', to_native(e)),
                             exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
        except botocore.exceptions.BotoCoreError as e:
            module.fail_json(msg=error_message.format('enableDnsSupport', to_native(e)),
                             exception=traceback.format_exc())
        try:
            dns_hostnames = describe_vpc_attr_with_backoff(connection, vpc['VpcId'], 'enableDnsHostnames')
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg=error_message.format('enableDnsHostnames', to_native(e)),
                             exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
        except botocore.exceptions.BotoCoreError as e:
            module.fail_json(msg=error_message.format('enableDnsHostnames', to_native(e)),
                             exception=traceback.format_exc())

        # loop through the ClassicLink Enabled results and add the value for the correct VPC
        for item in cl_enabled['Vpcs']:
            if vpc['VpcId'] == item['VpcId']:
                vpc['ClassicLinkEnabled'] = item['ClassicLinkEnabled']

        # loop through the ClassicLink DNS support results and add the value for the correct VPC
        for item in cl_dns_support['Vpcs']:
            if vpc['VpcId'] == item['VpcId']:
                vpc['ClassicLinkDnsSupported'] = item['ClassicLinkDnsSupported']

        # add the two DNS attributes
        vpc['EnableDnsSupport'] = dns_support['EnableDnsSupport'].get('Value')
        vpc['EnableDnsHostnames'] = dns_hostnames['EnableDnsHostnames'].get('Value')
        # for backwards compatibility
        vpc['id'] = vpc['VpcId']
        vpc_info.append(camel_dict_to_snake_dict(vpc))
        # convert tag list to ansible dict
        vpc_info[-1]['tags'] = boto3_tag_list_to_ansible_dict(vpc.get('Tags', []))

    module.exit_json(vpcs=vpc_info)
def describe_tags_with_backoff(connection, resource_id):
    filters = ansible_dict_to_boto3_filter_list({'resource-id': resource_id})
    paginator = connection.get_paginator('describe_tags')
    tags = paginator.paginate(Filters=filters).build_full_result()['Tags']
    return boto3_tag_list_to_ansible_dict(tags)