def create_eni(connection, vpc_id, module): instance_id = module.params.get("instance_id") attached = module.params.get("attached") if instance_id == 'None': instance_id = None device_index = module.params.get("device_index") subnet_id = module.params.get('subnet_id') private_ip_address = module.params.get('private_ip_address') description = module.params.get('description') security_groups = get_ec2_security_group_ids_from_names( module.params.get('security_groups'), connection, vpc_id=vpc_id, boto3=False) secondary_private_ip_addresses = module.params.get( "secondary_private_ip_addresses") secondary_private_ip_address_count = module.params.get( "secondary_private_ip_address_count") changed = False try: eni = connection.create_network_interface(subnet_id, private_ip_address, description, security_groups) if attached and instance_id is not None: try: eni.attach(instance_id, device_index) except BotoServerError: eni.delete() raise # Wait to allow creation / attachment to finish wait_for_eni(eni, "attached") eni.update() if secondary_private_ip_address_count is not None: try: connection.assign_private_ip_addresses( network_interface_id=eni.id, secondary_private_ip_address_count= secondary_private_ip_address_count) except BotoServerError: eni.delete() raise if secondary_private_ip_addresses is not None: try: connection.assign_private_ip_addresses( network_interface_id=eni.id, private_ip_addresses=secondary_private_ip_addresses) except BotoServerError: eni.delete() raise changed = True except BotoServerError as e: module.fail_json(msg=e.message) module.exit_json(changed=changed, interface=get_eni_info(eni))
def format_network_configuration(self, network_config): result = dict() if network_config['subnets'] is not None: result['subnets'] = network_config['subnets'] else: self.module.fail_json( msg="Network configuration must include subnets") if network_config['security_groups'] is not None: groups = network_config['security_groups'] if any(not sg.startswith('sg-') for sg in groups): try: vpc_id = self.ec2.describe_subnets( SubnetIds=[result['subnets'][0] ])['Subnets'][0]['VpcId'] groups = get_ec2_security_group_ids_from_names( groups, self.ec2, vpc_id) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: self.module.fail_json_aws( e, msg="Couldn't look up security groups") result['securityGroups'] = groups if network_config['assign_public_ip'] is not None: if self.module.botocore_at_least('1.8.4'): if network_config['assign_public_ip'] is True: result['assignPublicIp'] = "ENABLED" else: result['assignPublicIp'] = "DISABLED" else: self.module.fail_json( msg= 'botocore needs to be version 1.8.4 or higher to use assign_public_ip in network_configuration' ) return dict(awsvpcConfiguration=result)
def ensure_present(client, module): name = module.params.get('name') subnets = module.params['subnets'] groups = module.params['security_groups'] wait = module.params.get('wait') cluster = get_cluster(client, module) try: ec2 = module.client('ec2') vpc_id = ec2.describe_subnets( SubnetIds=[subnets[0]])['Subnets'][0]['VpcId'] groups = get_ec2_security_group_ids_from_names(groups, ec2, vpc_id) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: module.fail_json_aws(e, msg="Couldn't lookup security groups") if cluster: if set(cluster['resourcesVpcConfig']['subnetIds']) != set(subnets): module.fail_json(msg="Cannot modify subnets of existing cluster") if set(cluster['resourcesVpcConfig']['securityGroupIds']) != set( groups): module.fail_json( msg="Cannot modify security groups of existing cluster") if module.params.get('version') and module.params.get( 'version') != cluster['version']: module.fail_json(msg="Cannot modify version of existing cluster") if wait: wait_until(client, module, 'cluster_active') # Ensure that fields that are only available for active clusters are # included in the returned value cluster = get_cluster(client, module) module.exit_json(changed=False, **camel_dict_to_snake_dict(cluster)) if module.check_mode: module.exit_json(changed=True) try: params = dict(name=name, roleArn=module.params['role_arn'], resourcesVpcConfig=dict(subnetIds=subnets, securityGroupIds=groups), clientRequestToken='ansible-create-%s' % name) if module.params['version']: params['version'] = module.params['version'] cluster = client.create_cluster(**params)['cluster'] except botocore.exceptions.EndpointConnectionError as e: module.fail_json(msg="Region %s is not supported by EKS" % client.meta.region_name) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: module.fail_json_aws(e, msg="Couldn't create cluster %s" % name) if wait: wait_until(client, module, 'cluster_active') # Ensure that fields that are only available for active clusters are # included in the returned value cluster = get_cluster(client, module) module.exit_json(changed=True, **camel_dict_to_snake_dict(cluster))
def format_network_configuration(self, network_config): result = dict() if 'subnets' in network_config: result['subnets'] = network_config['subnets'] else: self.module.fail_json( msg="Network configuration must include subnets") if 'security_groups' in network_config: groups = network_config['security_groups'] if any(not sg.startswith('sg-') for sg in groups): try: vpc_id = self.ec2.describe_subnets( SubnetIds=[result['subnets'][0] ])['Subnets'][0]['VpcId'] groups = get_ec2_security_group_ids_from_names( groups, self.ec2, vpc_id) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: self.module.fail_json_aws( e, msg="Couldn't look up security groups") result['securityGroups'] = groups return dict(awsvpcConfiguration=result)
def modify_eni(connection, vpc_id, module, eni): instance_id = module.params.get("instance_id") attached = module.params.get("attached") do_detach = module.params.get('state') == 'detached' device_index = module.params.get("device_index") description = module.params.get('description') security_groups = module.params.get('security_groups') force_detach = module.params.get("force_detach") source_dest_check = module.params.get("source_dest_check") delete_on_termination = module.params.get("delete_on_termination") secondary_private_ip_addresses = module.params.get( "secondary_private_ip_addresses") purge_secondary_private_ip_addresses = module.params.get( "purge_secondary_private_ip_addresses") secondary_private_ip_address_count = module.params.get( "secondary_private_ip_address_count") allow_reassignment = module.params.get("allow_reassignment") changed = False try: if description is not None: if eni.description != description: connection.modify_network_interface_attribute( eni.id, "description", description) changed = True if len(security_groups) > 0: groups = get_ec2_security_group_ids_from_names(security_groups, connection, vpc_id=vpc_id, boto3=False) if sorted(get_sec_group_list(eni.groups)) != sorted(groups): connection.modify_network_interface_attribute( eni.id, "groupSet", groups) changed = True if source_dest_check is not None: if eni.source_dest_check != source_dest_check: connection.modify_network_interface_attribute( eni.id, "sourceDestCheck", source_dest_check) changed = True if delete_on_termination is not None and eni.attachment is not None: if eni.attachment.delete_on_termination is not delete_on_termination: connection.modify_network_interface_attribute( eni.id, "deleteOnTermination", delete_on_termination, eni.attachment.id) changed = True current_secondary_addresses = [ i.private_ip_address for i in eni.private_ip_addresses if not i.primary ] if secondary_private_ip_addresses is not None: secondary_addresses_to_remove = list( set(current_secondary_addresses) - set(secondary_private_ip_addresses)) if secondary_addresses_to_remove and purge_secondary_private_ip_addresses: connection.unassign_private_ip_addresses( network_interface_id=eni.id, private_ip_addresses=list( set(current_secondary_addresses) - set(secondary_private_ip_addresses)), dry_run=False) changed = True secondary_addresses_to_add = list( set(secondary_private_ip_addresses) - set(current_secondary_addresses)) if secondary_addresses_to_add: connection.assign_private_ip_addresses( network_interface_id=eni.id, private_ip_addresses=secondary_addresses_to_add, secondary_private_ip_address_count=None, allow_reassignment=allow_reassignment, dry_run=False) changed = True if secondary_private_ip_address_count is not None: current_secondary_address_count = len(current_secondary_addresses) if secondary_private_ip_address_count > current_secondary_address_count: connection.assign_private_ip_addresses( network_interface_id=eni.id, private_ip_addresses=None, secondary_private_ip_address_count=( secondary_private_ip_address_count - current_secondary_address_count), allow_reassignment=allow_reassignment, dry_run=False) changed = True elif secondary_private_ip_address_count < current_secondary_address_count: # How many of these addresses do we want to remove secondary_addresses_to_remove_count = current_secondary_address_count - secondary_private_ip_address_count connection.unassign_private_ip_addresses( network_interface_id=eni.id, private_ip_addresses= current_secondary_addresses[: secondary_addresses_to_remove_count], dry_run=False) if attached is True: if eni.attachment and eni.attachment.instance_id != instance_id: detach_eni(eni, module) eni.attach(instance_id, device_index) wait_for_eni(eni, "attached") changed = True if eni.attachment is None: eni.attach(instance_id, device_index) wait_for_eni(eni, "attached") changed = True elif attached is False: detach_eni(eni, module) except BotoServerError as e: module.fail_json(msg=e.message) eni.update() module.exit_json(changed=changed, interface=get_eni_info(eni))
def create_launch_config(connection, module): name = module.params.get('name') vpc_id = module.params.get('vpc_id') try: region, ec2_url, aws_connect_kwargs = get_aws_connection_info( module, boto3=True) ec2_connection = boto3_conn(module, 'client', 'ec2', region, ec2_url, **aws_connect_kwargs) security_groups = get_ec2_security_group_ids_from_names( module.params.get('security_groups'), ec2_connection, vpc_id=vpc_id, boto3=True) except botocore.exceptions.ClientError as e: module.fail_json(msg="Failed to get Security Group IDs", exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except ValueError as e: module.fail_json(msg="Failed to get Security Group IDs", exception=traceback.format_exc()) user_data = module.params.get('user_data') user_data_path = module.params.get('user_data_path') volumes = module.params['volumes'] instance_monitoring = module.params.get('instance_monitoring') assign_public_ip = module.params.get('assign_public_ip') instance_profile_name = module.params.get('instance_profile_name') ebs_optimized = module.params.get('ebs_optimized') classic_link_vpc_id = module.params.get('classic_link_vpc_id') classic_link_vpc_security_groups = module.params.get( 'classic_link_vpc_security_groups') block_device_mapping = [] convert_list = [ 'image_id', 'instance_type', 'instance_type', 'instance_id', 'placement_tenancy', 'key_name', 'kernel_id', 'ramdisk_id', 'spot_price' ] launch_config = (snake_dict_to_camel_dict( dict((k.capitalize(), str(v)) for k, v in module.params.items() if v is not None and k in convert_list))) if user_data_path: try: with open(user_data_path, 'r') as user_data_file: user_data = user_data_file.read() except IOError as e: module.fail_json(msg="Failed to open file for reading", exception=traceback.format_exc()) if volumes: for volume in volumes: if 'device_name' not in volume: module.fail_json(msg='Device name must be set for volume') # Minimum volume size is 1GiB. We'll use volume size explicitly set to 0 to be a signal not to create this volume if 'volume_size' not in volume or int(volume['volume_size']) > 0: block_device_mapping.append( create_block_device_meta(module, volume)) try: launch_configs = connection.describe_launch_configurations( LaunchConfigurationNames=[name]).get('LaunchConfigurations') except botocore.exceptions.ClientError as e: module.fail_json(msg="Failed to describe launch configuration by name", exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = False result = {} launch_config['LaunchConfigurationName'] = name if security_groups is not None: launch_config['SecurityGroups'] = security_groups if classic_link_vpc_id is not None: launch_config['ClassicLinkVPCId'] = classic_link_vpc_id if instance_monitoring is not None: launch_config['InstanceMonitoring'] = {'Enabled': instance_monitoring} if classic_link_vpc_security_groups is not None: launch_config[ 'ClassicLinkVPCSecurityGroups'] = classic_link_vpc_security_groups if block_device_mapping: launch_config['BlockDeviceMappings'] = block_device_mapping if instance_profile_name is not None: launch_config['IamInstanceProfile'] = instance_profile_name if assign_public_ip is not None: launch_config['AssociatePublicIpAddress'] = assign_public_ip if user_data is not None: launch_config['UserData'] = user_data if ebs_optimized is not None: launch_config['EbsOptimized'] = ebs_optimized if len(launch_configs) == 0: try: connection.create_launch_configuration(**launch_config) launch_configs = connection.describe_launch_configurations( LaunchConfigurationNames=[name]).get('LaunchConfigurations') changed = True if launch_configs: launch_config = launch_configs[0] except botocore.exceptions.ClientError as e: module.fail_json(msg="Failed to create launch configuration", exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) result = (dict((k, v) for k, v in launch_config.items() if k not in [ 'Connection', 'CreatedTime', 'InstanceMonitoring', 'BlockDeviceMappings' ])) result['CreatedTime'] = to_text(launch_config.get('CreatedTime')) try: result['InstanceMonitoring'] = module.boolean( launch_config.get('InstanceMonitoring').get('Enabled')) except AttributeError: result['InstanceMonitoring'] = False result['BlockDeviceMappings'] = [] for block_device_mapping in launch_config.get('BlockDeviceMappings', []): result['BlockDeviceMappings'].append( dict(device_name=block_device_mapping.get('DeviceName'), virtual_name=block_device_mapping.get('VirtualName'))) if block_device_mapping.get('Ebs') is not None: result['BlockDeviceMappings'][-1]['ebs'] = dict( snapshot_id=block_device_mapping.get('Ebs').get('SnapshotId'), volume_size=block_device_mapping.get('Ebs').get('VolumeSize')) if user_data_path: result[ 'UserData'] = "hidden" # Otherwise, we dump binary to the user's terminal return_object = { 'Name': result.get('LaunchConfigurationName'), 'CreatedTime': result.get('CreatedTime'), 'ImageId': result.get('ImageId'), 'Arn': result.get('LaunchConfigurationARN'), 'SecurityGroups': result.get('SecurityGroups'), 'InstanceType': result.get('InstanceType'), 'Result': result } module.exit_json(changed=changed, **camel_dict_to_snake_dict(return_object))
def create_or_update_glue_connection(connection, connection_ec2, module, glue_connection): """ Create or update an AWS Glue connection :param connection: AWS boto3 glue connection :param module: Ansible module :param glue_connection: a dict of AWS Glue connection parameters or None :return: """ changed = False params = dict() params['ConnectionInput'] = dict() params['ConnectionInput']['Name'] = module.params.get("name") params['ConnectionInput']['ConnectionType'] = module.params.get( "connection_type") params['ConnectionInput']['ConnectionProperties'] = module.params.get( "connection_properties") if module.params.get("catalog_id") is not None: params['CatalogId'] = module.params.get("catalog_id") if module.params.get("description") is not None: params['ConnectionInput']['Description'] = module.params.get( "description") if module.params.get("match_criteria") is not None: params['ConnectionInput']['MatchCriteria'] = module.params.get( "match_criteria") if module.params.get("security_groups") is not None or module.params.get( "subnet_id") is not None: params['ConnectionInput']['PhysicalConnectionRequirements'] = dict() if module.params.get("security_groups") is not None: # Get security group IDs from names security_group_ids = get_ec2_security_group_ids_from_names( module.params.get('security_groups'), connection_ec2, boto3=True) params['ConnectionInput']['PhysicalConnectionRequirements'][ 'SecurityGroupIdList'] = security_group_ids if module.params.get("subnet_id") is not None: params['ConnectionInput']['PhysicalConnectionRequirements'][ 'SubnetId'] = module.params.get("subnet_id") # If glue_connection is not None then check if it needs to be modified, else create it if glue_connection: if _compare_glue_connection_params(params, glue_connection): try: # We need to slightly modify the params for an update update_params = copy.deepcopy(params) update_params['Name'] = update_params['ConnectionInput'][ 'Name'] connection.update_connection(**update_params) changed = True except (BotoCoreError, ClientError) as e: module.fail_json_aws(e) else: try: connection.create_connection(**params) changed = True except (BotoCoreError, ClientError) as e: module.fail_json_aws(e) # If changed, get the Glue connection again if changed: glue_connection = None for i in range(10): glue_connection = _get_glue_connection(connection, module) if glue_connection is not None: break time.sleep(10) module.exit_json(changed=changed, **camel_dict_to_snake_dict(glue_connection))