[libvirt] [PATCH] esx: Add .vmdk storage volume creation

Matthias Bolte matthias.bolte at googlemail.com
Sat Aug 28 19:53:11 UTC 2010


---
 src/esx/esx_driver.c           |    3 +-
 src/esx/esx_storage_driver.c   |  215 +++++++++++++++++++++++++++++++++++++++-
 src/esx/esx_vi.c               |   57 +++++++-----
 src/esx/esx_vi.h               |    1 +
 src/esx/esx_vi_generator.input |   32 ++++++
 src/esx/esx_vi_generator.py    |    7 +-
 src/esx/esx_vi_methods.c       |   12 +++
 7 files changed, 296 insertions(+), 31 deletions(-)

diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index eda3fc2..f8d4771 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -353,7 +353,8 @@ esxAutodetectSCSIControllerModel(virDomainDiskDefPtr def, int *model,
         return 0;
     }
 
-    if (esxVI_LookupFileInfoByDatastorePath(data->ctx, def->src, &fileInfo,
+    if (esxVI_LookupFileInfoByDatastorePath(data->ctx, def->src,
+                                            false, &fileInfo,
                                             esxVI_Occurrence_RequiredItem) < 0) {
         goto cleanup;
     }
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index d2d8f22..3b959c2 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -709,7 +709,7 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name)
     }
 
     if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
-                                            &fileInfo,
+                                            false, &fileInfo,
                                             esxVI_Occurrence_RequiredItem) < 0) {
         goto cleanup;
     }
@@ -743,7 +743,8 @@ esxStorageVolumeLookupByKeyOrPath(virConnectPtr conn, const char *keyOrPath)
         goto cleanup;
     }
 
-    if (esxVI_LookupFileInfoByDatastorePath(priv->primary, keyOrPath, &fileInfo,
+    if (esxVI_LookupFileInfoByDatastorePath(priv->primary, keyOrPath,
+                                            false, &fileInfo,
                                             esxVI_Occurrence_RequiredItem) < 0) {
         goto cleanup;
     }
@@ -761,6 +762,210 @@ esxStorageVolumeLookupByKeyOrPath(virConnectPtr conn, const char *keyOrPath)
 
 
 
+static virStorageVolPtr
+esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
+                          unsigned int flags)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_DatastoreInfo *datastoreInfo = NULL;
+    virStoragePoolDef poolDef;
+    virStorageVolDefPtr def = NULL;
+    char *tmp1;
+    char *tmp2;
+    char *datastorePath = NULL;
+    char *directoryName = NULL;
+    char *datastorePathWithoutFileName = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+
+    virCheckFlags(0, NULL);
+
+    memset(&poolDef, 0, sizeof (poolDef));
+
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        return NULL;
+    }
+
+    /* Lookup storage pool type */
+    if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
+        esxVI_LookupDatastoreByName(priv->primary, pool->name,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "info")) {
+            if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+                                                    &datastoreInfo) < 0) {
+                goto cleanup;
+            }
+
+            break;
+        }
+    }
+
+    if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+        poolDef.type = VIR_STORAGE_POOL_DIR;
+    } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+        poolDef.type = VIR_STORAGE_POOL_NETFS;
+    } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+        poolDef.type = VIR_STORAGE_POOL_FS;
+    } else {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("DatastoreInfo has unexpected type"));
+        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 */
+    tmp1 = strchr(def->name, '/');
+    tmp2 = strrchr(def->name, '/');
+
+    if (tmp1 == NULL || tmp1 == def->name ||
+        tmp2 == NULL || tmp2[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(&datastorePath, "[%s] %s", pool->name, def->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
+        /* Create directory, if it doesn't exist yet */
+        if (esxUtil_ParseDatastorePath(datastorePath, NULL, &directoryName,
+                                       NULL) < 0) {
+            goto cleanup;
+        }
+
+        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
+                        directoryName) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        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;
+            }
+        }
+
+        /* Create VirtualDisk */
+        if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 ||
+            esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) {
+            goto cleanup;
+        }
+
+        /* From the vSphere API documentation about VirtualDiskType ... */
+        if (def->allocation == def->capacity) {
+            /*
+             * "A preallocated disk has all space allocated at creation time
+             *  and the space is zeroed on demand as the space is used."
+             */
+            virtualDiskSpec->diskType = (char *)"preallocated";
+        } else if (def->allocation == 0) {
+            /*
+             * "Space required for thin-provisioned virtual disk is allocated
+             *  and zeroed on demand as the space is used."
+             */
+            virtualDiskSpec->diskType = (char *)"thin";
+        } else {
+            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                      _("Unsupported capacity-to-allocation relation"));
+            goto cleanup;
+        }
+
+        /*
+         * FIXME: The adapter type is a required parameter, but there is no
+         * way to let the user specifiy it in the volume XML config. Therefore,
+         * default to 'busLogic' here.
+         */
+        virtualDiskSpec->adapterType = (char *)"busLogic";
+
+        virtualDiskSpec->capacityKb->value = def->capacity / 1024; /* Scale from byte to kilobyte */
+
+        if (esxVI_CreateVirtualDisk_Task
+              (priv->primary, datastorePath, priv->primary->datacenter->_reference,
+               esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 ||
+            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+                                        esxVI_Occurrence_None,
+                                        priv->autoAnswer, &taskInfoState) < 0) {
+            goto cleanup;
+        }
+
+        if (taskInfoState != esxVI_TaskInfoState_Success) {
+            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create volume"));
+            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, datastorePath);
+
+  cleanup:
+    if (virtualDiskSpec != NULL) {
+        virtualDiskSpec->diskType = NULL;
+        virtualDiskSpec->adapterType = NULL;
+    }
+
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+    esxVI_DatastoreInfo_Free(&datastoreInfo);
+    virStorageVolDefFree(def);
+    VIR_FREE(datastorePath);
+    VIR_FREE(directoryName);
+    VIR_FREE(datastorePathWithoutFileName);
+    esxVI_FileInfo_Free(&fileInfo);
+    esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
+    esxVI_ManagedObjectReference_Free(&task);
+
+    return volume;
+}
+
+
+
 static int
 esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
 {
@@ -782,7 +987,7 @@ esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
     }
 
     if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
