From 635f01ae287fa2981f1db5f8b5c177e1585c320e Mon Sep 17 00:00:00 2001 From: Matthias Bolte Date: Sun, 29 Aug 2010 19:33:49 +0200 Subject: [PATCH] esx: Use the VirtualDisk UUID as storage volume key VirtualDisks are .vmdk file based. Other files in a datastore like .iso or .flp files don't have a UUID attached, fall back to the path as key for them. --- src/esx/esx_storage_driver.c | 190 +++++++++++++++++++++++++++++---- src/esx/esx_util.c | 19 ++++ src/esx/esx_util.h | 2 + src/esx/esx_vi.c | 53 +++++++++ src/esx/esx_vi.h | 4 + src/esx/esx_vi_generator.input | 7 ++ 6 files changed, 256 insertions(+), 19 deletions(-) diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index c7ce9b494c..76f87691b5 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -697,7 +697,7 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name) virStorageVolPtr volume = NULL; esxPrivate *priv = pool->conn->storagePrivateData; char *datastorePath = NULL; - esxVI_FileInfo *fileInfo = NULL; + char *key = NULL; if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; @@ -708,17 +708,16 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name) goto cleanup; } - if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath, - false, &fileInfo, - esxVI_Occurrence_RequiredItem) < 0) { + if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, + datastorePath, &key) < 0) { goto cleanup; } - volume = virGetStorageVol(pool->conn, pool->name, name, datastorePath); + volume = virGetStorageVol(pool->conn, pool->name, name, key); cleanup: VIR_FREE(datastorePath); - esxVI_FileInfo_Free(&fileInfo); + VIR_FREE(key); return volume; } @@ -726,36 +725,170 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name) static virStorageVolPtr -esxStorageVolumeLookupByKeyOrPath(virConnectPtr conn, const char *keyOrPath) +esxStorageVolumeLookupByPath(virConnectPtr conn, const char *path) { virStorageVolPtr volume = NULL; esxPrivate *priv = conn->storagePrivateData; char *datastoreName = NULL; char *directoryAndFileName = NULL; - esxVI_FileInfo *fileInfo = NULL; + char *key = NULL; if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (esxUtil_ParseDatastorePath(keyOrPath, &datastoreName, NULL, + if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL, &directoryAndFileName) < 0) { goto cleanup; } - if (esxVI_LookupFileInfoByDatastorePath(priv->primary, keyOrPath, - false, &fileInfo, - esxVI_Occurrence_RequiredItem) < 0) { + if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path, + &key) < 0) { goto cleanup; } - volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, - keyOrPath); + volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key); cleanup: VIR_FREE(datastoreName); VIR_FREE(directoryAndFileName); - esxVI_FileInfo_Free(&fileInfo); + VIR_FREE(key); + + return volume; +} + + + +static virStorageVolPtr +esxStorageVolumeLookupByKey(virConnectPtr conn, const char *key) +{ + virStorageVolPtr volume = NULL; + esxPrivate *priv = conn->storagePrivateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *datastoreList = NULL; + esxVI_ObjectContent *datastore = NULL; + char *datastoreName = NULL; + esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL; + esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL; + char *directoryAndFileName = NULL; + size_t length; + char *datastorePath = NULL; + char *volumeName = NULL; + esxVI_FileInfo *fileInfo = NULL; + char *uuid_string = NULL; + char key_candidate[VIR_UUID_STRING_BUFLEN] = ""; + + if (STRPREFIX(key, "[")) { + /* Key is probably a datastore path */ + return esxStorageVolumeLookupByPath(conn, key); + } + + if (esxVI_EnsureSession(priv->primary) < 0) { + return NULL; + } + + /* Lookup all datastores */ + if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 || + esxVI_LookupDatastoreList(priv->primary, propertyNameList, + &datastoreList) < 0) { + goto cleanup; + } + + for (datastore = datastoreList; datastore != NULL; + datastore = datastore->_next) { + datastoreName = NULL; + + if (esxVI_GetStringValue(datastore, "summary.name", &datastoreName, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + /* Lookup datastore content */ + esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList); + + if (esxVI_LookupDatastoreContentByDatastoreName + (priv->primary, datastoreName, &searchResultsList) < 0) { + goto cleanup; + } + + /* Interpret search result */ + for (searchResults = searchResultsList; searchResults != NULL; + searchResults = searchResults->_next) { + VIR_FREE(directoryAndFileName); + + if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL, + NULL, &directoryAndFileName) < 0) { + goto cleanup; + } + + /* Strip trailing separators */ + length = strlen(directoryAndFileName); + + while (length > 0 && directoryAndFileName[length - 1] == '/') { + directoryAndFileName[length - 1] = '\0'; + --length; + } + + /* Build datastore path and query the UUID */ + for (fileInfo = searchResults->file; fileInfo != NULL; + fileInfo = fileInfo->_next) { + VIR_FREE(datastorePath); + + if (length < 1) { + if (virAsprintf(&volumeName, "%s", + fileInfo->path) < 0) { + virReportOOMError(); + goto cleanup; + } + } else if (virAsprintf(&volumeName, "%s/%s", + directoryAndFileName, + fileInfo->path) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&datastorePath, "[%s] %s", datastoreName, + volumeName) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (esxVI_VmDiskFileInfo_DynamicCast(fileInfo) == NULL) { + /* Only a VirtualDisk has a UUID */ + continue; + } + + VIR_FREE(uuid_string); + + if (esxVI_QueryVirtualDiskUuid + (priv->primary, datastorePath, + priv->primary->datacenter->_reference, + &uuid_string) < 0) { + goto cleanup; + } + + if (esxUtil_ReformatUuid(uuid_string, key_candidate) < 0) { + goto cleanup; + } + + if (STREQ(key, key_candidate)) { + /* Found matching UUID */ + volume = virGetStorageVol(conn, datastoreName, + volumeName, key); + goto cleanup; + } + } + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datastoreList); + esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList); + VIR_FREE(directoryAndFileName); + VIR_FREE(datastorePath); + VIR_FREE(volumeName); + VIR_FREE(uuid_string); return volume; } @@ -782,6 +915,8 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc, esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL; esxVI_ManagedObjectReference *task = NULL; esxVI_TaskInfoState taskInfoState; + char *uuid_string = NULL; + char key[VIR_UUID_STRING_BUFLEN] = ""; virCheckFlags(0, NULL); @@ -932,6 +1067,16 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc, ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create volume")); goto cleanup; } + + if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath, + priv->primary->datacenter->_reference, + &uuid_string) < 0) { + goto cleanup; + } + + if (esxUtil_ReformatUuid(uuid_string, key) < 0) { + goto cleanup; + } } else { ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Creation of %s volumes is not supported"), @@ -939,7 +1084,7 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc, goto cleanup; } - volume = virGetStorageVol(pool->conn, pool->name, def->name, datastorePath); + volume = virGetStorageVol(pool->conn, pool->name, def->name, key); cleanup: if (virtualDiskSpec != NULL) { @@ -957,6 +1102,7 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc, esxVI_FileInfo_Free(&fileInfo); esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec); esxVI_ManagedObjectReference_Free(&task); + VIR_FREE(uuid_string); return volume; } @@ -1087,7 +1233,12 @@ esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags) floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo); def.name = volume->name; - def.key = datastorePath; + + if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath, + &def.key) < 0) { + goto cleanup; + } + def.type = VIR_STORAGE_VOL_FILE; def.target.path = datastorePath; @@ -1120,6 +1271,7 @@ esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags) esxVI_DatastoreInfo_Free(&datastoreInfo); VIR_FREE(datastorePath); esxVI_FileInfo_Free(&fileInfo); + VIR_FREE(def.key); return xml; } @@ -1186,8 +1338,8 @@ static virStorageDriver esxStorageDriver = { esxStoragePoolNumberOfStorageVolumes, /* poolNumOfVolumes */ esxStoragePoolListStorageVolumes, /* poolListVolumes */ esxStorageVolumeLookupByName, /* volLookupByName */ - esxStorageVolumeLookupByKeyOrPath, /* volLookupByKey */ - esxStorageVolumeLookupByKeyOrPath, /* volLookupByPath */ + esxStorageVolumeLookupByKey, /* volLookupByKey */ + esxStorageVolumeLookupByPath, /* volLookupByPath */ esxStorageVolumeCreateXML, /* volCreateXML */ NULL, /* volCreateXMLFrom */ NULL, /* volDelete */ diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index 08c6c46235..99cc4f6b53 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -602,3 +602,22 @@ esxUtil_GetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_, return 0; } + + + +int +esxUtil_ReformatUuid(const char *input, char *output) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + + if (virUUIDParse(input, uuid) < 0) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Could not parse UUID from string '%s'"), + input); + return -1; + } + + virUUIDFormat(uuid, output); + + return 0; +} diff --git a/src/esx/esx_util.h b/src/esx/esx_util.h index 4d92333616..650f14536b 100644 --- a/src/esx/esx_util.h +++ b/src/esx/esx_util.h @@ -69,4 +69,6 @@ int esxUtil_GetConfigLong(virConfPtr conf, const char *name, long long *number, int esxUtil_GetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_, bool default_, bool optional); +int esxUtil_ReformatUuid(const char *input, char *output); + #endif /* __ESX_UTIL_H__ */ diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 6b6175554b..00e15f0a05 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -3253,6 +3253,59 @@ esxVI_LookupDatastoreContentByDatastoreName +int +esxVI_LookupStorageVolumeKeyByDatastorePath(esxVI_Context *ctx, + const char *datastorePath, + char **key) +{ + int result = -1; + esxVI_FileInfo *fileInfo = NULL; + char *uuid_string = NULL; + + if (key == NULL || *key != NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + return -1; + } + + if (esxVI_LookupFileInfoByDatastorePath(ctx, datastorePath, false, &fileInfo, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + if (esxVI_VmDiskFileInfo_DynamicCast(fileInfo) != NULL) { + /* VirtualDisks have a UUID, use it as key */ + if (esxVI_QueryVirtualDiskUuid(ctx, datastorePath, + ctx->datacenter->_reference, + &uuid_string) < 0) { + goto cleanup; + } + + if (VIR_ALLOC_N(*key, VIR_UUID_STRING_BUFLEN) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (esxUtil_ReformatUuid(uuid_string, *key) < 0) { + goto cleanup; + } + } else { + /* Other files don't have a UUID, fall back to the path as key */ + if (esxVI_String_DeepCopyValue(key, datastorePath) < 0) { + goto cleanup; + } + } + + result = 0; + + cleanup: + esxVI_FileInfo_Free(&fileInfo); + VIR_FREE(uuid_string); + + return result; +} + + + int esxVI_HandleVirtualMachineQuestion (esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine, diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index 773a1c69f6..bd37b058e8 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -409,6 +409,10 @@ int esxVI_LookupDatastoreContentByDatastoreName (esxVI_Context *ctx, const char *datastoreName, esxVI_HostDatastoreBrowserSearchResults **searchResultsList); +int esxVI_LookupStorageVolumeKeyByDatastorePath(esxVI_Context *ctx, + const char *datastorePath, + char **key); + int esxVI_HandleVirtualMachineQuestion (esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine, diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input index b911c22b6d..2ee513a2f1 100644 --- a/src/esx/esx_vi_generator.input +++ b/src/esx/esx_vi_generator.input @@ -801,6 +801,13 @@ method QueryPerfCounter returns PerfCounterInfo ol end +method QueryVirtualDiskUuid returns String r + ManagedObjectReference _this:VirtualDiskManager r + String name r + ManagedObjectReference datacenter o +end + + method RebootGuest ManagedObjectReference _this r end