Bug 1380946

Summary: [RFE] nova vmwareapi driver allow display of hostnames as instance names instead of UUID only
Product: Red Hat OpenStack Reporter: Andreas Karis <akaris>
Component: openstack-novaAssignee: Eoghan Glynn <eglynn>
Status: CLOSED NOTABUG QA Contact: Tzach Shefi <tshefi>
Severity: low Docs Contact:
Priority: low    
Version: 9.0 (Mitaka)CC: berrange, dasmith, eglynn, kchamart, sbauza, sferdjao, sgordon, srevivo, tshefi, vromanso
Target Milestone: ---Keywords: FutureFeature
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2017-07-18 19:56:32 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Andreas Karis 2016-10-01 19:15:02 UTC
Description of problem:
When instances are created from openstack, the VMs created in vCenter are named by the instance UUID. I would like to configure it, so they appear with the instance names instead.

Version-Release number of selected component (if applicable):
all versions

How reproducible:
all the time

Additional info:
Looking into the newest code
https://github.com/openstack/nova/blob/master/nova/virt/vmwareapi/driver.py
~~~
(...)
from oslo_vmware import api
(...)
from nova.virt.vmwareapi import vmops
(...)
   self._session = VMwareAPISession(scheme=scheme)
(...)
   self._vmops = vmops.VMwareVMOps(self._session,
                                        virtapi,
                                        self._volumeops,
                                        self._cluster_ref,
                                        datastore_regex=self._datastore_regex)
(...)
    def spawn(self, context, instance, image_meta, injected_files,
              admin_password, network_info=None, block_device_info=None):
        """Create VM instance."""
        self._vmops.spawn(context, instance, image_meta, injected_files,
                          admin_password, network_info, block_device_info)
(...)
class VMwareAPISession(api.VMwareAPISession):
(...)
    def _call_method(self, module, method, *args, **kwargs):
        """Calls a method within the module specified with
        args provided.
        """
        if not self._is_vim_object(module):
            return self.invoke_api(module, method, self.vim, *args, **kwargs)
        else:
            return self.invoke_api(module, method, *args, **kwargs)
(...)
~~~

https://github.com/openstack/nova/blob/master/nova/virt/vmwareapi/vmops.py
~~~
(...)
from nova.virt.vmwareapi import vm_util
(...)
  class VMwareVMOps(object):
    """Management class for VM-related tasks."""

    def __init__(self, session, virtapi, volumeops, cluster=None,
                 datastore_regex=None):
(...)       
        # Creates the virtual machine. The virtual machine reference returned
        # is unique within Virtual Center.
        vm_ref = self.build_virtual_machine(instance,
                                            image_info,
                                            vi.dc_info,
                                            vi.datastore,
                                            network_info,
                                            extra_specs,
                                            metadata)
(...)
        config_spec = vm_util.get_vm_create_spec(client_factory,
                                                 instance,
                                                 datastore.name,
                                                 vif_infos,
                                                 extra_specs,
                                                 image_info.os_type,
                                                 profile_spec=profile_spec,
                                                 metadata=metadata)
(...)
        # Create the VM
        vm_ref = vm_util.create_vm(self._session, instance, folder,
                                   config_spec, self._root_resource_pool)
(...)
~~~

https://github.com/openstack/nova/blob/master/nova/virt/vmwareapi/vm_util.py
~~~
(...)
def get_vm_create_spec(client_factory, instance, data_store_name,
                       vif_infos, extra_specs,
                       os_type=constants.DEFAULT_OS_TYPE,
                       profile_spec=None, metadata=None):
    """Builds the VM Create spec."""
    config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
    config_spec.name = instance.uuid
    config_spec.guestId = os_type
    # The name is the unique identifier for the VM.
    config_spec.instanceUuid = instance.uuid
    if metadata:
        config_spec.annotation = metadata
    # set the Hardware version
    config_spec.version = extra_specs.hw_version
