def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict(filters=dict(default=None, type='dict'))) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if module._name == 'ec2_vpc_route_table_facts': module.deprecate( "The 'ec2_vpc_route_table_facts' module has been renamed to 'ec2_vpc_route_table_info'", version='2.13') if not HAS_BOTO: module.fail_json(msg='boto required for this module') region, ec2_url, aws_connect_params = get_aws_connection_info(module) if region: try: connection = connect_to_aws(boto.vpc, region, **aws_connect_params) except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: module.fail_json(msg=str(e)) else: module.fail_json(msg="region must be specified") list_ec2_vpc_route_tables(connection, module)
def _get_auto_scaling_group_lbs(self): """Returns a list of ELBs associated with self.instance_id indirectly through its auto scaling group membership""" try: asg = connect_to_aws(boto.ec2.autoscale, self.region, **self.aws_connect_params) except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: self.module.fail_json(msg=str(e)) asg_instances = asg.get_all_autoscaling_instances([self.instance_id]) if len(asg_instances) > 1: self.module.fail_json( msg="Illegal state, expected one auto scaling group instance.") if not asg_instances: asg_elbs = [] else: asg_name = asg_instances[0].group_name asgs = asg.get_all_groups([asg_name]) if len(asg_instances) != 1: self.module.fail_json( msg="Illegal state, expected one auto scaling group.") asg_elbs = asgs[0].load_balancers return asg_elbs
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict( name=dict(required=True, type='str'), adjustment_type=dict(type='str', choices=['ChangeInCapacity', 'ExactCapacity', 'PercentChangeInCapacity']), asg_name=dict(required=True, type='str'), scaling_adjustment=dict(type='int'), min_adjustment_step=dict(type='int'), cooldown=dict(type='int'), state=dict(default='present', choices=['present', 'absent']), ) ) module = AnsibleModule(argument_spec=argument_spec) if not HAS_BOTO: module.fail_json(msg='boto required for this module') region, ec2_url, aws_connect_params = get_aws_connection_info(module) state = module.params.get('state') try: connection = connect_to_aws(boto.ec2.autoscale, region, **aws_connect_params) except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: module.fail_json(msg=str(e)) if state == 'present': create_scaling_policy(connection, module) elif state == 'absent': delete_scaling_policy(connection, module)
def _get_instance(self): """Returns a boto.ec2.InstanceObject for self.instance_id""" try: ec2 = connect_to_aws(boto.ec2, self.region, **self.aws_connect_params) except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: self.module.fail_json(msg=str(e)) return ec2.get_only_instances(instance_ids=[self.instance_id])[0]
def _get_instance_lbs(self, ec2_elbs=None): """Returns a list of ELBs attached to self.instance_id ec2_elbs: an optional list of elb names that will be used for elb lookup instead of returning what elbs are attached to self.instance_id""" if not ec2_elbs: ec2_elbs = self._get_auto_scaling_group_lbs() try: elb = connect_to_aws(boto.ec2.elb, self.region, **self.aws_connect_params) except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: self.module.fail_json(msg=str(e)) elbs = [] marker = None while True: try: newelbs = elb.get_all_load_balancers(marker=marker) marker = newelbs.next_marker elbs.extend(newelbs) if not marker: break except TypeError: # Older version of boto do not allow for params elbs = elb.get_all_load_balancers() break if ec2_elbs: lbs = sorted(lb for lb in elbs if lb.name in ec2_elbs) else: lbs = [] for lb in elbs: for info in lb.instances: if self.instance_id == info.id: lbs.append(lb) return lbs
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict( state=dict(default='present', choices=['present', 'absent']), name=dict(required=True, type='str'), default_visibility_timeout=dict(type='int'), message_retention_period=dict(type='int'), maximum_message_size=dict(type='int'), delivery_delay=dict(type='int'), receive_message_wait_time=dict(type='int'), policy=dict(type='dict', required=False), redrive_policy=dict(type='dict', required=False), )) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if not HAS_BOTO: module.fail_json(msg='boto required for this module') region, ec2_url, aws_connect_params = get_aws_connection_info(module) if not region: module.fail_json(msg='region must be specified') try: connection = connect_to_aws(boto.sqs, region, **aws_connect_params) except (NoAuthHandlerFound, AnsibleAWSError) as e: module.fail_json(msg=str(e)) state = module.params.get('state') if state == 'present': create_or_update_sqs_queue(connection, module) elif state == 'absent': delete_sqs_queue(connection, module)
def _get_elb_connection(self): return connect_to_aws(boto.ec2.elb, self.region, **self.aws_connect_params)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(state=dict(required=True, choices=['present', 'absent']), name=dict(required=True), cert=dict(), key=dict(no_log=True), cert_chain=dict(), new_name=dict(), path=dict(default='/'), new_path=dict(), dup_ok=dict(type='bool'))) module = AnsibleModule( argument_spec=argument_spec, mutually_exclusive=[ ['new_path', 'key'], ['new_path', 'cert'], ['new_path', 'cert_chain'], ['new_name', 'key'], ['new_name', 'cert'], ['new_name', 'cert_chain'], ], ) if not HAS_BOTO: module.fail_json(msg="Boto is required for this module") region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module) try: if region: iam = connect_to_aws(boto.iam, region, **aws_connect_kwargs) else: iam = boto.iam.connection.IAMConnection(**aws_connect_kwargs) except boto.exception.NoAuthHandlerFound as e: module.fail_json(msg=str(e)) state = module.params.get('state') name = module.params.get('name') path = module.params.get('path') new_name = module.params.get('new_name') new_path = module.params.get('new_path') dup_ok = module.params.get('dup_ok') if state == 'present' and not new_name and not new_path: cert, key, cert_chain = load_data( cert=module.params.get('cert'), key=module.params.get('key'), cert_chain=module.params.get('cert_chain')) else: cert = key = cert_chain = None orig_cert_names = [ ctb['server_certificate_name'] for ctb in iam.get_all_server_certs(). list_server_certificates_result.server_certificate_metadata_list ] orig_cert_bodies = [ iam.get_server_certificate( thing).get_server_certificate_result.certificate_body for thing in orig_cert_names ] if new_name == name: new_name = None if new_path == path: new_path = None changed = False try: cert_action(module, iam, name, path, new_name, new_path, state, cert, key, cert_chain, orig_cert_names, orig_cert_bodies, dup_ok) except boto.exception.BotoServerError as err: module.fail_json(changed=changed, msg=str(err), debug=[cert, key])
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(eni_id=dict(default=None, type='str'), instance_id=dict(default=None, type='str'), private_ip_address=dict(type='str'), subnet_id=dict(type='str'), description=dict(type='str'), security_groups=dict(default=[], type='list'), device_index=dict(default=0, type='int'), state=dict(default='present', choices=['present', 'absent']), force_detach=dict(default='no', type='bool'), source_dest_check=dict(default=None, type='bool'), delete_on_termination=dict(default=None, type='bool'), secondary_private_ip_addresses=dict(default=None, type='list'), purge_secondary_private_ip_addresses=dict(default=False, type='bool'), secondary_private_ip_address_count=dict(default=None, type='int'), allow_reassignment=dict(default=False, type='bool'), attached=dict(default=None, type='bool'))) module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[[ 'secondary_private_ip_addresses', 'secondary_private_ip_address_count' ]], required_if=([ ('state', 'absent', ['eni_id']), ('attached', True, ['instance_id']), ('purge_secondary_private_ip_addresses', True, ['secondary_private_ip_addresses']) ])) if not HAS_BOTO: module.fail_json(msg='boto required for this module') region, ec2_url, aws_connect_params = get_aws_connection_info(module) if region: try: connection = connect_to_aws(boto.ec2, region, **aws_connect_params) vpc_connection = connect_to_aws(boto.vpc, region, **aws_connect_params) except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: module.fail_json(msg=str(e)) else: module.fail_json(msg="region must be specified") state = module.params.get("state") if state == 'present': eni = uniquely_find_eni(connection, module) if eni is None: subnet_id = module.params.get("subnet_id") if subnet_id is None: module.fail_json( msg="subnet_id is required when creating a new ENI") vpc_id = _get_vpc_id(vpc_connection, module, subnet_id) create_eni(connection, vpc_id, module) else: vpc_id = eni.vpc_id modify_eni(connection, vpc_id, module, eni) elif state == 'absent': delete_eni(connection, module)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(dhcp_options_id=dict(type='str', default=None), domain_name=dict(type='str', default=None), dns_servers=dict(type='list', default=None), ntp_servers=dict(type='list', default=None), netbios_name_servers=dict(type='list', default=None), netbios_node_type=dict(type='int', default=None), vpc_id=dict(type='str', default=None), delete_old=dict(type='bool', default=True), inherit_existing=dict(type='bool', default=False), tags=dict(type='dict', default=None, aliases=['resource_tags']), state=dict(type='str', default='present', choices=['present', 'absent']))) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) params = module.params found = False changed = False new_options = collections.defaultdict(lambda: None) if not HAS_BOTO: module.fail_json(msg='boto is required for this module') region, ec2_url, boto_params = get_aws_connection_info(module) connection = connect_to_aws(boto.vpc, region, **boto_params) existing_options = None # First check if we were given a dhcp_options_id if not params['dhcp_options_id']: # No, so create new_options from the parameters if params['dns_servers'] is not None: new_options['domain-name-servers'] = params['dns_servers'] if params['netbios_name_servers'] is not None: new_options['netbios-name-servers'] = params[ 'netbios_name_servers'] if params['ntp_servers'] is not None: new_options['ntp-servers'] = params['ntp_servers'] if params['domain_name'] is not None: # needs to be a list for comparison with boto objects later new_options['domain-name'] = [params['domain_name']] if params['netbios_node_type'] is not None: # needs to be a list for comparison with boto objects later new_options['netbios-node-type'] = [ str(params['netbios_node_type']) ] # If we were given a vpc_id then we need to look at the options on that if params['vpc_id']: existing_options = fetch_dhcp_options_for_vpc( connection, params['vpc_id']) # if we've been asked to inherit existing options, do that now if params['inherit_existing']: if existing_options: for option in [ 'domain-name-servers', 'netbios-name-servers', 'ntp-servers', 'domain-name', 'netbios-node-type' ]: if existing_options.options.get( option) and new_options[option] != [] and ( not new_options[option] or [''] == new_options[option]): new_options[option] = existing_options.options.get( option) # Do the vpc's dhcp options already match what we're asked for? if so we are done if existing_options and new_options == existing_options.options: module.exit_json(changed=changed, new_options=new_options, dhcp_options_id=existing_options.id) # If no vpc_id was given, or the options don't match then look for an existing set using tags found, dhcp_option = match_dhcp_options(connection, params['tags'], new_options) # Now let's cover the case where there are existing options that we were told about by id # If a dhcp_options_id was supplied we don't look at options inside, just set tags (if given) else: supplied_options = connection.get_all_dhcp_options( filters={'dhcp-options-id': params['dhcp_options_id']}) if len(supplied_options) != 1: if params['state'] != 'absent': module.fail_json( msg=" a dhcp_options_id was supplied, but does not exist") else: found = True dhcp_option = supplied_options[0] if params['state'] != 'absent' and params['tags']: ensure_tags(module, connection, dhcp_option.id, params['tags'], False, module.check_mode) # Now we have the dhcp options set, let's do the necessary # if we found options we were asked to remove then try to do so if params['state'] == 'absent': if not module.check_mode: if found: changed = remove_dhcp_options_by_id(connection, dhcp_option.id) module.exit_json(changed=changed, new_options={}) # otherwise if we haven't found the required options we have something to do elif not module.check_mode and not found: # create some dhcp options if we weren't able to use existing ones if not found: # Convert netbios-node-type and domain-name back to strings if new_options['netbios-node-type']: new_options['netbios-node-type'] = new_options[ 'netbios-node-type'][0] if new_options['domain-name']: new_options['domain-name'] = new_options['domain-name'][0] # create the new dhcp options set requested dhcp_option = connection.create_dhcp_options( new_options['domain-name'], new_options['domain-name-servers'], new_options['ntp-servers'], new_options['netbios-name-servers'], new_options['netbios-node-type']) # wait for dhcp option to be accessible found_dhcp_opt = False start_time = time() try: found_dhcp_opt = retry_not_found( connection.get_all_dhcp_options, dhcp_options_ids=[dhcp_option.id]) except EC2ResponseError as e: module.fail_json(msg="Failed to describe DHCP options", exception=traceback.format_exc) if not found_dhcp_opt: module.fail_json(msg="Failed to wait for {0} to be available.". format(dhcp_option.id)) changed = True if params['tags']: ensure_tags(module, connection, dhcp_option.id, params['tags'], False, module.check_mode) # If we were given a vpc_id, then attach the options we now have to that before we finish if params['vpc_id'] and not module.check_mode: changed = True connection.associate_dhcp_options(dhcp_option.id, params['vpc_id']) # and remove old ones if that was requested if params['delete_old'] and existing_options: remove_dhcp_options_by_id(connection, existing_options.id) module.exit_json(changed=changed, new_options=new_options, dhcp_options_id=dhcp_option.id)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict( state=dict(default='present', choices=['present', 'absent']), name=dict(required=True, type='str'), hash_key_name=dict(type='str'), hash_key_type=dict(default='STRING', type='str', choices=['STRING', 'NUMBER', 'BINARY']), range_key_name=dict(type='str'), range_key_type=dict(default='STRING', type='str', choices=['STRING', 'NUMBER', 'BINARY']), read_capacity=dict(default=1, type='int'), write_capacity=dict(default=1, type='int'), indexes=dict(default=[], type='list'), tags=dict(type='dict'), wait_for_active_timeout=dict(default=60, type='int'), )) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if not HAS_BOTO: module.fail_json(msg='boto required for this module') if not HAS_BOTO3 and module.params.get('tags'): module.fail_json(msg='boto3 required when using tags for this module') region, ec2_url, aws_connect_params = get_aws_connection_info(module) if not region: module.fail_json(msg='region must be specified') try: connection = connect_to_aws(boto.dynamodb2, region, **aws_connect_params) except (NoAuthHandlerFound, AnsibleAWSError) as e: module.fail_json(msg=str(e)) if module.params.get('tags'): try: region, ec2_url, aws_connect_kwargs = get_aws_connection_info( module, boto3=True) boto3_dynamodb = boto3_conn(module, conn_type='client', resource='dynamodb', region=region, endpoint=ec2_url, **aws_connect_kwargs) if not hasattr(boto3_dynamodb, 'tag_resource'): module.fail_json( msg= 'boto3 connection does not have tag_resource(), likely due to using an old version' ) boto3_sts = boto3_conn(module, conn_type='client', resource='sts', region=region, endpoint=ec2_url, **aws_connect_kwargs) except botocore.exceptions.NoCredentialsError as e: module.fail_json(msg='cannot connect to AWS', exception=traceback.format_exc()) else: boto3_dynamodb = None boto3_sts = None state = module.params.get('state') if state == 'present': create_or_update_dynamo_table(connection, module, boto3_dynamodb, boto3_sts, region) elif state == 'absent': delete_dynamo_table(connection, module)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict( state=dict(required=True, choices=['present', 'absent']), name=dict(required=True), description=dict(required=False), subnets=dict(required=False, type='list'), )) module = AnsibleModule(argument_spec=argument_spec) if not HAS_BOTO: module.fail_json(msg='boto required for this module') state = module.params.get('state') group_name = module.params.get('name').lower() group_description = module.params.get('description') group_subnets = module.params.get('subnets') or {} if state == 'present': for required in ['description', 'subnets']: if not module.params.get(required): module.fail_json( msg=str("Parameter %s required for state='present'" % required)) else: for not_allowed in ['description', 'subnets']: if module.params.get(not_allowed): module.fail_json( msg=str("Parameter %s not allowed for state='absent'" % not_allowed)) # Retrieve any AWS settings from the environment. region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module) if not region: module.fail_json(msg=str( "Either region or AWS_REGION or EC2_REGION environment variable or boto config aws_region or ec2_region must be set." )) try: conn = connect_to_aws(boto.rds, region, **aws_connect_kwargs) except BotoServerError as e: module.fail_json(msg=e.error_message) try: exists = False result = create_result(False) try: matching_groups = conn.get_all_db_subnet_groups(group_name, max_records=100) exists = len(matching_groups) > 0 except BotoServerError as e: if e.error_code != 'DBSubnetGroupNotFoundFault': module.fail_json(msg=e.error_message) if state == 'absent': if exists: conn.delete_db_subnet_group(group_name) result = create_result(True) else: if not exists: new_group = conn.create_db_subnet_group( group_name, desc=group_description, subnet_ids=group_subnets) result = create_result(True, new_group) else: # Sort the subnet groups before we compare them matching_groups[0].subnet_ids.sort() group_subnets.sort() if (matching_groups[0].name != group_name or matching_groups[0].description != group_description or matching_groups[0].subnet_ids != group_subnets): changed_group = conn.modify_db_subnet_group( group_name, description=group_description, subnet_ids=group_subnets) result = create_result(True, changed_group) else: result = create_result(False, matching_groups[0]) except BotoServerError as e: module.fail_json(msg=e.error_message) module.exit_json(**result)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(instance=dict(), id=dict(), name=dict(), volume_size=dict(type='int'), volume_type=dict(choices=['standard', 'gp2', 'io1', 'st1', 'sc1'], default='standard'), iops=dict(type='int'), encrypted=dict(type='bool', default=False), kms_key_id=dict(), device_name=dict(), delete_on_termination=dict(type='bool', default=False), zone=dict(aliases=['availability_zone', 'aws_zone', 'ec2_zone']), snapshot=dict(), state=dict(choices=['absent', 'present', 'list'], default='present'), tags=dict(type='dict', default={}))) module = AnsibleModule(argument_spec=argument_spec) if not HAS_BOTO: module.fail_json(msg='boto required for this module') id = module.params.get('id') name = module.params.get('name') instance = module.params.get('instance') volume_size = module.params.get('volume_size') encrypted = module.params.get('encrypted') kms_key_id = module.params.get('kms_key_id') device_name = module.params.get('device_name') zone = module.params.get('zone') snapshot = module.params.get('snapshot') state = module.params.get('state') tags = module.params.get('tags') # Ensure we have the zone or can get the zone if instance is None and zone is None and state == 'present': module.fail_json(msg="You must specify either instance or zone") # Set volume detach flag if instance == 'None' or instance == '': instance = None detach_vol_flag = True else: detach_vol_flag = False # Set changed flag changed = False region, ec2_url, aws_connect_params = get_aws_connection_info(module) if region: try: ec2 = connect_to_aws(boto.ec2, region, **aws_connect_params) except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: module.fail_json(msg=str(e)) else: module.fail_json(msg="region must be specified") if state == 'list': returned_volumes = [] vols = get_volumes(module, ec2) for v in vols: attachment = v.attach_data returned_volumes.append(get_volume_info(v, state)) module.exit_json(changed=False, volumes=returned_volumes) if encrypted and not boto_supports_volume_encryption(): module.fail_json( msg="You must use boto >= v2.29.0 to use encrypted volumes") if kms_key_id is not None and not boto_supports_kms_key_id(): module.fail_json(msg="You must use boto >= v2.39.0 to use kms_key_id") # Here we need to get the zone info for the instance. This covers situation where # instance is specified but zone isn't. # Useful for playbooks chaining instance launch with volume create + attach and where the # zone doesn't matter to the user. inst = None if instance: try: reservation = ec2.get_all_instances(instance_ids=instance) except BotoServerError as e: module.fail_json(msg=e.message) inst = reservation[0].instances[0] zone = inst.placement # Check if there is a volume already mounted there. if device_name: if device_name in inst.block_device_mapping: module.exit_json( msg="Volume mapping for %s already exists on instance %s" % (device_name, instance), volume_id=inst.block_device_mapping[device_name].volume_id, device=device_name, changed=False) # Delaying the checks until after the instance check allows us to get volume ids for existing volumes # without needing to pass an unused volume_size if not volume_size and not (id or name or snapshot): module.fail_json( msg= "You must specify volume_size or identify an existing volume by id, name, or snapshot" ) if volume_size and id: module.fail_json(msg="Cannot specify volume_size together with id") if state == 'present': volume, changed = create_volume(module, ec2, zone) if detach_vol_flag: volume, changed = detach_volume(module, ec2, volume) elif inst is not None: volume, changed = attach_volume(module, ec2, volume, inst) # Add device, volume_id and volume_type parameters separately to maintain backward compatibility volume_info = get_volume_info(volume, state) # deleteOnTermination is not correctly reflected on attachment if module.params.get('delete_on_termination'): for attempt in range(0, 8): if volume_info['attachment_set'].get( 'deleteOnTermination') == 'true': break time.sleep(5) volume = ec2.get_all_volumes(volume_ids=volume.id)[0] volume_info = get_volume_info(volume, state) module.exit_json(changed=changed, volume=volume_info, device=volume_info['attachment_set']['device'], volume_id=volume_info['id'], volume_type=volume_info['type']) elif state == 'absent': delete_volume(module, ec2)
def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( state=dict(required=True, choices=['present', 'absent']), group_name=dict(required=True, aliases=['name']), group_description=dict(required=False, aliases=['description']), group_subnets=dict(required=False, aliases=['subnets'], type='list'), )) module = AnsibleModule(argument_spec=argument_spec) if not HAS_BOTO: module.fail_json(msg='boto v2.9.0+ required for this module') state = module.params.get('state') group_name = module.params.get('group_name') group_description = module.params.get('group_description') group_subnets = module.params.get('group_subnets') if state == 'present': for required in ('group_name', 'group_description', 'group_subnets'): if not module.params.get(required): module.fail_json(msg=str("parameter %s required for state='present'" % required)) else: for not_allowed in ('group_description', 'group_subnets'): if module.params.get(not_allowed): module.fail_json(msg=str("parameter %s not allowed for state='absent'" % not_allowed)) region, ec2_url, aws_connect_params = get_aws_connection_info(module) if not region: module.fail_json(msg=str("Region must be specified as a parameter, in EC2_REGION or AWS_REGION environment variables or in boto configuration file")) # Connect to the Redshift endpoint. try: conn = connect_to_aws(boto.redshift, region, **aws_connect_params) except boto.exception.JSONResponseError as e: module.fail_json(msg=str(e)) try: changed = False exists = False group = None try: matching_groups = conn.describe_cluster_subnet_groups(group_name, max_records=100) exists = len(matching_groups) > 0 except boto.exception.JSONResponseError as e: if e.body['Error']['Code'] != 'ClusterSubnetGroupNotFoundFault': # if e.code != 'ClusterSubnetGroupNotFoundFault': module.fail_json(msg=str(e)) if state == 'absent': if exists: conn.delete_cluster_subnet_group(group_name) changed = True else: if not exists: new_group = conn.create_cluster_subnet_group(group_name, group_description, group_subnets) group = { 'name': new_group['CreateClusterSubnetGroupResponse']['CreateClusterSubnetGroupResult'] ['ClusterSubnetGroup']['ClusterSubnetGroupName'], 'vpc_id': new_group['CreateClusterSubnetGroupResponse']['CreateClusterSubnetGroupResult'] ['ClusterSubnetGroup']['VpcId'], } else: changed_group = conn.modify_cluster_subnet_group(group_name, group_subnets, description=group_description) group = { 'name': changed_group['ModifyClusterSubnetGroupResponse']['ModifyClusterSubnetGroupResult'] ['ClusterSubnetGroup']['ClusterSubnetGroupName'], 'vpc_id': changed_group['ModifyClusterSubnetGroupResponse']['ModifyClusterSubnetGroupResult'] ['ClusterSubnetGroup']['VpcId'], } changed = True except boto.exception.JSONResponseError as e: module.fail_json(msg=str(e)) module.exit_json(changed=changed, group=group)