[libvirt] [PATCH] esx: Support folders in the path of vpx:// connection URIs

Matthias Bolte matthias.bolte at googlemail.com
Tue Sep 6 20:03:21 UTC 2011


Allow the datacenter and compute resource parts of the path
to be prefixed with folders. Therefore, the way the path is
parsed has changed. Before, it was split in 2 or 3 items and
the items' meanings were determined by their positions. Now
the path can have 2 or more items and the the vCenter server
is asked whether a folder, datacenter of compute resource
with the specified name exists at the current hierarchy level.

Before the datacenter and compute resource lookup automatically
traversed folders during lookup. This is logic got removed
and folders have to be specified explicitly.

The proper datacenter path including folders is now used when
accessing a datastore over HTTPS. This makes virsh dumpxml
and define work for datacenters in folders.

https://bugzilla.redhat.com/show_bug.cgi?id=732676
---
 docs/drvesx.html.in            |   10 ++-
 src/esx/esx_driver.c           |   14 ++--
 src/esx/esx_util.c             |   19 +---
 src/esx/esx_util.h             |    1 +
 src/esx/esx_vi.c               |  223 ++++++++++++++++++++++++++++++++++------
 src/esx/esx_vi_generator.input |    4 +
 6 files changed, 215 insertions(+), 56 deletions(-)

diff --git a/docs/drvesx.html.in b/docs/drvesx.html.in
index da9d2a1..aa8ecd4 100644
--- a/docs/drvesx.html.in
+++ b/docs/drvesx.html.in
@@ -56,7 +56,7 @@ esx://example-esx.com/?no_verify=1     (ESX over HTTPS, but doesn't verify the s
         URIs have this general form (<code>[...]</code> marks an optional part).
     </p>
 <pre>
-type://[username@]hostname[:port]/[datacenter[/cluster]/server][?extraparameters]
+type://[username@]hostname[:port]/[[folder/...]datacenter/[folder/...][cluster/]server][?extraparameters]
 </pre>
     <p>
         The <code>type://</code> is either <code>esx://</code> or
@@ -80,6 +80,14 @@ type://[username@]hostname[:port]/[datacenter[/cluster]/server][?extraparameters
 <pre>
 vpx://example-vcenter.com/dc1/cluster1/example-esx.com
 </pre>
+    <p>
+        Datacenters and clusters can be organized in folders, those have to be
+        specified as well. The driver can handle folders
+        <span class="since">since 0.9.5</span>.
+    </p>
+<pre>
+vpx://example-vcenter.com/folder1/dc1/folder2/example-esx.com
+</pre>
 
 
     <h4><a name="extraparams">Extra parameters</a></h4>
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index f1102ea..fd83a9c 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -802,8 +802,7 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
     char *url = NULL;
 
     if (hostSystemIpAddress == NULL &&
-        (priv->parsedUri->path_datacenter == NULL ||
-         priv->parsedUri->path_computeResource == NULL)) {
+        (priv->parsedUri->path == NULL || STREQ(priv->parsedUri->path, "/"))) {
         ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                   _("Path has to specify the datacenter and compute resource"));
         return -1;
