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
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_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)
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
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']]
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)
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 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']
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']
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))
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']]
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
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)
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)
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 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']]
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 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
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)
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']]
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)
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])
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)
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 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)
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
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)
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)
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
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)
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)
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)
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)
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
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)
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
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)