---
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