-                                            &fileInfo,
+                                            false, &fileInfo,
                                             esxVI_Occurrence_RequiredItem) < 0) {
         goto cleanup;
     }
@@ -875,7 +1080,7 @@ esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags)
     }
 
     if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
-                                            &fileInfo,
+                                            false, &fileInfo,
                                             esxVI_Occurrence_RequiredItem) < 0) {
         goto cleanup;
     }
@@ -986,7 +1191,7 @@ static virStorageDriver esxStorageDriver = {
     esxStorageVolumeLookupByName,          /* volLookupByName */
     esxStorageVolumeLookupByKeyOrPath,     /* volLookupByKey */
     esxStorageVolumeLookupByKeyOrPath,     /* volLookupByPath */
-    NULL,                                  /* volCreateXML */
+    esxStorageVolumeCreateXML,             /* volCreateXML */
     NULL,                                  /* volCreateXMLFrom */
     NULL,                                  /* volDelete */
     NULL,                                  /* volWipe */
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index a6950fd..8d83eac 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -2940,6 +2940,7 @@ esxVI_LookupCurrentSnapshotTree
 int
 esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
                                     const char *datastorePath,
+                                    bool lookupFolder,
                                     esxVI_FileInfo **fileInfo,
                                     esxVI_Occurrence occurrence)
 {
@@ -2954,6 +2955,7 @@ esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
     esxVI_ObjectContent *datastore = NULL;
     esxVI_ManagedObjectReference *hostDatastoreBrowser = NULL;
     esxVI_HostDatastoreBrowserSearchSpec *searchSpec = NULL;
+    esxVI_FolderFileQuery *folderFileQuery = NULL;
     esxVI_VmDiskFileQuery *vmDiskFileQuery = NULL;
     esxVI_IsoImageFileQuery *isoImageFileQuery = NULL;
     esxVI_FloppyImageFileQuery *floppyImageFileQuery = NULL;
@@ -3030,32 +3032,41 @@ esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
     searchSpec->details->fileSize = esxVI_Boolean_True;
     searchSpec->details->modification = esxVI_Boolean_False;
 
-    if (esxVI_VmDiskFileQuery_Alloc(&vmDiskFileQuery) < 0 ||
-        esxVI_VmDiskFileQueryFlags_Alloc(&vmDiskFileQuery->details) < 0 ||
-        esxVI_FileQuery_AppendToList
-          (&searchSpec->query,
-           esxVI_FileQuery_DynamicCast(vmDiskFileQuery)) < 0) {
-        goto cleanup;
-    }
+    if (lookupFolder) {
+        if (esxVI_FolderFileQuery_Alloc(&folderFileQuery) < 0 ||
+            esxVI_FileQuery_AppendToList
+              (&searchSpec->query,
+               esxVI_FileQuery_DynamicCast(folderFileQuery)) < 0) {
+            goto cleanup;
+        }
+    } else {
+        if (esxVI_VmDiskFileQuery_Alloc(&vmDiskFileQuery) < 0 ||
+            esxVI_VmDiskFileQueryFlags_Alloc(&vmDiskFileQuery->details) < 0 ||
+            esxVI_FileQuery_AppendToList
+              (&searchSpec->query,
+               esxVI_FileQuery_DynamicCast(vmDiskFileQuery)) < 0) {
+            goto cleanup;
+        }
 
-    vmDiskFileQuery->details->diskType = esxVI_Boolean_False;
-    vmDiskFileQuery->details->capacityKb = esxVI_Boolean_True;
-    vmDiskFileQuery->details->hardwareVersion = esxVI_Boolean_False;
-    vmDiskFileQuery->details->controllerType = esxVI_Boolean_True;
-    vmDiskFileQuery->details->diskExtents = esxVI_Boolean_False;
+        vmDiskFileQuery->details->diskType = esxVI_Boolean_False;
+        vmDiskFileQuery->details->capacityKb = esxVI_Boolean_True;
+        vmDiskFileQuery->details->hardwareVersion = esxVI_Boolean_False;
+        vmDiskFileQuery->details->controllerType = esxVI_Boolean_True;
+        vmDiskFileQuery->details->diskExtents = esxVI_Boolean_False;
 
-    if (esxVI_IsoImageFileQuery_Alloc(&isoImageFileQuery) < 0 ||
-        esxVI_FileQuery_AppendToList
-          (&searchSpec->query,
-           esxVI_FileQuery_DynamicCast(isoImageFileQuery)) < 0) {
-        goto cleanup;
-    }
+        if (esxVI_IsoImageFileQuery_Alloc(&isoImageFileQuery) < 0 ||
+            esxVI_FileQuery_AppendToList
+              (&searchSpec->query,
+               esxVI_FileQuery_DynamicCast(isoImageFileQuery)) < 0) {
+            goto cleanup;
+        }
 
-    if (esxVI_FloppyImageFileQuery_Alloc(&floppyImageFileQuery) < 0 ||
-        esxVI_FileQuery_AppendToList
-          (&searchSpec->query,
-           esxVI_FileQuery_DynamicCast(floppyImageFileQuery)) < 0) {
-        goto cleanup;
+        if (esxVI_FloppyImageFileQuery_Alloc(&floppyImageFileQuery) < 0 ||
+            esxVI_FileQuery_AppendToList
+              (&searchSpec->query,
+               esxVI_FileQuery_DynamicCast(floppyImageFileQuery)) < 0) {
+            goto cleanup;
+        }
     }
 
     if (esxVI_String_Alloc(&searchSpec->matchPattern) < 0) {
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 3d1aee0..773a1c6 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -401,6 +401,7 @@ int esxVI_LookupCurrentSnapshotTree
 
 int esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
                                         const char *datastorePath,
+                                        bool lookupFolder,
                                         esxVI_FileInfo **fileInfo,
                                         esxVI_Occurrence occurrence);
 
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 0fb9448..b911c22 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -166,6 +166,11 @@ object Description
 end
 
 
+object DeviceBackedVirtualDiskSpec extends VirtualDiskSpec
+    String                                   device                         r
+end
+
+
 object DynamicProperty
     String                                   name                           r
     AnyType                                  val                            r
@@ -190,6 +195,11 @@ object Event
 end
 
 
+object FileBackedVirtualDiskSpec extends VirtualDiskSpec
+    Long                                     capacityKb                     r
+end
+
+
 object FileInfo
     String                                   path                           r
     Long                                     fileSize                       o
@@ -528,6 +538,12 @@ object UserSession
 end
 
 
+object VirtualDiskSpec
+    String                                   diskType                       r
+    String                                   adapterType                    r
+end
+
+
 object VirtualMachineConfigSpec
     String                                   changeVersion                  o
     String                                   name                           o
@@ -694,6 +710,14 @@ method CreateSnapshot_Task returns ManagedObjectReference r
 end
 
 
+method CreateVirtualDisk_Task returns ManagedObjectReference r
+    ManagedObjectReference                   _this:VirtualDiskManager       r
+    String                                   name                           r
+    ManagedObjectReference                   datacenter                     o
+    VirtualDiskSpec                          spec                           r
+end
+
+
 method DestroyPropertyFilter
     ManagedObjectReference                   _this                          r
 end
@@ -728,6 +752,14 @@ method Logout
 end
 
 
+method MakeDirectory
+    ManagedObjectReference                   _this:FileManager              r
+    String                                   name                           r
+    ManagedObjectReference                   datacenter                     o
+    Boolean                                  createParentDirectories        o
+end
+
+
 method MigrateVM_Task returns ManagedObjectReference r
     ManagedObjectReference                   _this                          r
     ManagedObjectReference                   pool                           o
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 411fd80..be96a03 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -45,10 +45,12 @@ valid_occurrences = [OCCURRENCE__REQUIRED_ITEM,
 
 
 class Parameter:
-    autobind_map = { "PerformanceManager" : "perfManager",
+    autobind_map = { "FileManager"        : "fileManager",
+                     "PerformanceManager" : "perfManager",
                      "PropertyCollector"  : "propertyCollector",
                      "SearchIndex"        : "searchIndex",
-                     "SessionManager"     : "sessionManager" }
+                     "SessionManager"     : "sessionManager",
+                     "VirtualDiskManager" : "virtualDiskManager" }
 
     def __init__(self, type, name, occurrence):
         self.type = type
@@ -1146,6 +1148,7 @@ additional_object_features = { "DatastoreHostMount"         : Object.FEATURE__DE
                                "SharesInfo"                 : Object.FEATURE__ANY_TYPE,
                                "TaskInfo"                   : Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
                                "UserSession"                : Object.FEATURE__ANY_TYPE,
+                               "VirtualDiskSpec"            : Object.FEATURE__DYNAMIC_CAST,
                                "VirtualMachineQuestionInfo" : Object.FEATURE__ANY_TYPE,
                                "VirtualMachineSnapshotTree" : Object.FEATURE__DEEP_COPY | Object.FEATURE__ANY_TYPE }
 
diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c
index 56d2e58..a00561f 100644
--- a/src/esx/esx_vi_methods.c
+++ b/src/esx/esx_vi_methods.c
@@ -173,6 +173,12 @@
 
 
 
+#define ESX_VI__METHOD__PARAMETER__THIS__fileManager                          \
+    ESX_VI__METHOD__PARAMETER__THIS_FROM_SERVICE(ManagedObjectReference,      \
+                                                 fileManager)
+
+
+
 #define ESX_VI__METHOD__PARAMETER__THIS__perfManager                          \
     ESX_VI__METHOD__PARAMETER__THIS_FROM_SERVICE(ManagedObjectReference,      \
                                                  perfManager)
@@ -197,6 +203,12 @@
 
 
 
+#define ESX_VI__METHOD__PARAMETER__THIS__virtualDiskManager                   \
+    ESX_VI__METHOD__PARAMETER__THIS_FROM_SERVICE(ManagedObjectReference,      \
+                                                 virtualDiskManager)
+
+
+
 /*
  * A required parameter must be != 0 (NULL for pointers, "undefined" == 0 for
  * enumeration values).
-- 
1.7.0.4




More information about the libvir-list mailing list