def get_object(self): # find_obj doesn't include rootFolder if self.params['object_type'] == 'Folder' and self.params[ 'object_name'] == 'rootFolder': self.current_obj = self.content.rootFolder return try: getattr(vim, self.params['object_type']) except AttributeError: self.module.fail_json(msg="Object type %s is not valid." % self.params['object_type']) self.current_obj = find_obj( content=self.content, vimtype=[getattr(vim, self.params['object_type'])], name=self.params['object_name']) if self.current_obj is None: self.module.fail_json( msg="Specified object %s of type %s was not found." % (self.params['object_name'], self.params['object_type'])) if self.params['object_type'] == 'DistributedVirtualSwitch': msg = "You are applying permissions to a Distributed vSwitch. " \ "This will probably fail, since Distributed vSwitches inherits permissions " \ "from the datacenter or a folder level. " \ "Define permissions on the datacenter or the folder containing the switch." self.module.warn(msg)
def __init__(self, module): super(VMwareDvSwitchInfoManager, self).__init__(module) self.folder = self.params['folder'] self.switch_name = self.params['switch_name'] folder_obj = None if self.folder: folder_obj = self.content.searchIndex.FindByInventoryPath( self.folder) if not folder_obj: self.module.fail_json( msg="Failed to find folder specified by %s" % self.folder) if self.switch_name: self.switch_objs = [ find_object_by_name(self.content, self.switch_name, vim.DistributedVirtualSwitch, folder_obj) ] if None in self.switch_objs: self.switch_objs = None else: self.switch_objs = find_obj(self.content, [vim.DistributedVirtualSwitch], '', first=False)
def __init__(self, module): super(VMwareHostDatastore, self).__init__(module) # NOTE: The below parameter is deprecated starting from Ansible v2.11 self.datacenter_name = module.params['datacenter_name'] self.datastore_name = module.params['datastore_name'] self.datastore_type = module.params['datastore_type'] self.nfs_server = module.params['nfs_server'] self.nfs_path = module.params['nfs_path'] self.nfs_ro = module.params['nfs_ro'] self.vmfs_device_name = module.params['vmfs_device_name'] self.vmfs_version = module.params['vmfs_version'] self.esxi_hostname = module.params['esxi_hostname'] self.state = module.params['state'] if self.is_vcenter(): if not self.esxi_hostname: self.module.fail_json( msg="esxi_hostname is mandatory with a vcenter") self.esxi = self.find_hostsystem_by_name(self.esxi_hostname) if self.esxi is None: self.module.fail_json(msg="Failed to find ESXi hostname %s" % self.esxi_hostname) else: self.esxi = find_obj(self.content, [vim.HostSystem], None)
def __init__(self, module): super(VmwareHostSnmp, self).__init__(module) if self.is_vcenter(): self.module.fail_json( msg="You have to connect directly to the ESXi host. " "It's not possible to configure SNMP through a vCenter connection." ) else: self.host = find_obj(self.content, [vim.HostSystem], None) if self.host is None: self.module.fail_json(msg="Failed to find host system.")
def sanitize_params(self): ''' this method is used to verify user provided parameters ''' self.vm_obj = self.get_vm() if self.vm_obj is None: vm_id = self.vm_uuid or self.vm_name or self.moid self.module.fail_json( msg="Failed to find the VM/template with %s" % vm_id) # connect to destination VC self.destination_content = connect_to_api( self.module, hostname=self.destination_vcenter, username=self.destination_vcenter_username, password=self.destination_vcenter_password, port=self.destination_vcenter_port, validate_certs=self.destination_vcenter_validate_certs) # Check if vm name already exists in the destination VC vm = find_vm_by_name(content=self.destination_content, vm_name=self.params['destination_vm_name']) if vm: self.module.exit_json( changed=False, msg="A VM with the given name already exists") datastore_name = self.params['destination_datastore'] datastore_cluster = find_obj(self.destination_content, [vim.StoragePod], datastore_name) if datastore_cluster: # If user specified datastore cluster so get recommended datastore datastore_name = self.get_recommended_datastore( datastore_cluster_obj=datastore_cluster) # Check if get_recommended_datastore or user specified datastore exists or not self.destination_datastore = find_datastore_by_name( content=self.destination_content, datastore_name=datastore_name) if self.destination_datastore is None: self.module.fail_json(msg="Destination datastore not found.") self.destination_host = find_hostsystem_by_name( content=self.destination_content, hostname=self.params['destination_host']) if self.destination_host is None: self.module.fail_json(msg="Destination host not found.") if self.params['destination_resource_pool']: self.destination_resource_pool = find_resource_pool_by_name( content=self.destination_content, resource_pool_name=self.params['destination_resource_pool']) else: self.destination_resource_pool = self.destination_host.parent.resourcePool
def __init__(self, module): super(VMwareHostFactManager, self).__init__(module) esxi_host_name = self.params.get('esxi_hostname', None) if self.is_vcenter(): if esxi_host_name is None: self.module.fail_json(msg="Connected to a vCenter system without specifying esxi_hostname") self.host = self.get_all_host_objs(esxi_host_name=esxi_host_name) if len(self.host) > 1: self.module.fail_json(msg="esxi_hostname matched multiple hosts") self.host = self.host[0] else: self.host = find_obj(self.content, [vim.HostSystem], None) if self.host is None: self.module.fail_json(msg="Failed to find host system.")
def execute(self): result = {'changed': False} if self.object_name: obj = find_obj(self.content, [self.valid_object_types[self.object_type]], self.object_name) elif self.moid: obj = self.find_obj_by_moid(self.object_type, self.moid) if not obj: self.module.fail_json( msg="can't find the object: %s" % self.object_name if self.object_name else self.moid) custom_attributes = [] available_fields = {} for available_custom_attribute in obj.availableField: available_fields.update({ available_custom_attribute.key: { 'name': available_custom_attribute.name, 'type': available_custom_attribute.managedObjectType } }) custom_values = {} for custom_value in obj.customValue: custom_values.update({custom_value.key: custom_value.value}) for key, value in available_fields.items(): attribute_result = { 'attribute': value['name'], 'type': self.to_json(value['type']).replace('vim.', ''), 'key': key, 'value': None } if key in custom_values: attribute_result['value'] = custom_values[key] custom_attributes.append(attribute_result) result['custom_attributes'] = custom_attributes self.module.exit_json(**result)
def get_object(self): # find_obj doesn't include rootFolder if (self.params["object_type"] == "Folder" and self.params["object_name"] == "rootFolder"): self.current_obj = self.content.rootFolder return vim_type = None try: vim_type = getattr(vim, self.params["object_type"]) except AttributeError: pass if not vim_type: self.module.fail_json(msg="Object type %s is not valid." % self.params["object_type"]) msg = "Specified object " if "moid" in self.params and self.params["moid"]: self.current_obj = vim_type(self.params["moid"], self.si._stub) msg += "with moid %s of type %s" % ( self.params["moid"], self.params["object_type"], ) elif "object_name" in self.params and self.params["object_name"]: self.current_obj = find_obj( content=self.content, vimtype=[vim_type], name=self.params["object_name"], ) msg = "%s of type %s" % ( self.params["object_name"], self.params["object_type"], ) if self.current_obj is None: msg += "was not found" self.module.fail_json(msg=msg)
def sanitize_disk_inputs(self): """ Check correctness of disk input provided by user Returns: A list of dictionary containing disk information """ disks_data = list() if not self.desired_disks: self.module.exit_json(changed=False, msg="No disks provided for virtual" " machine '%s' for management." % self.vm.name) for disk_index, disk in enumerate(self.desired_disks): # Initialize default value for disk current_disk = dict(disk_index=disk_index, state='present', destroy=True, filename=None, datastore_cluster=None, datastore=None, autoselect_datastore=True, disk_unit_number=0, scsi_controller=0, disk_mode='persistent') # Check state if 'state' in disk: if disk['state'] not in ['absent', 'present']: self.module.fail_json( msg="Invalid state provided '%s' for disk index [%s]." " State can be either - 'absent', 'present'" % (disk['state'], disk_index)) else: current_disk['state'] = disk['state'] if current_disk['state'] == 'absent': current_disk['destroy'] = disk['destroy'] elif current_disk['state'] == 'present': # Select datastore or datastore cluster if 'datastore' in disk: if 'autoselect_datastore' in disk: self.module.fail_json( msg="Please specify either 'datastore' " "or 'autoselect_datastore' for disk index [%s]" % disk_index) # Check if given value is datastore or datastore cluster datastore_name = disk['datastore'] datastore_cluster = find_obj(self.content, [vim.StoragePod], datastore_name) datastore = find_obj(self.content, [vim.Datastore], datastore_name) if datastore is None and datastore_cluster is None: self.module.fail_json( msg= "Failed to find datastore or datastore cluster named '%s' " "in given configuration." % disk['datastore']) if datastore_cluster: # If user specified datastore cluster, keep track of that for determining datastore later current_disk['datastore_cluster'] = datastore_cluster elif datastore: current_disk['datastore'] = datastore current_disk['autoselect_datastore'] = False elif 'autoselect_datastore' in disk: # Find datastore which fits requirement datastores = get_all_objs(self.content, [vim.Datastore]) if not datastores: self.module.fail_json( msg="Failed to gather information about" " available datastores in given datacenter.") datastore = None datastore_freespace = 0 for ds in datastores: if ds.summary.freeSpace > datastore_freespace: # If datastore field is provided, filter destination datastores datastore = ds datastore_freespace = ds.summary.freeSpace current_disk['datastore'] = datastore if 'datastore' not in disk and 'autoselect_datastore' not in disk and 'filename' not in disk: self.module.fail_json( msg="Either 'datastore' or 'autoselect_datastore' is" " required parameter while creating disk for " "disk index [%s]." % disk_index) if 'filename' in disk: current_disk['filename'] = disk['filename'] if [ x for x in disk.keys() if x.startswith('size_') or x == 'size' ]: # size, size_tb, size_gb, size_mb, size_kb disk_size_parse_failed = False if 'size' in disk: size_regex = re.compile( r'(\d+(?:\.\d+)?)([tgmkTGMK][bB])') disk_size_m = size_regex.match(disk['size']) if disk_size_m: expected = disk_size_m.group(1) unit = disk_size_m.group(2) else: disk_size_parse_failed = True try: if re.match(r'\d+\.\d+', expected): # We found float value in string, let's typecast it expected = float(expected) else: # We found int value in string, let's typecast it expected = int(expected) except (TypeError, ValueError, NameError): disk_size_parse_failed = True else: # Even multiple size_ parameter provided by user, # consider first value only param = [ x for x in disk.keys() if x.startswith('size_') ][0] unit = param.split('_')[-1] disk_size = disk[param] if isinstance(disk_size, (float, int)): disk_size = str(disk_size) try: if re.match(r'\d+\.\d+', disk_size): # We found float value in string, let's typecast it expected = float(disk_size) else: # We found int value in string, let's typecast it expected = int(disk_size) except (TypeError, ValueError, NameError): disk_size_parse_failed = True if disk_size_parse_failed: # Common failure self.module.fail_json( msg="Failed to parse disk size for disk index [%s]," " please review value provided" " using documentation." % disk_index) disk_units = dict(tb=3, gb=2, mb=1, kb=0) unit = unit.lower() if unit in disk_units: current_disk['size'] = expected * (1024** disk_units[unit]) else: self.module.fail_json( msg= "%s is not a supported unit for disk size for disk index [%s]." " Supported units are ['%s']." % (unit, disk_index, "', '".join(disk_units.keys()))) elif current_disk['filename'] is None: # No size found but disk, fail self.module.fail_json( msg="No size, size_kb, size_mb, size_gb or size_tb" " attribute found into disk index [%s] configuration." % disk_index) # Check SCSI controller key if 'scsi_controller' in disk: try: temp_disk_controller = int(disk['scsi_controller']) except ValueError: self.module.fail_json( msg="Invalid SCSI controller ID '%s' specified" " at index [%s]" % (disk['scsi_controller'], disk_index)) if temp_disk_controller not in range(0, 4): # Only 4 SCSI controllers are allowed per VM self.module.fail_json( msg="Invalid SCSI controller ID specified [%s]," " please specify value between 0 to 3 only." % temp_disk_controller) current_disk['scsi_controller'] = temp_disk_controller else: self.module.fail_json( msg="Please specify 'scsi_controller' under disk parameter" " at index [%s], which is required while creating disk." % disk_index) # Check for disk unit number if 'unit_number' in disk: try: temp_disk_unit_number = int(disk['unit_number']) except ValueError: self.module.fail_json( msg="Invalid Disk unit number ID '%s'" " specified at index [%s]" % (disk['unit_number'], disk_index)) if temp_disk_unit_number not in range(0, 16): self.module.fail_json( msg= "Invalid Disk unit number ID specified for disk [%s] at index [%s]," " please specify value between 0 to 15" " only (excluding 7)." % (temp_disk_unit_number, disk_index)) if temp_disk_unit_number == 7: self.module.fail_json( msg= "Invalid Disk unit number ID specified for disk at index [%s]," " please specify value other than 7 as it is reserved" "for SCSI Controller" % disk_index) current_disk['disk_unit_number'] = temp_disk_unit_number else: self.module.fail_json( msg="Please specify 'unit_number' under disk parameter" " at index [%s], which is required while creating disk." % disk_index) # Type of Disk disk_type = disk.get('type', 'thick').lower() if disk_type not in ['thin', 'thick', 'eagerzeroedthick']: self.module.fail_json( msg= "Invalid 'disk_type' specified for disk index [%s]. Please specify" " 'disk_type' value from ['thin', 'thick', 'eagerzeroedthick']." % disk_index) current_disk['disk_type'] = disk_type # Mode of Disk temp_disk_mode = disk.get('disk_mode', 'persistent').lower() if temp_disk_mode not in [ 'persistent', 'independent_persistent', 'independent_nonpersistent' ]: self.module.fail_json( msg= "Invalid 'disk_mode' specified for disk index [%s]. Please specify" " 'disk_mode' value from ['persistent', 'independent_persistent', 'independent_nonpersistent']." % disk_index) current_disk['disk_mode'] = temp_disk_mode # SCSI Controller Type scsi_contrl_type = disk.get('scsi_type', 'paravirtual').lower() if scsi_contrl_type not in self.scsi_device_type.keys(): self.module.fail_json( msg= "Invalid 'scsi_type' specified for disk index [%s]. Please specify" " 'scsi_type' value from ['%s']" % (disk_index, "', '".join(self.scsi_device_type.keys()))) current_disk['scsi_type'] = scsi_contrl_type if 'shares' in disk: current_disk['shares'] = disk['shares'] if 'iolimit' in disk: current_disk['iolimit'] = disk['iolimit'] disks_data.append(current_disk) return disks_data
def ensure_disks(self, vm_obj=None): """ Manage internal state of virtual machine disks Args: vm_obj: Managed object of virtual machine """ # Set vm object self.vm = vm_obj # Sanitize user input disk_data = self.sanitize_disk_inputs() # Create stateful information about SCSI devices current_scsi_info = dict() results = dict(changed=False, disk_data=None, disk_changes=dict()) # Deal with SCSI Controller for device in vm_obj.config.hardware.device: if isinstance(device, tuple(self.scsi_device_type.values())): # Found SCSI device if device.busNumber not in current_scsi_info: device_bus_number = 1000 + device.busNumber current_scsi_info[device_bus_number] = dict(disks=dict()) scsi_changed = False for disk in disk_data: scsi_controller = disk['scsi_controller'] + 1000 if scsi_controller not in current_scsi_info and disk[ 'state'] == 'present': scsi_ctl = self.create_scsi_controller(disk['scsi_type'], disk['scsi_controller']) current_scsi_info[scsi_controller] = dict(disks=dict()) self.config_spec.deviceChange.append(scsi_ctl) scsi_changed = True if scsi_changed: self.reconfigure_vm(self.config_spec, 'SCSI Controller') self.config_spec = vim.vm.ConfigSpec() self.config_spec.deviceChange = [] # Deal with Disks for device in vm_obj.config.hardware.device: if isinstance(device, vim.vm.device.VirtualDisk): # Found Virtual Disk device if device.controllerKey not in current_scsi_info: current_scsi_info[device.controllerKey] = dict( disks=dict()) current_scsi_info[device.controllerKey]['disks'][ device.unitNumber] = device disk_change_list = [] for disk in disk_data: disk_change = False scsi_controller = disk[ 'scsi_controller'] + 1000 # VMware auto assign 1000 + SCSI Controller if disk['disk_unit_number'] not in current_scsi_info[ scsi_controller]['disks'] and disk['state'] == 'present': # Add new disk disk_spec = self.create_scsi_disk(scsi_controller, disk['disk_unit_number'], disk['disk_mode'], disk['filename']) if disk['filename'] is None: disk_spec.device.capacityInKB = disk['size'] if disk['disk_type'] == 'thin': disk_spec.device.backing.thinProvisioned = True elif disk['disk_type'] == 'eagerzeroedthick': disk_spec.device.backing.eagerlyScrub = True # get Storage DRS recommended datastore from the datastore cluster if disk['datastore_cluster'] is not None: datastore_name = self.get_recommended_datastore( datastore_cluster_obj=disk['datastore_cluster'], disk_spec_obj=disk_spec) disk['datastore'] = find_obj(self.content, [vim.Datastore], datastore_name) if disk['filename'] is not None: disk_spec.device.backing.fileName = disk['filename'] disk_spec.device.backing.datastore = disk['datastore'] disk_spec = self.get_ioandshares_diskconfig(disk_spec, disk) self.config_spec.deviceChange.append(disk_spec) disk_change = True current_scsi_info[scsi_controller]['disks'][ disk['disk_unit_number']] = disk_spec.device results['disk_changes'][disk['disk_index']] = "Disk created." elif disk['disk_unit_number'] in current_scsi_info[ scsi_controller]['disks']: if disk['state'] == 'present': disk_spec = vim.vm.device.VirtualDeviceSpec() # set the operation to edit so that it knows to keep other settings disk_spec.device = current_scsi_info[scsi_controller][ 'disks'][disk['disk_unit_number']] # Edit and no resizing allowed if disk['size'] < disk_spec.device.capacityInKB: self.module.fail_json( msg= "Given disk size at disk index [%s] is smaller than found (%d < %d)." "Reducing disks is not allowed." % (disk['disk_index'], disk['size'], disk_spec.device.capacityInKB)) if disk['size'] != disk_spec.device.capacityInKB: disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit disk_spec = self.get_ioandshares_diskconfig( disk_spec, disk) disk_spec.device.capacityInKB = disk['size'] self.config_spec.deviceChange.append(disk_spec) disk_change = True results['disk_changes'][ disk['disk_index']] = "Disk size increased." else: results['disk_changes'][ disk['disk_index']] = "Disk already exists." elif disk['state'] == 'absent': # Disk already exists, deleting disk_spec = vim.vm.device.VirtualDeviceSpec() disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.remove if disk['destroy'] is True: disk_spec.fileOperation = vim.vm.device.VirtualDeviceSpec.FileOperation.destroy disk_spec.device = current_scsi_info[scsi_controller][ 'disks'][disk['disk_unit_number']] self.config_spec.deviceChange.append(disk_spec) disk_change = True results['disk_changes'][ disk['disk_index']] = "Disk deleted." if disk_change: # Adding multiple disks in a single attempt raises weird errors # So adding single disk at a time. self.reconfigure_vm(self.config_spec, 'disks') self.config_spec = vim.vm.ConfigSpec() self.config_spec.deviceChange = [] disk_change_list.append(disk_change) if any(disk_change_list): results['changed'] = True results['disk_data'] = self.gather_disk_facts(vm_obj=self.vm) self.module.exit_json(**results)
def sanitize_params(self): ''' Verify user-provided parameters ''' # connect to host/VC self.destination_content = connect_to_api( self.module, hostname=self.hostname, username=self.username, password=self.password, port=self.port, validate_certs=self.validate_certs) use_instance_uuid = self.params.get('use_instance_uuid') or False if 'parent_vm' in self.params and self.params['parent_vm']: self.vm_obj = find_vm_by_name(content=self.destination_content, vm_name=self.parent_vm) elif 'uuid' in self.params and self.params['uuid']: if not use_instance_uuid: self.vm_obj = find_vm_by_id(content=self.destination_content, vm_id=self.params['uuid'], vm_id_type="uuid") elif use_instance_uuid: self.vm_obj = find_vm_by_id(content=self.destination_content, vm_id=self.params['uuid'], vm_id_type="instance_uuid") elif 'moid' in self.params and self.params['moid']: self.vm_obj = vim.VirtualMachine(self.params['moid'], self.si._stub) if self.vm_obj is None: vm_id = self.parent_vm or self.uuid or self.moid self.module.fail_json( msg="Failed to find the VM/template with %s" % vm_id) vm = find_vm_by_name(content=self.destination_content, vm_name=self.params['name']) if vm: self.module.exit_json( changed=False, msg="A VM with the given name already exists") self.datacenter = self.find_datacenter_by_name( self.params['datacenter']) # datacentre check if self.datacenter is None: self.module.fail_json(msg="Datacenter not found.") datastore_name = self.params['datastore'] datastore_cluster = find_obj(self.destination_content, [vim.StoragePod], datastore_name) if datastore_cluster: # If user specified datastore cluster so get recommended datastore datastore_name = self.get_recommended_datastore( datastore_cluster_obj=datastore_cluster) # Check if get_recommended_datastore or user specified datastore exists or not # datastore check self.datastore = self.find_datastore_by_name( datastore_name=datastore_name) if self.datastore is None: self.module.fail_json(msg="Datastore not found.") if self.params['folder']: self.folder = self.find_folder_by_name( folder_name=self.params['folder']) if self.folder is None: self.module.fail_json(msg="Folder not found.") else: self.folder = self.datacenter.vmFolder self.host = self.find_hostsystem_by_name(host_name=self.params['host']) if self.host is None: self.module.fail_json(msg="Host not found.") if self.params['resource_pool']: self.resource_pool = self.find_resource_pool_by_name( resource_pool_name=self.params['resource_pool']) if self.resource_pool is None: self.module.fail_json(msg="Resource Pool not found.") else: self.resource_pool = self.host.parent.resourcePool
def get_config_option_for_guest(self): results = {} guest_id = [] host = None datacenter_name = self.params.get('datacenter') cluster_name = self.params.get('cluster_name') esxi_host_name = self.params.get('esxi_hostname') if self.params.get('guest_id'): guest_id = [self.params.get('guest_id')] if not self.params.get('get_hardware_versions') and not self.params.get('get_guest_os_ids') \ and not self.params.get('get_config_options'): self.module.exit_json(msg="Please set at least one of these parameters 'get_hardware_versions'," " 'get_guest_os_ids', 'get_config_options' to True to get the desired info.") if self.params.get('get_config_options') and len(guest_id) == 0: self.module.fail_json(msg="Please set 'guest_id' when 'get_config_options' is set to True," " to get the VM recommended config option for specific guest OS.") # Get the datacenter object datacenter = find_obj(self.content, [vim.Datacenter], datacenter_name) if not datacenter: self.module.fail_json(msg='Unable to find datacenter "%s"' % datacenter_name) # Get the cluster object if cluster_name: cluster = find_obj(self.content, [vim.ComputeResource], cluster_name, folder=datacenter) if not cluster: self.module.fail_json(msg='Unable to find cluster "%s"' % cluster_name) # If host is given, get the cluster object using the host elif esxi_host_name: host = find_obj(self.content, [vim.HostSystem], esxi_host_name, folder=datacenter) if not host: self.module.fail_json(msg='Unable to find host "%s"' % esxi_host_name) cluster = host.parent # Define the environment browser object the ComputeResource presents env_browser = cluster.environmentBrowser if env_browser is None: self.module.fail_json(msg="The environmentBrowser of the ComputeResource is None, so can not get the" " desired config option info, please check your vSphere environment.") # Get supported hardware versions list support_create_list, default_config = self.get_hardware_versions(env_browser=env_browser) if self.params.get('get_hardware_versions'): results.update({'Supported hardware versions': support_create_list, 'Default hardware version': default_config}) if self.params.get('get_guest_os_ids') or self.params.get('get_config_options'): # Get supported guest ID list hardware_version = self.params.get('hardware_version', '') if hardware_version and len(support_create_list) != 0 and hardware_version not in support_create_list: self.module.fail_json(msg="Specified hardware version '%s' is not in the supported create list: %s" % (hardware_version, support_create_list)) vm_config_option_all = self.get_config_option_by_spec(env_browser=env_browser, host=host, key=hardware_version) supported_gos_list = self.get_guest_id_list(guest_os_desc=vm_config_option_all) if self.params.get('get_guest_os_ids'): info_key = 'Supported guest IDs for %s' % vm_config_option_all.version results.update({info_key: supported_gos_list}) if self.params.get('get_config_options') and len(guest_id) != 0: if supported_gos_list and guest_id[0] not in supported_gos_list: self.module.fail_json(msg="Specified guest ID '%s' is not in the supported guest ID list: '%s'" % (guest_id[0], supported_gos_list)) vm_config_option_guest = self.get_config_option_by_spec(env_browser=env_browser, host=host, guest_id=guest_id, key=hardware_version) guest_os_options = vm_config_option_guest.guestOSDescriptor guest_os_option_dict = self.get_config_option_recommended(guest_os_desc=guest_os_options, hwv_version=vm_config_option_guest.version) results.update({'Recommended config options': guest_os_option_dict}) self.module.exit_json(changed=False, failed=False, instance=results)