[libvirt] [PATCH] vmx: Expose VMware Managed Object Reference (moref) in XML.

Michal Privoznik mprivozn at redhat.com
Fri Sep 1 09:23:56 UTC 2017


On 08/25/2017 04:04 PM, Richard W.M. Jones wrote:
> If you use the VDDK library to access virtual machines remotely, you
> really need to know the Managed Object Reference ("moref") of the VM.
> This must be passed each time you connect to the API.
> 
> For example nbdkit's VDDK plugin requires a moref to be passed to
> mount up a VM's disk remotely:
> 
>  nbdkit vddk user=root password=+/tmp/rootpw \
>              server=esxi.example.com thumbprint=xx:xx:xx:... \
>              vm=moref=2 \
>              file="[datastore1] Fedora/Fedora.vmdk"
> 
> Getting the moref is a huge pain.  To get some idea of what it is, why
> it is needed, and how much trouble it is to get it, see:
> https://blogs.vmware.com/vsphere/2012/02/uniquely-identifying-virtual-machines-in-vsphere-and-vcloud-part-1-overview.html
> https://blogs.vmware.com/vsphere/2012/02/uniquely-identifying-virtual-machines-in-vsphere-and-vcloud-part-2-technical.html
> 
> However the moref is available conveniently in the internals of the
> libvirt VMX driver.  This patch exposes it as a custom XML element
> using the same "vmware:" namespace which was previously used for the
> datacenterpath (see libvirt commit 636a99058758a044).
> 
> It appears in the XML like this:
> 
> <domain type='vmware' xmlns:vmware='http://libvirt.org/schemas/domain/vmware/1.0'>
>   <name>Fedora</name>
> ...
>   <vmware:datacenterpath>ha-datacenter</vmware:datacenterpath>
>   <vmware:moref>2</vmware:moref>
> </domain>
> 
> Note that the moref can appear as either a simple ID (for esx://
> connections) or as a "vm-<ID>" (for vpx:// connections).  It should be
> treated by users as an opaque string.
> ---
>  src/esx/esx_driver.c |  7 +++++++
>  src/esx/esx_vi.c     | 15 +++++++++++++++
>  src/esx/esx_vi.h     |  4 ++++
>  src/vmx/vmx.c        | 51 +++++++++++++++++++++++++++++++++++++++++----------
>  src/vmx/vmx.h        |  2 ++
>  5 files changed, 69 insertions(+), 10 deletions(-)
> 
> diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
> index 1f4f2c7a7..0cce0a41a 100644
> --- a/src/esx/esx_driver.c
> +++ b/src/esx/esx_driver.c
> @@ -2645,6 +2645,7 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
>      esxVI_ObjectContent *virtualMachine = NULL;
>      esxVI_VirtualMachinePowerState powerState;
>      int id;
> +    char *moref = NULL;
>      char *vmPathName = NULL;
>      char *datastoreName = NULL;
>      char *directoryName = NULL;
> @@ -2670,6 +2671,7 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
>          esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
>                                           propertyNameList, &virtualMachine,
>                                           esxVI_Occurrence_RequiredItem) < 0 ||
> +        esxVI_GetVirtualMachineMORef(virtualMachine, &moref) < 0 ||
>          esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
>          esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0 ||
>          esxVI_GetStringValue(virtualMachine, "config.files.vmPathName",
> @@ -2715,6 +2717,7 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
>      ctx.formatFileName = NULL;
>      ctx.autodetectSCSIControllerModel = NULL;
>      ctx.datacenterPath = priv->primary->datacenterPath;
> +    ctx.moref = moref;
>  
>      def = virVMXParseConfig(&ctx, priv->xmlopt, priv->caps, vmx);
>  
> @@ -2732,6 +2735,7 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
>  
>      esxVI_String_Free(&propertyNameList);
>      esxVI_ObjectContent_Free(&virtualMachine);
> +    VIR_FREE(moref);
>      VIR_FREE(datastoreName);
>      VIR_FREE(directoryName);
>      VIR_FREE(directoryAndFileName);
> @@ -2774,6 +2778,7 @@ esxConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
>      ctx.formatFileName = NULL;
>      ctx.autodetectSCSIControllerModel = NULL;
>      ctx.datacenterPath = NULL;
> +    ctx.moref = NULL;
>  
>      def = virVMXParseConfig(&ctx, priv->xmlopt, priv->caps, nativeConfig);
>  
> @@ -2830,6 +2835,7 @@ esxConnectDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
>      ctx.formatFileName = esxFormatVMXFileName;
>      ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
>      ctx.datacenterPath = NULL;
> +    ctx.moref = NULL;
>  
>      vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
>  
> @@ -3077,6 +3083,7 @@ esxDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
>      ctx.formatFileName = esxFormatVMXFileName;
>      ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
>      ctx.datacenterPath = NULL;
> +    ctx.moref = NULL;
>  
>      vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
>  
> diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
> index 8586e3ff0..77bcfd9b6 100644
> --- a/src/esx/esx_vi.c
> +++ b/src/esx/esx_vi.c
> @@ -2390,6 +2390,21 @@ esxVI_GetVirtualMachineQuestionInfo
>  }
>  
>  
> +int
> +esxVI_GetVirtualMachineMORef(esxVI_ObjectContent *virtualMachine,
> +                             char **moref)
> +{
> +    for (; virtualMachine != NULL; virtualMachine = virtualMachine->_next) {
> +        if (virtualMachine->obj &&
> +            STREQ(virtualMachine->obj->type, "VirtualMachine") &&
> +            virtualMachine->obj->value) {
> +            if (VIR_STRDUP(*moref, virtualMachine->obj->value) < 0)
> +                return -1;
> +            return 0;

Or return VIR_STRDUP() for short.

> +        }
> +    }
> +    return -1;
> +}
>  
>  int
>  esxVI_GetBoolean(esxVI_ObjectContent *objectContent, const char *propertyName,
> diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
> index 7c53f3781..47d518dd1 100644
> --- a/src/esx/esx_vi.h
> +++ b/src/esx/esx_vi.h
> @@ -334,6 +334,10 @@ int esxVI_GetVirtualMachineQuestionInfo
>        (esxVI_ObjectContent *virtualMachine,
>         esxVI_VirtualMachineQuestionInfo **questionInfo);
>  
> +int esxVI_GetVirtualMachineMORef
> +      (esxVI_ObjectContent *virtualMachine,
> +       char **moref);
> +
>  int esxVI_GetBoolean(esxVI_ObjectContent *objectContent,
>                       const char *propertyName,
>                       esxVI_Boolean *value, esxVI_Occurrence occurrence);
> diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c
> index d1d8184c5..6f96f4cbf 100644
> --- a/src/vmx/vmx.c
> +++ b/src/vmx/vmx.c
> @@ -553,23 +553,41 @@ static virDomainDefParserConfig virVMXDomainDefParserConfig = {
>                   VIR_DOMAIN_DEF_FEATURE_NAME_SLASH),
>  };
>  
> +struct virVMXDomainDefNamespaceData {
> +    char *datacenterPath;
> +    char *moref;
> +};
> +
>  static void
>  virVMXDomainDefNamespaceFree(void *nsdata)
>  {
> -    VIR_FREE(nsdata);
> +    struct virVMXDomainDefNamespaceData *data = nsdata;
> +
> +    if (data) {
> +        VIR_FREE(data->datacenterPath);
> +        VIR_FREE(data->moref);
> +    }
> +    VIR_FREE(data);
>  }
>  
>  static int
>  virVMXDomainDefNamespaceFormatXML(virBufferPtr buf, void *nsdata)
>  {
> -    const char *datacenterPath = nsdata;
> +    struct virVMXDomainDefNamespaceData *data = nsdata;
>  
> -    if (!datacenterPath)
> +    if (!data)
>          return 0;
>  
> -    virBufferAddLit(buf, "<vmware:datacenterpath>");
> -    virBufferEscapeString(buf, "%s", datacenterPath);
> -    virBufferAddLit(buf, "</vmware:datacenterpath>\n");
> +    if (data->datacenterPath) {
> +        virBufferAddLit(buf, "<vmware:datacenterpath>");
> +        virBufferEscapeString(buf, "%s", data->datacenterPath);
> +        virBufferAddLit(buf, "</vmware:datacenterpath>\n");
> +    }
> +    if (data->moref) {
> +        virBufferAddLit(buf, "<vmware:moref>");
> +        virBufferEscapeString(buf, "%s", data->moref);
> +        virBufferAddLit(buf, "</vmware:moref>\n");
> +    }
>  
>      return 0;
>  }
> @@ -1304,7 +1322,6 @@ virVMXParseConfig(virVMXContext *ctx,
>      bool hgfs_disabled = true;
>      long long sharedFolder_maxNum = 0;
>      int cpumasklen;
> -    char *namespaceData;
>  
>      if (ctx->parseFileName == NULL) {
>          virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> @@ -1802,12 +1819,26 @@ virVMXParseConfig(virVMXContext *ctx,
>      }
>  
>      /* ctx:datacenterPath -> def:namespaceData */
> -    if (ctx->datacenterPath) {
> -        if (VIR_STRDUP(namespaceData, ctx->datacenterPath) < 0)
> +    if (ctx->datacenterPath || ctx->moref) {
> +        struct virVMXDomainDefNamespaceData *nsdata;
> +
> +        if (VIR_ALLOC(nsdata) < 0)
>              goto cleanup;
> +        nsdata->datacenterPath = NULL;
> +        nsdata->moref = NULL;

This explicit set to NULL is not necessary. VIR_ALLOC uses calloc()
under the hood so the memory is zeroed out.

> +
> +        if (ctx->datacenterPath) {
> +            if (VIR_STRDUP(nsdata->datacenterPath, ctx->datacenterPath) < 0)

VIR_STRDUP() accepts NULL as source (in which case success is returned).
So this can be just:

if (VIR_STRDUP() < 0) ..

> +                goto cleanup;

Almost, @nsdata is leaked here. These lines can be then written as:

if (VIR_ALLOC(nsdata) < 0 ||
    VIR_STRDUP(nsdata->datacenterPath, ctx->datacenterPath) < 0 ||
    VIR_STRDUP(nsdata->moref, ctx->moref) < 0) {
    virVMXDomainDefNamespaceFree(nsdata);
    goto cleanup;
}


> +        }
> +
> +        if (ctx->moref) {
> +            if (VIR_STRDUP(nsdata->moref, ctx->moref) < 0)
> +                goto cleanup;
> +        }
>  
>          def->ns = *virDomainXMLOptionGetNamespace(xmlopt);
> -        def->namespaceData = namespaceData;
> +        def->namespaceData = nsdata;
>      }
>  
>      if (virDomainDefPostParse(def, caps, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,

Oh, not testcase? :(  I'll write one.

ACK with those small nits fixed.

Michal




More information about the libvir-list mailing list