[libvirt] [PATCH] esx: Use the VirtualDisk UUID as storage volume key

Matthias Bolte matthias.bolte at googlemail.com
Sun Aug 29 23:00:38 UTC 2010


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 3b959c2..a9a5633 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;
 }
@@ -783,6 +916,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);
 
@@ -935,6 +1070,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"),
@@ -942,7 +1087,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) {
@@ -960,6 +1105,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;
 }
@@ -1090,7 +1236,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;
 
@@ -1123,6 +1274,7 @@ esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags)
     esxVI_DatastoreInfo_Free(&datastoreInfo);
     VIR_FREE(datastorePath);
     esxVI_FileInfo_Free(&fileInfo);
+    VIR_FREE(def.key);
 
     return xml;
 }
@@ -1189,8 +1341,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 08c6c46..99cc4f6 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 4d92333..650f145 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 8d83eac..fb2a499 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -3254,6 +3254,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,
    esxVI_VirtualMachineQuestionInfo *questionInfo,
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 773a1c6..bd37b05 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 b911c22..2ee513a 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
-- 
1.7.0.4




More information about the libvir-list mailing list