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

Richard W.M. Jones posted 1 patch 6 years, 7 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20170825140439.2183-1-rjones@redhat.com
There is a newer version of this series
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(-)
[libvirt] [PATCH] vmx: Expose VMware Managed Object Reference (moref) in XML.
Posted by Richard W.M. Jones 6 years, 7 months ago
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;
+        }
+    }
+    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;
+
+        if (ctx->datacenterPath) {
+            if (VIR_STRDUP(nsdata->datacenterPath, ctx->datacenterPath) < 0)
+                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,
diff --git a/src/vmx/vmx.h b/src/vmx/vmx.h
index 08b627765..6b3d880d6 100644
--- a/src/vmx/vmx.h
+++ b/src/vmx/vmx.h
@@ -45,6 +45,7 @@ typedef int (*virVMXAutodetectSCSIControllerModel)(virDomainDiskDefPtr def,
  * formatFileName is only used by virVMXFormatConfig.
  * autodetectSCSIControllerModel is optionally used by virVMXFormatConfig.
  * datacenterPath is only used by virVMXFormatConfig.
+ * moref is only used by virVMXFormatConfig.
  */
 struct _virVMXContext {
     void *opaque;
@@ -52,6 +53,7 @@ struct _virVMXContext {
     virVMXFormatFileName formatFileName;
     virVMXAutodetectSCSIControllerModel autodetectSCSIControllerModel;
     const char *datacenterPath; /* including folders */
+    const char *moref;
 };
 
 
-- 
2.13.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] vmx: Expose VMware Managed Object Reference (moref) in XML.
Posted by Michal Privoznik 6 years, 7 months ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list