diff --git a/docs/drvesx.html.in b/docs/drvesx.html.in index da9d2a1ba711051b7a79aebca44ab1628edcd60d..7d323b352169cb0f3a78687784e0e55f93524161 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 ([...] marks an optional part).

-type://[username@]hostname[:port]/[datacenter[/cluster]/server][?extraparameters]
+type://[username@]hostname[:port]/[[folder/...]datacenter/[folder/...][cluster/]server][?extraparameters]
 

The type:// is either esx:// or @@ -79,6 +79,14 @@ type://[username@]hostname[:port]/[datacenter[/cluster]/server][?extraparameters

 vpx://example-vcenter.com/dc1/cluster1/example-esx.com
+
+

+ Datacenters and clusters can be organized in folders, those have to be + specified as well. The driver can handle folders + since 0.9.7. +

+
+vpx://example-vcenter.com/folder1/dc1/folder2/example-esx.com
 
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 5d0b6dbd51e04aa0ba62648e3d40bb6441e2e701..dfeef8533239a53f3297b8f6a1b43f7916dfbe96 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -722,7 +722,7 @@ esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth, if (esxVI_Context_Alloc(&priv->host) < 0 || esxVI_Context_Connect(priv->host, url, ipAddress, username, password, priv->parsedUri) < 0 || - esxVI_Context_LookupObjectsByPath(priv->host, priv->parsedUri) < 0) { + esxVI_Context_LookupManagedObjects(priv->host) < 0) { goto cleanup; } @@ -804,8 +804,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; @@ -869,13 +868,13 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth, } if (hostSystemIpAddress != NULL) { - if (esxVI_Context_LookupObjectsByHostSystemIp(priv->vCenter, - hostSystemIpAddress) < 0) { + if (esxVI_Context_LookupManagedObjectsByHostSystemIp + (priv->vCenter, hostSystemIpAddress) < 0) { goto cleanup; } } else { - if (esxVI_Context_LookupObjectsByPath(priv->vCenter, - priv->parsedUri) < 0) { + if (esxVI_Context_LookupManagedObjectsByPath(priv->vCenter, + priv->parsedUri->path) < 0) { goto cleanup; } } @@ -894,8 +893,8 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth, /* - * URI format: {vpx|esx|gsx}://[@][:]/[][? ...] - * = /[/] + * URI format: {vpx|esx|gsx}://[@][:]/[][?...] + * = [/...]/[/...][/] * * If no port is specified the default port is set dependent on the scheme and * transport parameter: @@ -909,7 +908,8 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth, * For a vpx:// connection references a host managed by the vCenter. * In case the host is part of a cluster then is the cluster * name. Otherwise and 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 . * * Optional query parameters: * - transport={http|https} @@ -977,6 +977,12 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, return VIR_DRV_OPEN_ERROR; } + if (STRCASENEQ(conn->uri->scheme, "vpx") && + conn->uri->path != NULL && STRNEQ(conn->uri->path, "/")) { + VIR_WARN("Ignoring unexpected path '%s' for non-vpx scheme '%s'", + conn->uri->path, conn->uri->scheme); + } + /* Require server part */ if (conn->uri->server == NULL) { ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", @@ -2769,7 +2775,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->primary->datacenterPath); virBufferAddLit(&buffer, "&dsName="); virBufferURIEncodeString(&buffer, datastoreName); @@ -3237,7 +3243,7 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml) virBufferURIEncodeString(&buffer, escapedName); virBufferAddLit(&buffer, ".vmx?dcPath="); - virBufferURIEncodeString(&buffer, priv->primary->datacenter->name); + virBufferURIEncodeString(&buffer, priv->primary->datacenterPath); virBufferAddLit(&buffer, "&dsName="); virBufferURIEncodeString(&buffer, datastoreName); diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index c14179d7f1971fee9aa05a28fbe10e79a98df7e4..1925802f490ae551ad2d8270f21cdf3e10daa063 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: [/]/[/] */ 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,9 +228,7 @@ esxUtil_FreeParsedUri(esxUtil_ParsedUri **parsedUri) VIR_FREE((*parsedUri)->transport); VIR_FREE((*parsedUri)->vCenter); VIR_FREE((*parsedUri)->proxy_hostname); - VIR_FREE((*parsedUri)->path_datacenter); - VIR_FREE((*parsedUri)->path_computeResource); - VIR_FREE((*parsedUri)->path_hostSystem); + VIR_FREE((*parsedUri)->path); VIR_FREE(*parsedUri); } diff --git a/src/esx/esx_util.h b/src/esx/esx_util.h index 39fdb6db415f4e8ff07a435c299988cd85088912..8d172e10a709c4ede2e28150148936e12440ccf4 100644 --- a/src/esx/esx_util.h +++ b/src/esx/esx_util.h @@ -37,9 +37,7 @@ struct _esxUtil_ParsedUri { int proxy_type; char *proxy_hostname; int proxy_port; - char *path_datacenter; - char *path_computeResource; - char *path_hostSystem; + char *path; }; int esxUtil_ParseUri(esxUtil_ParsedUri **parsedUri, xmlURIPtr uri); diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 86e5739a34080bc17982a915723a5b754bf324be..21892a0119225bae1dd7963f6a863a10911952de 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -616,8 +616,11 @@ ESX_VI__TEMPLATE__FREE(Context, esxVI_UserSession_Free(&item->session); VIR_FREE(item->sessionLock); esxVI_Datacenter_Free(&item->datacenter); + VIR_FREE(item->datacenterPath); esxVI_ComputeResource_Free(&item->computeResource); + VIR_FREE(item->computeResourcePath); esxVI_HostSystem_Free(&item->hostSystem); + VIR_FREE(item->hostSystemName); esxVI_SelectionSpec_Free(&item->selectSet_folderToChildEntity); esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToParent); esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToVm); @@ -789,21 +792,25 @@ esxVI_Context_Connect(esxVI_Context *ctx, const char *url, } int -esxVI_Context_LookupObjectsByPath(esxVI_Context *ctx, - esxUtil_ParsedUri *parsedUri) +esxVI_Context_LookupManagedObjects(esxVI_Context *ctx) { - char *hostSystemName = NULL; /* Lookup Datacenter */ - if (esxVI_LookupDatacenter(ctx, parsedUri->path_datacenter, - ctx->service->rootFolder, NULL, &ctx->datacenter, + if (esxVI_LookupDatacenter(ctx, NULL, ctx->service->rootFolder, NULL, + &ctx->datacenter, esxVI_Occurrence_RequiredItem) < 0) { return -1; } + ctx->datacenterPath = strdup(ctx->datacenter->name); + + if (ctx->datacenterPath == NULL) { + virReportOOMError(); + return -1; + } + /* Lookup (Cluster)ComputeResource */ - if (esxVI_LookupComputeResource(ctx, parsedUri->path_computeResource, - ctx->datacenter->hostFolder, NULL, - &ctx->computeResource, + if (esxVI_LookupComputeResource(ctx, NULL, ctx->datacenter->hostFolder, + NULL, &ctx->computeResource, esxVI_Occurrence_RequiredItem) < 0) { return -1; } @@ -814,38 +821,240 @@ esxVI_Context_LookupObjectsByPath(esxVI_Context *ctx, return -1; } + ctx->computeResourcePath = strdup(ctx->computeResource->name); + + if (ctx->computeResourcePath == NULL) { + virReportOOMError(); + return -1; + } + /* Lookup HostSystem */ - if (parsedUri->path_hostSystem == NULL && - STREQ(ctx->computeResource->_reference->type, - "ClusterComputeResource")) { - ESX_VI_ERROR(VIR_ERR_INVALID_ARG, "%s", - _("Path has to specify the host system")); + if (esxVI_LookupHostSystem(ctx, NULL, ctx->computeResource->_reference, + NULL, &ctx->hostSystem, + esxVI_Occurrence_RequiredItem) < 0) { return -1; } - if (parsedUri->path_hostSystem != NULL || - (parsedUri->path_computeResource != NULL && - parsedUri->path_hostSystem == NULL)) { - if (parsedUri->path_hostSystem != NULL) { - hostSystemName = parsedUri->path_hostSystem; + ctx->hostSystemName = strdup(ctx->hostSystem->name); + + if (ctx->hostSystemName == NULL) { + virReportOOMError(); + return -1; + } + + return 0; +} + +int +esxVI_Context_LookupManagedObjectsByPath(esxVI_Context *ctx, const char *path) +{ + int result = -1; + char *tmp = NULL; + char *saveptr = NULL; + char *previousItem = NULL; + char *item = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + esxVI_ManagedObjectReference *root = NULL; + esxVI_Folder *folder = NULL; + + tmp = strdup(path); + + if (tmp == NULL) { + virReportOOMError(); + goto cleanup; + } + + /* Lookup Datacenter */ + item = strtok_r(tmp, "/", &saveptr); + + if (item == NULL) { + ESX_VI_ERROR(VIR_ERR_INVALID_ARG, + _("Path '%s' does not specify a datacenter"), 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 datacenter path */ + 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'"), path); + goto cleanup; + } + + if (virBufferError(&buffer)) { + virReportOOMError(); + goto cleanup; + } + + ctx->datacenterPath = virBufferContentAndReset(&buffer); + + /* Lookup (Cluster)ComputeResource */ + if (item == NULL) { + ESX_VI_ERROR(VIR_ERR_INVALID_ARG, + _("Path '%s' does not specify a compute resource"), 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 { - hostSystemName = parsedUri->path_computeResource; + /* Try to lookup item as a compute resource */ + if (esxVI_LookupComputeResource(ctx, item, root, NULL, + &ctx->computeResource, + esxVI_Occurrence_OptionalItem) < 0) { + goto cleanup; + } + } + + /* Build compute resource path */ + 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'"), + path); + goto cleanup; + } + + if (ctx->computeResource->resourcePool == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve resource pool")); + goto cleanup; + } + + if (virBufferError(&buffer)) { + virReportOOMError(); + goto cleanup; + } + + ctx->computeResourcePath = virBufferContentAndReset(&buffer); + + /* Lookup HostSystem */ + if (STREQ(ctx->computeResource->_reference->type, + "ClusterComputeResource")) { + if (item == NULL) { + ESX_VI_ERROR(VIR_ERR_INVALID_ARG, + _("Path '%s' does not specify a host system"), path); + goto cleanup; } + + /* The path specified a cluster, it has to specify a host system too */ + previousItem = item; + item = strtok_r(NULL, "/", &saveptr); + } + + if (item != NULL) { + ESX_VI_ERROR(VIR_ERR_INVALID_ARG, + _("Path '%s' ends with an excess item"), path); + goto cleanup; } - if (esxVI_LookupHostSystem(ctx, hostSystemName, + ctx->hostSystemName = strdup(previousItem); + + if (ctx->hostSystemName == NULL) { + virReportOOMError(); + goto cleanup; + } + + if (esxVI_LookupHostSystem(ctx, ctx->hostSystemName, 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'"), 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(tmp); + esxVI_Folder_Free(&folder); + + return result; } int -esxVI_Context_LookupObjectsByHostSystemIp(esxVI_Context *ctx, - const char *hostSystemIpAddress) +esxVI_Context_LookupManagedObjectsByHostSystemIp(esxVI_Context *ctx, + const char *hostSystemIpAddress) { int result = -1; esxVI_ManagedObjectReference *managedObjectReference = NULL; @@ -1491,8 +1700,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; } @@ -1689,9 +1897,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.h b/src/esx/esx_vi.h index 0b3f889b5ec81e668c010b10584445a230c8752f..78d3986096471547d8ebab57d7b38b1d5af4ef7a 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -204,8 +204,11 @@ struct _esxVI_Context { esxVI_UserSession *session; /* ... except the session ... */ virMutexPtr sessionLock; /* ... that is protected by this mutex */ esxVI_Datacenter *datacenter; + char *datacenterPath; /* including folders */ esxVI_ComputeResource *computeResource; + char *computeResourcePath; /* including folders */ esxVI_HostSystem *hostSystem; + char *hostSystemName; esxVI_SelectionSpec *selectSet_folderToChildEntity; esxVI_SelectionSpec *selectSet_hostSystemToParent; esxVI_SelectionSpec *selectSet_hostSystemToVm; @@ -221,10 +224,10 @@ void esxVI_Context_Free(esxVI_Context **ctx); int esxVI_Context_Connect(esxVI_Context *ctx, const char *ipAddress, const char *url, const char *username, const char *password, esxUtil_ParsedUri *parsedUri); -int esxVI_Context_LookupObjectsByPath(esxVI_Context *ctx, - esxUtil_ParsedUri *parsedUri); -int esxVI_Context_LookupObjectsByHostSystemIp(esxVI_Context *ctx, - const char *hostSystemIpAddress); +int esxVI_Context_LookupManagedObjects(esxVI_Context *ctx); +int esxVI_Context_LookupManagedObjectsByPath(esxVI_Context *ctx, const char *path); +int esxVI_Context_LookupManagedObjectsByHostSystemIp(esxVI_Context *ctx, + const char *hostSystemIpAddress); int esxVI_Context_Execute(esxVI_Context *ctx, const char *methodName, const char *request, esxVI_Response **response, esxVI_Occurrence occurrence); diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input index 361a6e70458163057b5272787d650a48c8105af1..1a67a8cadb3a10d291a18b2e9683922356b9ce8f 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