(...)
def create_vm(session, instance, vm_folder, config_spec, res_pool_ref):
    """Create VM on ESX host."""
    LOG.debug("Creating VM on the ESX host", instance=instance)
    vm_create_task = session._call_method(
        session.vim,
        "CreateVM_Task", vm_folder,
        config=config_spec, pool=res_pool_ref)
    try:
        task_info = session._wait_for_task(vm_create_task)
(...)
~~~

If I correctly interpret the code, the actual "issue" lies here:
https://github.com/openstack/nova/blob/master/nova/virt/vmwareapi/vm_util.py
Line 199: config_spec.name = instance.uuid
Line 202: config_spec.instanceUuid = instance.uuid

In driver.py, this here
~~~
    def _call_method(self, module, method, *args, **kwargs):
        """Calls a method within the module specified with
        args provided.
        """
        if not self._is_vim_object(module):
            return self.invoke_api(module, method, self.vim, *args, **kwargs)
        else:
            return self.invoke_api(module, method, *args, **kwargs)
~~~
calls  oslo_vmware api.VMwareAPISession's invoke_api with method:
"CreateVM_Task", config=config_spec (with config_spec.name and config_spec.instanceUuuid both set to the instance's uuid).

https://github.com/openstack/oslo.vmware/blob/master/oslo_vmware/api.py
~~~
(...)
def invoke_api(self, module, method, *args, **kwargs):
        """Wrapper method for invoking APIs.
        The API call is retried in the event of exceptions due to session
        overload or connection problems.
        :param module: module corresponding to the VIM API call
        :param method: method in the module which corresponds to the
                       VIM API call
        :param args: arguments to the method
        :param kwargs: keyword arguments to the method
        :returns: response from the API call
        :raises: VimException, VimFaultException, VimAttributeException,
                 VimSessionOverLoadException, VimConnectionException
(...)
~~~

So let's have a look at the vmware API
https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2017436
http://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/right-pane.html

And specifically for CreateVM_Task:
http://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.Folder.html?path=7_0_0_2_6_3_78#createVm

where: config	VirtualMachineConfigSpec The configuration of the virtual machine hardware.

So let's look at http://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.ConfigSpec.html
~~~
(...)
name*	xsd:string	

Display name of the virtual machine.

Any % (percent) character used in this name parameter must be escaped, unless it is used to start an escape sequence. Clients may also escape any other characters in this name parameter. Snapshots of virtual machines that have spaces in their names and are associated with ESX 2.x servers are not supported. Therefore, if you want the option to take snapshots of this virtual machine and you are associating it with an ESX 2.x server, do not use spaces in the name.

Reconfigure privilege: VirtualMachine.Config.Rename 
(...)
instanceUuid*	xsd:string	

VirtualCenter-specific 128-bit UUID of a virtual machine, represented as a hexadecimal string. This identifier is used by VirtalCenter to uniquely identify all virtual machine instances in the Virtual Infrastructure environment, including those that may share the same SMBIOS UUID.

Normally, this property is not set by a client, allowing the Virtual Infrastructure environment to assign or change it when VirtualCenter detects an identifier conflict between virtual machines. This identifier can be modified even when a virtual machine is powered on. Clients can specify that vCenter Server reassign a new identifier by a providing an empty string. Reassigning the identifer is not allowed for Fault Tolerance virtual machines.

Reconfigure privilege: VirtualMachine.Config.Settings

Since vSphere API 4.0
(...)
~~~

Which proves that the display name is hardcoded as the instance UUID.

Comment 1 Stephen Gordon 2017-07-18 19:56:32 UTC
(In reply to Andreas Karis from comment #0)

> Which proves that the display name is hardcoded as the instance UUID.

This (hardcoding the instance name to the UUID) is the intended/documented behavior choice of the VMware vCenter driver as provided upstream - not an accidental choice as I understand it.

From the configuration reference guide:

"The vCenter driver generates instance name by instance ID. Instance name template is ignored."

https://docs.openstack.org/ocata/config-reference/compute/hypervisor-vmware.html

http://git.openstack.org/cgit/openstack/nova/commit/?id=86f385b955151d2648aa42c42a8489d36e489286