[libvirt] [PATCH] esx: Add support for storage volume cloning

Matthias Bolte matthias.bolte at googlemail.com
Mon Dec 6 20:42:52 UTC 2010


---
 src/esx/esx_storage_driver.c   |  198 +++++++++++++++++++++++++++++++++++++++-
 src/esx/esx_vi_generator.input |   11 ++
 2 files changed, 208 insertions(+), 1 deletions(-)

diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 9165f7a..e6803c2 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -1180,6 +1180,202 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
 
 
 
+static virStorageVolPtr
+esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
+                              virStorageVolPtr sourceVolume, unsigned int flags)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    virStoragePoolDef poolDef;
+    char *sourceDatastorePath = NULL;
+    virStorageVolDefPtr def = NULL;
+    char *tmp;
+    char *unescapedDatastorePath = NULL;
+    char *unescapedDirectoryName = NULL;
+    char *unescapedDirectoryAndFileName = NULL;
+    char *directoryName = NULL;
+    char *fileName = NULL;
+    char *datastorePathWithoutFileName = NULL;
+    char *datastorePath = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+    char *taskInfoErrorMessage = NULL;
+    char *uuid_string = NULL;
+    char *key = NULL;
+
+    virCheckFlags(0, NULL);
+
+    memset(&poolDef, 0, sizeof (poolDef));
+
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        return NULL;
+    }
+
+    if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) {
+        return NULL;
+    }
+
+    if (virAsprintf(&sourceDatastorePath, "[%s] %s", sourceVolume->pool,
+                    sourceVolume->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* Parse config */
+    def = virStorageVolDefParseString(&poolDef, xmldesc);
+
+    if (def == NULL) {
+        goto cleanup;
+    }
+
+    if (def->type != VIR_STORAGE_VOL_FILE) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Creating non-file volumes is not supported"));
+        goto cleanup;
+    }
+
+    /* Validate config */
+    tmp = strrchr(def->name, '/');
+
+    if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Volume name '%s' doesn't have expected format "
+                    "'<directory>/<file>'"), def->name);
+        goto cleanup;
+    }
+
+    if (! virFileHasSuffix(def->name, ".vmdk")) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
+                  def->name);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
+                    def->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
+        /* Parse and escape datastore path */
+        if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
+                                       &unescapedDirectoryName,
+                                       &unescapedDirectoryAndFileName) < 0) {
+            goto cleanup;
+        }
+
+        directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
+
+        if (directoryName == NULL) {
+            goto cleanup;
+        }
+
+        fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
+                                               strlen(unescapedDirectoryName) + 1);
+
+        if (fileName == NULL) {
+            goto cleanup;
+        }
+
+        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
+                        directoryName) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
+                        fileName) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        /* Create directory, if it doesn't exist yet */
+        if (esxVI_LookupFileInfoByDatastorePath
+              (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
+               esxVI_Occurrence_OptionalItem) < 0) {
+            goto cleanup;
+        }
+
+        if (fileInfo == NULL) {
+            if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
+                                    priv->primary->datacenter->_reference,
+                                    esxVI_Boolean_True) < 0) {
+                goto cleanup;
+            }
+        }
+
+        /* Copy VirtualDisk */
+        if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath,
+                                       priv->primary->datacenter->_reference,
+                                       datastorePath,
+                                       priv->primary->datacenter->_reference,
+                                       NULL, esxVI_Boolean_False, &task) < 0 ||
+            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+                                        esxVI_Occurrence_None,
+                                        priv->autoAnswer, &taskInfoState,
+                                        &taskInfoErrorMessage) < 0) {
+            goto cleanup;
+        }
+
+        if (taskInfoState != esxVI_TaskInfoState_Success) {
+            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"),
+                      taskInfoErrorMessage);
+            goto cleanup;
+        }
+
+        if (priv->primary->hasQueryVirtualDiskUuid) {
+            if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
+                virReportOOMError();
+                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 {
+            /* Fall back to the path as key */
+            if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
+                goto cleanup;
+            }
+        }
+    } else {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Creation of %s volumes is not supported"),
+                  virStorageFileFormatTypeToString(def->target.format));
+        goto cleanup;
+    }
+
+    volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+
+  cleanup:
+    VIR_FREE(sourceDatastorePath);
+    virStorageVolDefFree(def);
+    VIR_FREE(unescapedDatastorePath);
+    VIR_FREE(unescapedDirectoryName);
+    VIR_FREE(unescapedDirectoryAndFileName);
+    VIR_FREE(directoryName);
+    VIR_FREE(fileName);
+    VIR_FREE(datastorePathWithoutFileName);
+    VIR_FREE(datastorePath);
+    esxVI_FileInfo_Free(&fileInfo);
+    esxVI_ManagedObjectReference_Free(&task);
+    VIR_FREE(taskInfoErrorMessage);
+    VIR_FREE(uuid_string);
+    VIR_FREE(key);
+
+    return volume;
+}
+
+
+
 static int
 esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
 {
@@ -1377,7 +1573,7 @@ static virStorageDriver esxStorageDriver = {
     esxStorageVolumeLookupByKey,           /* volLookupByKey */
     esxStorageVolumeLookupByPath,          /* volLookupByPath */
     esxStorageVolumeCreateXML,             /* volCreateXML */
-    NULL,                                  /* volCreateXMLFrom */
+    esxStorageVolumeCreateXMLFrom,         /* volCreateXMLFrom */
     NULL,                                  /* volDelete */
     NULL,                                  /* volWipe */
     esxStorageVolumeGetInfo,               /* volGetInfo */
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 991ce8a..4018c6e 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -700,6 +700,17 @@ method CancelTask
 end
 
 
+method CopyVirtualDisk_Task returns ManagedObjectReference r
+    ManagedObjectReference                   _this:VirtualDiskManager       r
+    String                                   sourceName                     r
+    ManagedObjectReference                   sourceDatacenter               o
+    String                                   destName                       r
+    ManagedObjectReference                   destDatacenter                 o
+    VirtualDiskSpec                          destSpec                       o
+    Boolean                                  force                          o
+end
+
+
 method CreateFilter returns ManagedObjectReference r
     ManagedObjectReference                   _this:PropertyCollector        r
     PropertyFilterSpec                       spec                           r
-- 
1.7.0.4




More information about the libvir-list mailing list