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_nat_gateways(client, module, nat_gateway_id=None): params = dict() nat_gateways = list() 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)) for gateway in result['NatGateways']: # Turn the boto3 result into ansible_friendly_snaked_names converted_gateway = camel_dict_to_snake_dict(gateway) if 'tags' in converted_gateway: # Turn the boto3 result into ansible friendly tag dictionary converted_gateway['tags'] = boto3_tag_list_to_ansible_dict( converted_gateway['tags']) nat_gateways.append(converted_gateway) return nat_gateways
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 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_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 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 parse(self, inventory, loader, path, cache=True): super(InventoryModule, self).parse(inventory, loader, path) config_data = self._read_config_data(path) self._set_credentials() # get user specifications regions = self.get_option('regions') filters = self.get_option('filters') strict_permissions = self.get_option('strict_permissions') statuses = self.get_option('statuses') include_clusters = self.get_option('include_clusters') instance_filters = ansible_dict_to_boto3_filter_list(filters) cluster_filters = [] if 'db-cluster-id' in filters and include_clusters: cluster_filters = ansible_dict_to_boto3_filter_list({'db-cluster-id': filters['db-cluster-id']}) 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 formatted_inventory = {} cache_needs_update = False if cache: try: results = self._cache[cache_key] except KeyError: # if cache expires or cache file doesn't exist cache_needs_update = True else: self._populate_from_source(results) if not cache or cache_needs_update: results = self._get_all_hosts(regions, instance_filters, cluster_filters, strict_permissions, statuses, include_clusters) self._populate(results) formatted_inventory = self._format_inventory(results) # 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[cache_key] = formatted_inventory
def ensure_tags(self, tgw_id, tags, purge_tags): """ Ensures tags are applied to the transit gateway. Optionally will remove any existing tags not in the tags argument if purge_tags is set to true :param tgw_id: The AWS id of the transit gateway :param tags: list of tags to apply to the transit gateway. :param purge_tags: when true existing tags not in tags parms are removed :return: true if tags were updated """ tags_changed = False filters = ansible_dict_to_boto3_filter_list({'resource-id': tgw_id}) try: cur_tags = self._connection.describe_tags(Filters=filters) except (ClientError, BotoCoreError) as e: self._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 self._check_mode: AWSRetry.exponential_backoff()( self._connection.create_tags)( Resources=[tgw_id], Tags=ansible_dict_to_boto3_tag_list(to_update)) self._results['changed'] = True tags_changed = True except (ClientError, BotoCoreError) as e: self._module.fail_json_aws( e, msg="Couldn't create tags {0} for resource {1}".format( ansible_dict_to_boto3_tag_list(to_update), tgw_id)) if to_delete: try: if not self._check_mode: tags_list = [] for key in to_delete: tags_list.append({'Key': key}) AWSRetry.exponential_backoff()( self._connection.delete_tags)(Resources=[tgw_id], Tags=tags_list) self._results['changed'] = True tags_changed = True except (ClientError, BotoCoreError) as e: self._module.fail_json_aws( e, msg="Couldn't delete tags {0} for resource {1}".format( ansible_dict_to_boto3_tag_list(to_delete), tgw_id)) return tags_changed
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 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 module._name == 'ec2_group_facts': module.deprecate( "The 'ec2_group_facts' module has been renamed to 'ec2_group_info'", version='2.13') 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 list(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 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_aws( e, msg="Unable to describe network ACLs {0}: {1}".format( nacl_ids, to_native(e))) except BotoCoreError as e: module.fail_json_aws( e, msg="Unable to describe network ACLs {0}: {1}".format( nacl_ids, to_native(e))) # 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 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 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 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 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 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_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_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 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_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 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[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[cache_key] = results
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_region_facts': module.deprecate( "The 'aws_region_facts' module has been renamed to 'aws_region_info'", version='2.13') 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: regions = connection.describe_regions( Filters=ansible_dict_to_boto3_filter_list(sanitized_filters)) except ClientError as e: module.fail_json(msg="Unable to describe regions: {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 regions: {0}".format( to_native(e)), exception=traceback.format_exc()) module.exit_json( regions=[camel_dict_to_snake_dict(r) for r in regions['Regions']])
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 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 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 describe_transit_gateways(self): """ Describe transit gateways. module : AnsibleAWSModule object connection : boto3 client connection object """ # collect parameters filters = ansible_dict_to_boto3_filter_list( self._module.params['filters']) transit_gateway_ids = self._module.params['transit_gateway_ids'] # init empty list for return vars transit_gateway_info = list() # Get the basic transit gateway info try: response = self._connection.describe_transit_gateways( TransitGatewayIds=transit_gateway_ids, Filters=filters) except (BotoCoreError, ClientError) as e: if e.response['Error'][ 'Code'] == 'InvalidTransitGatewayID.NotFound': self._results['transit_gateways'] = [] return else: self._module.fail_json_aws(e) for transit_gateway in response['TransitGateways']: transit_gateway_info.append( camel_dict_to_snake_dict(transit_gateway, ignore_list=['Tags'])) # convert tag list to ansible dict transit_gateway_info[-1]['tags'] = boto3_tag_list_to_ansible_dict( transit_gateway.get('Tags', [])) self._results['transit_gateways'] = transit_gateway_info return
def instance_info(module, conn): instance_name = module.params.get('db_instance_identifier') filters = module.params.get('filters') params = dict() if instance_name: params['DBInstanceIdentifier'] = instance_name if filters: params['Filters'] = ansible_dict_to_boto3_filter_list(filters) paginator = conn.get_paginator('describe_db_instances') try: results = paginator.paginate( **params).build_full_result()['DBInstances'] except is_boto3_error_code('DBInstanceNotFound'): results = [] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, "Couldn't get instance information") for instance in results: try: instance['Tags'] = boto3_tag_list_to_ansible_dict( conn.list_tags_for_resource( ResourceName=instance['DBInstanceArn'], aws_retry=True)['TagList']) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws( e, "Couldn't get tags for instance %s" % instance['DBInstanceIdentifier']) return dict(changed=False, instances=[ camel_dict_to_snake_dict(instance, ignore_list=['Tags']) for instance in results ])