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 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 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 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 = find_eni(connection, module) if eni is None: eni = connection.create_network_interface(subnet_id, private_ip_address, description, security_groups) if attached == True 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 '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 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 create_or_update_elb(connection, connection_ec2, module): """Create ELB or modify main attributes. json_exit here""" changed = False new_load_balancer = False params = dict() params['Name'] = module.params.get("name") params['Subnets'] = module.params.get("subnets") try: params['SecurityGroups'] = get_ec2_security_group_ids_from_names( module.params.get('security_groups'), connection_ec2, boto3=True) except ValueError as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except NoCredentialsError as e: module.fail_json(msg="AWS authentication problem. " + e.message, exception=traceback.format_exc()) params['Scheme'] = module.params.get("scheme") if module.params.get("tags"): params['Tags'] = ansible_dict_to_boto3_tag_list( module.params.get("tags")) purge_tags = module.params.get("purge_tags") access_logs_enabled = module.params.get("access_logs_enabled") access_logs_s3_bucket = module.params.get("access_logs_s3_bucket") access_logs_s3_prefix = module.params.get("access_logs_s3_prefix") deletion_protection = module.params.get("deletion_protection") idle_timeout = module.params.get("idle_timeout") # Does the ELB currently exist? elb = get_elb(connection, module) if elb: # ELB exists so check subnets, security groups and tags match what has been passed # Subnets if set(_get_subnet_ids_from_subnet_list( elb['AvailabilityZones'])) != set(params['Subnets']): try: connection.set_subnets(LoadBalancerArn=elb['LoadBalancerArn'], Subnets=params['Subnets']) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Security Groups if set(elb['SecurityGroups']) != set(params['SecurityGroups']): try: connection.set_security_groups( LoadBalancerArn=elb['LoadBalancerArn'], SecurityGroups=params['SecurityGroups']) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Tags - only need to play with tags if tags parameter has been set to something if module.params.get("tags"): try: elb_tags = connection.describe_tags( ResourceArns=[elb['LoadBalancerArn'] ])['TagDescriptions'][0]['Tags'] except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Delete necessary tags tags_need_modify, tags_to_delete = compare_aws_tags( boto3_tag_list_to_ansible_dict(elb_tags), boto3_tag_list_to_ansible_dict(params['Tags']), purge_tags) if tags_to_delete: try: connection.remove_tags( ResourceArns=[elb['LoadBalancerArn']], TagKeys=tags_to_delete) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Add/update tags if tags_need_modify: try: connection.add_tags(ResourceArns=[elb['LoadBalancerArn']], Tags=params['Tags']) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True else: try: elb = connection.create_load_balancer(**params)['LoadBalancers'][0] changed = True new_load_balancer = True except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) if module.params.get("wait"): status_achieved, new_elb = wait_for_status(connection, module, elb['LoadBalancerArn'], 'active') # Now set ELB attributes. Use try statement here so we can remove the ELB if this stage fails update_attributes = [] # Get current attributes current_elb_attributes = get_elb_attributes(connection, module, elb['LoadBalancerArn']) if access_logs_enabled and current_elb_attributes[ 'access_logs_s3_enabled'] != "true": update_attributes.append({ 'Key': 'access_logs.s3.enabled', 'Value': "true" }) if not access_logs_enabled and current_elb_attributes[ 'access_logs_s3_enabled'] != "false": update_attributes.append({ 'Key': 'access_logs.s3.enabled', 'Value': 'false' }) if access_logs_s3_bucket is not None and access_logs_s3_bucket != current_elb_attributes[ 'access_logs_s3_bucket']: update_attributes.append({ 'Key': 'access_logs.s3.bucket', 'Value': access_logs_s3_bucket }) if access_logs_s3_prefix is not None and access_logs_s3_prefix != current_elb_attributes[ 'access_logs_s3_prefix']: update_attributes.append({ 'Key': 'access_logs.s3.prefix', 'Value': access_logs_s3_prefix }) if deletion_protection and current_elb_attributes[ 'deletion_protection_enabled'] != "true": update_attributes.append({ 'Key': 'deletion_protection.enabled', 'Value': "true" }) if not deletion_protection and current_elb_attributes[ 'deletion_protection_enabled'] != "false": update_attributes.append({ 'Key': 'deletion_protection.enabled', 'Value': "false" }) if idle_timeout is not None and str( idle_timeout ) != current_elb_attributes['idle_timeout_timeout_seconds']: update_attributes.append({ 'Key': 'idle_timeout.timeout_seconds', 'Value': str(idle_timeout) }) if update_attributes: try: connection.modify_load_balancer_attributes( LoadBalancerArn=elb['LoadBalancerArn'], Attributes=update_attributes) changed = True except ClientError as e: # Something went wrong setting attributes. If this ELB was created during this task, delete it to leave a consistent state if new_load_balancer: connection.delete_load_balancer( LoadBalancerArn=elb['LoadBalancerArn']) module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Now, if required, set ELB listeners. Use try statement here so we can remove the ELB if this stage fails try: listener_changed = create_or_update_elb_listeners( connection, module, elb) if listener_changed: changed = True except ClientError as e: # Something went wrong setting listeners. If this ELB was created during this task, delete it to leave a consistent state if new_load_balancer: connection.delete_load_balancer( LoadBalancerArn=elb['LoadBalancerArn']) module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Get the ELB again elb = get_elb(connection, module) # Get the ELB listeners again elb['listeners'] = get_elb_listeners(connection, module, elb['LoadBalancerArn']) # For each listener, get listener rules for listener in elb['listeners']: listener['rules'] = get_listener_rules(connection, module, listener['ListenerArn']) # Get the ELB attributes again elb.update(get_elb_attributes(connection, module, elb['LoadBalancerArn'])) # Convert to snake_case snaked_elb = camel_dict_to_snake_dict(elb) # Get the tags of the ELB elb_tags = connection.describe_tags( ResourceArns=[elb['LoadBalancerArn']])['TagDescriptions'][0]['Tags'] snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(elb_tags) module.exit_json(changed=changed, **snaked_elb)
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 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 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") secondary_private_ip_address_count = module.params.get("secondary_private_ip_address_count") 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: 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) connection.assign_private_ip_addresses(network_interface_id=eni.id, private_ip_addresses=secondary_private_ip_addresses, secondary_private_ip_address_count=None, allow_reassignment=False, dry_run=False) 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=False, 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_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))
def create_or_update_elb(connection, connection_ec2, module): """Create ELB or modify main attributes. json_exit here""" changed = False new_load_balancer = False params = dict() params['Name'] = module.params.get("name") params['Subnets'] = module.params.get("subnets") try: params['SecurityGroups'] = get_ec2_security_group_ids_from_names( module.params.get('security_groups'), connection_ec2, boto3=True) except ValueError as e: module.fail_json(msg=str(e)) params['Scheme'] = module.params.get("scheme") if module.params.get("tags"): params['Tags'] = ansible_dict_to_boto3_tag_list( module.params.get("tags")) purge_tags = module.params.get("purge_tags") # Does the ELB currently exist? elb = get_elb(connection, module) if elb: # ELB exists so check subnets, security groups and tags match what has been passed # Subnets if set(_get_subnet_ids_from_subnet_list( elb['AvailabilityZones'])) != set(params['Subnets']): try: connection.set_subnets(LoadBalancerArn=elb['LoadBalancerArn'], Subnets=params['Subnets']) except (ClientError, NoCredentialsError) as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Security Groups if set(elb['SecurityGroups']) != set(params['SecurityGroups']): try: connection.set_security_groups( LoadBalancerArn=elb['LoadBalancerArn'], SecurityGroups=params['SecurityGroups']) except (ClientError, NoCredentialsError) as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Tags - only need to play with tags if tags parameter has been set to something if module.params.get("tags"): try: elb_tags = connection.describe_tags( ResourceArns=[elb['LoadBalancerArn'] ])['TagDescriptions'][0]['Tags'] except (ClientError, NoCredentialsError) as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Delete necessary tags tags_to_delete, tags_need_modify = _compare_tags( elb_tags, params['Tags'], purge_tags) if tags_to_delete: try: connection.remove_tags( ResourceArns=[elb['LoadBalancerArn']], TagKeys=tags_to_delete) except (ClientError, NoCredentialsError) as e: module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response)) changed = True # Add/update tags if tags_need_modify: try: connection.add_tags(ResourceArns=[elb['LoadBalancerArn']], Tags=params['Tags']) except (ClientError, NoCredentialsError) as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True else: try: elb = connection.create_load_balancer(**params)['LoadBalancers'][0] changed = True new_load_balancer = True except (ClientError, NoCredentialsError) as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) if module.params.get("wait"): status_achieved, new_elb = wait_for_status(connection, module, elb['LoadBalancerArn'], 'active') # Now set ELB attributes. Use try statement here so we can remove the ELB if this stage fails try: attribute_changed = update_elb_attributes(connection, module, elb) if attribute_changed: changed = True except (ClientError, NoCredentialsError) as e: # Something went wrong setting attributes. If this ELB was created during this task, delete it to leave a consistent state if new_load_balancer: connection.delete_load_balancer( LoadBalancerArn=elb['LoadBalancerArn']) module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Now, if required, set ELB listeners. Use try statement here so we can remove the ELB if this stage fails try: listener_changed = create_or_update_elb_listeners( connection, module, elb) if listener_changed: changed = True except (ClientError, NoCredentialsError) as e: # Something went wrong setting listeners. If this ELB was created during this task, delete it to leave a consistent state if new_load_balancer: connection.delete_load_balancer( LoadBalancerArn=elb['LoadBalancerArn']) module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Get the ELB again elb = get_elb(connection, module) # Get the tags of the ELB elb_tags = connection.describe_tags( ResourceArns=[elb['LoadBalancerArn']])['TagDescriptions'][0]['Tags'] elb['Tags'] = boto3_tag_list_to_ansible_dict(elb_tags) module.exit_json(changed=changed, load_balancer=camel_dict_to_snake_dict(elb))
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 1GB. 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.update(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: 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_launch_config(connection, module): name = module.params.get('name') image_id = module.params.get('image_id') key_name = module.params.get('key_name') try: security_groups = get_ec2_security_group_ids_from_names( module.params.get('security_groups'), ec2_connect(module), vpc_id=None, boto3=False) except ValueError as e: module.fail_json(msg=str(e)) user_data = module.params.get('user_data') user_data_path = module.params.get('user_data_path') volumes = module.params['volumes'] instance_type = module.params.get('instance_type') spot_price = module.params.get('spot_price') instance_monitoring = module.params.get('instance_monitoring') assign_public_ip = module.params.get('assign_public_ip') kernel_id = module.params.get('kernel_id') ramdisk_id = module.params.get('ramdisk_id') 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') bdm = BlockDeviceMapping() 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=str(e), 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 1GB. 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: bdm[volume['device_name']] = create_block_device( module, volume) lc = LaunchConfiguration( name=name, image_id=image_id, key_name=key_name, security_groups=security_groups, user_data=user_data, block_device_mappings=[bdm], instance_type=instance_type, kernel_id=kernel_id, spot_price=spot_price, instance_monitoring=instance_monitoring, associate_public_ip_address=assign_public_ip, ramdisk_id=ramdisk_id, instance_profile_name=instance_profile_name, ebs_optimized=ebs_optimized, classic_link_vpc_security_groups=classic_link_vpc_security_groups, classic_link_vpc_id=classic_link_vpc_id, ) launch_configs = connection.get_all_launch_configurations(names=[name]) changed = False if not launch_configs: try: connection.create_launch_configuration(lc) launch_configs = connection.get_all_launch_configurations( names=[name]) changed = True except BotoServerError as e: module.fail_json(msg=str(e)) result = dict( ((a[0], a[1]) for a in vars(launch_configs[0]).items() if a[0] not in ('connection', 'created_time', 'instance_monitoring', 'block_device_mappings'))) result['created_time'] = str(launch_configs[0].created_time) # Looking at boto's launchconfig.py, it looks like this could be a boolean # value or an object with an enabled attribute. The enabled attribute # could be a boolean or a string representation of a boolean. Since # I can't test all permutations myself to see if my reading of the code is # correct, have to code this *very* defensively if launch_configs[0].instance_monitoring is True: result['instance_monitoring'] = True else: try: result['instance_monitoring'] = module.boolean( launch_configs[0].instance_monitoring.enabled) except AttributeError: result['instance_monitoring'] = False if launch_configs[0].block_device_mappings is not None: result['block_device_mappings'] = [] for bdm in launch_configs[0].block_device_mappings: result['block_device_mappings'].append( dict(device_name=bdm.device_name, virtual_name=bdm.virtual_name)) if bdm.ebs is not None: result['block_device_mappings'][-1]['ebs'] = dict( snapshot_id=bdm.ebs.snapshot_id, volume_size=bdm.ebs.volume_size) if user_data_path: result[ 'user_data'] = "hidden" # Otherwise, we dump binary to the user's terminal module.exit_json(changed=changed, name=result['name'], created_time=result['created_time'], image_id=result['image_id'], arn=result['launch_configuration_arn'], security_groups=result['security_groups'], instance_type=result['instance_type'], result=result)
def create_or_update_elb(connection, connection_ec2, module): """Create ELB or modify main attributes. json_exit here""" changed = False new_load_balancer = False params = dict() params['Name'] = module.params.get("name") params['Subnets'] = module.params.get("subnets") try: params['SecurityGroups'] = get_ec2_security_group_ids_from_names(module.params.get('security_groups'), connection_ec2, boto3=True) except ValueError as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except NoCredentialsError as e: module.fail_json(msg="AWS authentication problem. " + e.message, exception=traceback.format_exc()) params['Scheme'] = module.params.get("scheme") if module.params.get("tags"): params['Tags'] = ansible_dict_to_boto3_tag_list(module.params.get("tags")) purge_tags = module.params.get("purge_tags") access_logs_enabled = module.params.get("access_logs_enabled") access_logs_s3_bucket = module.params.get("access_logs_s3_bucket") access_logs_s3_prefix = module.params.get("access_logs_s3_prefix") deletion_protection = module.params.get("deletion_protection") idle_timeout = module.params.get("idle_timeout") # Does the ELB currently exist? elb = get_elb(connection, module) if elb: # ELB exists so check subnets, security groups and tags match what has been passed # Subnets if set(_get_subnet_ids_from_subnet_list(elb['AvailabilityZones'])) != set(params['Subnets']): try: connection.set_subnets(LoadBalancerArn=elb['LoadBalancerArn'], Subnets=params['Subnets']) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Security Groups if set(elb['SecurityGroups']) != set(params['SecurityGroups']): try: connection.set_security_groups(LoadBalancerArn=elb['LoadBalancerArn'], SecurityGroups=params['SecurityGroups']) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Tags - only need to play with tags if tags parameter has been set to something if module.params.get("tags"): try: elb_tags = connection.describe_tags(ResourceArns=[elb['LoadBalancerArn']])['TagDescriptions'][0]['Tags'] except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Delete necessary tags tags_need_modify, tags_to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(elb_tags), boto3_tag_list_to_ansible_dict(params['Tags']), purge_tags) if tags_to_delete: try: connection.remove_tags(ResourceArns=[elb['LoadBalancerArn']], TagKeys=tags_to_delete) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True # Add/update tags if tags_need_modify: try: connection.add_tags(ResourceArns=[elb['LoadBalancerArn']], Tags=params['Tags']) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) changed = True else: try: elb = connection.create_load_balancer(**params)['LoadBalancers'][0] changed = True new_load_balancer = True except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) if module.params.get("wait"): status_achieved, new_elb = wait_for_status(connection, module, elb['LoadBalancerArn'], 'active') # Now set ELB attributes. Use try statement here so we can remove the ELB if this stage fails update_attributes = [] # Get current attributes current_elb_attributes = get_elb_attributes(connection, module, elb['LoadBalancerArn']) if access_logs_enabled and current_elb_attributes['access_logs_s3_enabled'] != "true": update_attributes.append({'Key': 'access_logs.s3.enabled', 'Value': "true"}) if not access_logs_enabled and current_elb_attributes['access_logs_s3_enabled'] != "false": update_attributes.append({'Key': 'access_logs.s3.enabled', 'Value': 'false'}) if access_logs_s3_bucket is not None and access_logs_s3_bucket != current_elb_attributes['access_logs_s3_bucket']: update_attributes.append({'Key': 'access_logs.s3.bucket', 'Value': access_logs_s3_bucket}) if access_logs_s3_prefix is not None and access_logs_s3_prefix != current_elb_attributes['access_logs_s3_prefix']: update_attributes.append({'Key': 'access_logs.s3.prefix', 'Value': access_logs_s3_prefix}) if deletion_protection and current_elb_attributes['deletion_protection_enabled'] != "true": update_attributes.append({'Key': 'deletion_protection.enabled', 'Value': "true"}) if not deletion_protection and current_elb_attributes['deletion_protection_enabled'] != "false": update_attributes.append({'Key': 'deletion_protection.enabled', 'Value': "false"}) if idle_timeout is not None and str(idle_timeout) != current_elb_attributes['idle_timeout_timeout_seconds']: update_attributes.append({'Key': 'idle_timeout.timeout_seconds', 'Value': str(idle_timeout)}) if update_attributes: try: connection.modify_load_balancer_attributes(LoadBalancerArn=elb['LoadBalancerArn'], Attributes=update_attributes) changed = True except ClientError as e: # Something went wrong setting attributes. If this ELB was created during this task, delete it to leave a consistent state if new_load_balancer: connection.delete_load_balancer(LoadBalancerArn=elb['LoadBalancerArn']) module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Now, if required, set ELB listeners. Use try statement here so we can remove the ELB if this stage fails try: listener_changed = create_or_update_elb_listeners(connection, module, elb) if listener_changed: changed = True except ClientError as e: # Something went wrong setting listeners. If this ELB was created during this task, delete it to leave a consistent state if new_load_balancer: connection.delete_load_balancer(LoadBalancerArn=elb['LoadBalancerArn']) module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Get the ELB again elb = get_elb(connection, module) # Get the ELB listeners again elb['listeners'] = get_elb_listeners(connection, module, elb['LoadBalancerArn']) # For each listener, get listener rules for listener in elb['listeners']: listener['rules'] = get_listener_rules(connection, module, listener['ListenerArn']) # Get the ELB attributes again elb.update(get_elb_attributes(connection, module, elb['LoadBalancerArn'])) # Convert to snake_case snaked_elb = camel_dict_to_snake_dict(elb) # Get the tags of the ELB elb_tags = connection.describe_tags(ResourceArns=[elb['LoadBalancerArn']])['TagDescriptions'][0]['Tags'] snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(elb_tags) module.exit_json(changed=changed, **snaked_elb)