@@ -890,8 +889,8 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
 
 
 /*
- * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter> ...]
- *             <path> = <datacenter>/<computeresource>[/<hostsystem>]
+ * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter>...]
+ *             <path> = [<folder>/...]<datacenter>/[<folder>/...]<computeresource>[/<hostsystem>]
  *
  * If no port is specified the default port is set dependent on the scheme and
  * transport parameter:
@@ -905,7 +904,8 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
  * For a vpx:// connection <path> references a host managed by the vCenter.
  * In case the host is part of a cluster then <computeresource> is the cluster
  * name. Otherwise <computeresource> and <hostsystem> are equal and the later
- * can be omitted.
+ * can be omitted. As datacenters and computeresources can be organized in
+ * folders those have to be included in <path>.
  *
  * Optional query parameters:
  * - transport={http|https}
@@ -2744,7 +2744,7 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
                       domain->conn->uri->server, domain->conn->uri->port);
     virBufferURIEncodeString(&buffer, directoryAndFileName);
     virBufferAddLit(&buffer, "?dcPath=");
-    virBufferURIEncodeString(&buffer, priv->primary->datacenter->name);
+    virBufferURIEncodeString(&buffer, priv->parsedUri->path_datacenter);
     virBufferAddLit(&buffer, "&dsName=");
     virBufferURIEncodeString(&buffer, datastoreName);
 
@@ -3212,7 +3212,7 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
 
     virBufferURIEncodeString(&buffer, escapedName);
     virBufferAddLit(&buffer, ".vmx?dcPath=");
-    virBufferURIEncodeString(&buffer, priv->primary->datacenter->name);
+    virBufferURIEncodeString(&buffer, priv->parsedUri->path_datacenter);
     virBufferAddLit(&buffer, "&dsName=");
     virBufferURIEncodeString(&buffer, datastoreName);
 
diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c
index c14179d..5243a0e 100644
--- a/src/esx/esx_util.c
+++ b/src/esx/esx_util.c
@@ -51,7 +51,6 @@ esxUtil_ParseUri(esxUtil_ParsedUri **parsedUri, xmlURIPtr uri)
     int noVerify;
     int autoAnswer;
     char *tmp;
-    char *saveptr;
 
     if (parsedUri == NULL || *parsedUri != NULL) {
         ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
@@ -184,26 +183,13 @@ esxUtil_ParseUri(esxUtil_ParsedUri **parsedUri, xmlURIPtr uri)
         }
     }
 
-    /* Expected format: [/]<datacenter>/<computeresource>[/<hostsystem>] */
     if (uri->path != NULL) {
-        tmp = strdup(uri->path);
+        (*parsedUri)->path = strdup(uri->path);
 
-        if (tmp == NULL) {
+        if ((*parsedUri)->path == NULL) {
             virReportOOMError();
             goto cleanup;
         }
-
-        if (esxVI_String_DeepCopyValue(&(*parsedUri)->path_datacenter,
-                                       strtok_r(tmp, "/", &saveptr)) < 0 ||
-            esxVI_String_DeepCopyValue(&(*parsedUri)->path_computeResource,
-                                       strtok_r(NULL, "/", &saveptr)) < 0 ||
-            esxVI_String_DeepCopyValue(&(*parsedUri)->path_hostSystem,
-                                       strtok_r(NULL, "", &saveptr)) < 0) {
-            VIR_FREE(tmp);
-            goto cleanup;
-        }
-
-        VIR_FREE(tmp);
     }
 
     if ((*parsedUri)->transport == NULL) {
@@ -242,6 +228,7 @@ esxUtil_FreeParsedUri(esxUtil_ParsedUri **parsedUri)
     VIR_FREE((*parsedUri)->transport);
     VIR_FREE((*parsedUri)->vCenter);
     VIR_FREE((*parsedUri)->proxy_hostname);
+    VIR_FREE((*parsedUri)->path);
     VIR_FREE((*parsedUri)->path_datacenter);
     VIR_FREE((*parsedUri)->path_computeResource);
     VIR_FREE((*parsedUri)->path_hostSystem);
diff --git a/src/esx/esx_util.h b/src/esx/esx_util.h
index 39fdb6d..4d7dccb 100644
--- a/src/esx/esx_util.h
+++ b/src/esx/esx_util.h
@@ -37,6 +37,7 @@ struct _esxUtil_ParsedUri {
     int proxy_type;
     char *proxy_hostname;
     int proxy_port;
+    char *path;
     char *path_datacenter;
     char *path_computeResource;
     char *path_hostSystem;
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index f4033eb..6f4f9ee 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -770,55 +770,214 @@ int
 esxVI_Context_LookupObjectsByPath(esxVI_Context *ctx,
                                   esxUtil_ParsedUri *parsedUri)
 {
-    char *hostSystemName = NULL;
+    int result = -1;
+    char *path = NULL;
+    char *saveptr = NULL;
+    char *previousItem = NULL;
+    char *item = NULL;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    esxVI_ManagedObjectReference *root = NULL;
+    esxVI_Folder *folder = NULL;
+
+    path = strdup(parsedUri->path);
+
+    if (path == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
     /* Lookup Datacenter */
-    if (esxVI_LookupDatacenter(ctx, parsedUri->path_datacenter,
-                               ctx->service->rootFolder, NULL, &ctx->datacenter,
-                               esxVI_Occurrence_RequiredItem) < 0) {
-        return -1;
+    item = strtok_r(path, "/", &saveptr);
+
+    if (item == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INVALID_ARG,
+                     _("Path '%s' does not specify a datacenter"),
+                     parsedUri->path);
+        goto cleanup;
+    }
+
+    root = ctx->service->rootFolder;
+
+    while (ctx->datacenter == NULL && item != NULL) {
+        esxVI_Folder_Free(&folder);
+
+        /* Try to lookup item as a folder */
+        if (esxVI_LookupFolder(ctx, item, root, NULL, &folder,
+                               esxVI_Occurrence_OptionalItem) < 0) {
+            goto cleanup;
+        }
+
+        if (folder != NULL) {
+            /* It's a folder, use it as new lookup root */
+            if (root != ctx->service->rootFolder) {
+                esxVI_ManagedObjectReference_Free(&root);
+            }
+
+            root = folder->_reference;
+            folder->_reference = NULL;
+        } else {
+            /* Try to lookup item as a datacenter */
+            if (esxVI_LookupDatacenter(ctx, item, root, NULL, &ctx->datacenter,
+                                       esxVI_Occurrence_OptionalItem) < 0) {
+                goto cleanup;
+            }
+        }
+
+        /* Build path_datacenter */
+        if (virBufferUse(&buffer) > 0) {
+            virBufferAddChar(&buffer, '/');
+        }
+
+        virBufferAdd(&buffer, item, -1);
+
+        previousItem = item;
+        item = strtok_r(NULL, "/", &saveptr);
+    }
+
+    if (ctx->datacenter == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not find datacenter specified in '%s'"),
+                     parsedUri->path);
+        goto cleanup;
     }
 
+    if (virBufferError(&buffer)) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    parsedUri->path_datacenter = virBufferContentAndReset(&buffer);
+
     /* Lookup (Cluster)ComputeResource */
-    if (esxVI_LookupComputeResource(ctx, parsedUri->path_computeResource,
-                                    ctx->datacenter->hostFolder, NULL,
-                                    &ctx->computeResource,
-                                    esxVI_Occurrence_RequiredItem) < 0) {
-        return -1;
+    if (item == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INVALID_ARG,
+                     _("Path '%s' does not specify a compute resource"),
+                     parsedUri->path);
+        goto cleanup;
+    }
+
+    if (root != ctx->service->rootFolder) {
+        esxVI_ManagedObjectReference_Free(&root);
+    }
+
+    root = ctx->datacenter->hostFolder;
+
+    while (ctx->computeResource == NULL && item != NULL) {
+        esxVI_Folder_Free(&folder);
+
+        /* Try to lookup item as a folder */
+        if (esxVI_LookupFolder(ctx, item, root, NULL, &folder,
+                               esxVI_Occurrence_OptionalItem) < 0) {
+            goto cleanup;
+        }
+
+        if (folder != NULL) {
+            /* It's a folder, use it as new lookup root */
+            if (root != ctx->datacenter->hostFolder) {
+                esxVI_ManagedObjectReference_Free(&root);
+            }
+
+            root = folder->_reference;
+            folder->_reference = NULL;
+        } else {
+            /* Try to lookup item as a compute resource */
+            if (esxVI_LookupComputeResource(ctx, item, root, NULL,
+                                            &ctx->computeResource,
+                                            esxVI_Occurrence_OptionalItem) < 0) {
+                goto cleanup;
+            }
+        }
+
+        /* Build path_computeResource */
+        if (virBufferUse(&buffer) > 0) {
+            virBufferAddChar(&buffer, '/');
+        }
+
+        virBufferAdd(&buffer, item, -1);
+
+        previousItem = item;
+        item = strtok_r(NULL, "/", &saveptr);
+    }
+
+    if (ctx->computeResource == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not find compute resource specified in '%s'"),
+                     parsedUri->path);
+        goto cleanup;
     }
 
     if (ctx->computeResource->resourcePool == NULL) {
         ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                      _("Could not retrieve resource pool"));
-        return -1;
+        goto cleanup;
+    }
+
+    if (virBufferError(&buffer)) {
+        virReportOOMError();
+        goto cleanup;
     }
 
+    parsedUri->path_computeResource = virBufferContentAndReset(&buffer);
+
     /* Lookup HostSystem */
-    if (parsedUri->path_hostSystem == NULL &&
-        STREQ(ctx->computeResource->_reference->type,
+    if (STREQ(ctx->computeResource->_reference->type,
               "ClusterComputeResource")) {
-        ESX_VI_ERROR(VIR_ERR_INVALID_ARG, "%s",
-                     _("Path has to specify the host system"));
-        return -1;
+        if (item == NULL) {
+            ESX_VI_ERROR(VIR_ERR_INVALID_ARG,
+                         _("Path '%s' does not specify a host system"),
+                         parsedUri->path);
+            goto cleanup;
+        }
+
+        /* The path specified a cluster, it has to specify a host system too */
+        previousItem = item;
+        item = strtok_r(NULL, "/", &saveptr);
     }
 
-    if (parsedUri->path_hostSystem != NULL ||
-        (parsedUri->path_computeResource != NULL &&
-         parsedUri->path_hostSystem == NULL)) {
-        if (parsedUri->path_hostSystem != NULL) {
-            hostSystemName = parsedUri->path_hostSystem;
-        } else {
-            hostSystemName = parsedUri->path_computeResource;
-        }
+    if (item != NULL) {
+        ESX_VI_ERROR(VIR_ERR_INVALID_ARG,
+                     _("Path '%s' ends with an excess item"),
+                     parsedUri->path);
+        goto cleanup;
+    }
+
+    parsedUri->path_hostSystem = strdup(previousItem);
+
+    if (parsedUri->path_hostSystem == NULL) {
+        virReportOOMError();
+        goto cleanup;
     }
 
-    if (esxVI_LookupHostSystem(ctx, hostSystemName,
+    if (esxVI_LookupHostSystem(ctx, parsedUri->path_hostSystem,
                                ctx->computeResource->_reference, NULL,
                                &ctx->hostSystem,
-                               esxVI_Occurrence_RequiredItem) < 0) {
-        return -1;
+                               esxVI_Occurrence_OptionalItem) < 0) {
+        goto cleanup;
     }
 
-    return 0;
+    if (ctx->hostSystem == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not find host system specified in '%s'"),
+                     parsedUri->path);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        virBufferFreeAndReset(&buffer);
+    }
+
+    if (root != ctx->service->rootFolder &&
+        (ctx->datacenter == NULL || root != ctx->datacenter->hostFolder)) {
+        esxVI_ManagedObjectReference_Free(&root);
+    }
+
+    VIR_FREE(path);
+    esxVI_Folder_Free(&folder);
+
+    return result;
 }
 
 int
@@ -1469,8 +1628,7 @@ esxVI_BuildSelectSetCollection(esxVI_Context *ctx)
     /* Folder -> childEntity (ManagedEntity) */
     if (esxVI_BuildSelectSet(&ctx->selectSet_folderToChildEntity,
                              "folderToChildEntity",
-                             "Folder", "childEntity",
-                             "folderToChildEntity\0") < 0) {
+                             "Folder", "childEntity", NULL) < 0) {
         return -1;
     }
 
@@ -1667,9 +1825,10 @@ esxVI_LookupObjectContentByType(esxVI_Context *ctx,
     objectSpec->obj = root;
     objectSpec->skip = esxVI_Boolean_False;
 
-    if (STRNEQ(root->type, type)) {
+    if (STRNEQ(root->type, type) || STREQ(root->type, "Folder")) {
         if (STREQ(root->type, "Folder")) {
-            if (STREQ(type, "Datacenter") || STREQ(type, "ComputeResource") ||
+            if (STREQ(type, "Folder") || STREQ(type, "Datacenter") ||
+                STREQ(type, "ComputeResource") ||
                 STREQ(type, "ClusterComputeResource")) {
                 objectSpec->selectSet = ctx->selectSet_folderToChildEntity;
             } else {
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 361a6e7..1a67a8c 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -755,6 +755,10 @@ managed object Datacenter            extends ManagedEntity
 end
 
 
+managed object Folder                extends ManagedEntity
+end
+
+
 managed object HostSystem            extends ManagedEntity
     HostConfigManager                        configManager                  r
 end
-- 
1.7.4.1




More information about the libvir-list mailing list