From 067e83ebee8ba98a019b1f8bd677c5fb13e25f78 Mon Sep 17 00:00:00 2001 From: Ata E Husain Bohra Date: Fri, 9 Nov 2012 23:18:07 -0800 Subject: [PATCH] Refactor ESX storage driver to implement facade pattern The patch refactors the current ESX storage driver due to following reasons: 1. Given most of the public APIs exposed by the storage driver in Libvirt remains same, ESX storage driver should not implement logic specific for only one supported format (current implementation only supports VMFS). 2. Decoupling interface from specific storage implementation gives us an extensible design to hook implementation for other supported storage formats. This patch refactors the current driver to implement it as a facade pattern i.e. the driver exposes all the public libvirt APIs, but uses backend drivers to get the required task done. The backend drivers provide implementation specific to the type of storage device. File changes: ------------------ esx_storage_driver.c ----> esx_storage_driver.c (base storage driver) | |---> esx_storage_backend_vmfs.c (VMFS backend) --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/esx/esx_driver.c | 6 +- src/esx/esx_storage_backend_vmfs.c | 1537 ++++++++++++++++++++++++++++ src/esx/esx_storage_backend_vmfs.h | 31 + src/esx/esx_storage_driver.c | 1329 +++--------------------- src/esx/esx_vi.c | 5 +- src/esx/esx_vi.h | 3 +- 8 files changed, 1704 insertions(+), 1209 deletions(-) create mode 100644 src/esx/esx_storage_backend_vmfs.c create mode 100644 src/esx/esx_storage_backend_vmfs.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 97685287f1..1b7640c0a6 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -32,6 +32,7 @@ src/datatypes.c src/driver.c src/esx/esx_driver.c src/esx/esx_network_driver.c +src/esx/esx_storage_backend_vmfs.c src/esx/esx_storage_driver.c src/esx/esx_util.c src/esx/esx_vi.c diff --git a/src/Makefile.am b/src/Makefile.am index 1f32263bdd..4026a15b69 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -493,6 +493,7 @@ ESX_DRIVER_SOURCES = \ esx/esx_interface_driver.c esx/esx_interface_driver.h \ esx/esx_network_driver.c esx/esx_network_driver.h \ esx/esx_storage_driver.c esx/esx_storage_driver.h \ + esx/esx_storage_backend_vmfs.c esx/esx_storage_backend_vmfs.h \ esx/esx_device_monitor.c esx/esx_device_monitor.h \ esx/esx_secret_driver.c esx/esx_secret_driver.h \ esx/esx_nwfilter_driver.c esx/esx_nwfilter_driver.h \ diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 56f31bb98a..0374a98f13 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -163,7 +163,8 @@ esxParseVMXFileName(const char *fileName, void *opaque) datastoreName = NULL; if (esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj, - &hostMount) < 0 || + &hostMount, + esxVI_Occurrence_RequiredItem) < 0 || esxVI_GetStringValue(datastore, "summary.name", &datastoreName, esxVI_Occurrence_RequiredItem) < 0) { goto cleanup; @@ -307,7 +308,8 @@ esxFormatVMXFileName(const char *fileName, void *opaque) if (esxVI_LookupDatastoreByName(data->ctx, datastoreName, NULL, &datastore, esxVI_Occurrence_RequiredItem) < 0 || esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj, - &hostMount) < 0) { + &hostMount, + esxVI_Occurrence_RequiredItem) < 0) { goto cleanup; } diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c new file mode 100644 index 0000000000..5ef2981f02 --- /dev/null +++ b/src/esx/esx_storage_backend_vmfs.c @@ -0,0 +1,1537 @@ + +/* + * esx_storage_backend_vmfs.c: ESX storage driver backend for + * managing VMFS datastores + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2010-2012 Matthias Bolte + * Copyright (C) 2012 Ata E Husain Bohra + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#include + +#include +#include +#include + +#include "internal.h" +#include "md5.h" +#include "util.h" +#include "memory.h" +#include "logging.h" +#include "uuid.h" +#include "storage_conf.h" +#include "storage_file.h" +#include "esx_storage_backend_vmfs.h" +#include "esx_private.h" +#include "esx_vi.h" +#include "esx_vi_methods.h" +#include "esx_util.h" + +#define VIR_FROM_THIS VIR_FROM_ESX + +/* + * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore, + * verify that UUID and MD5 sum match in size, because we rely on that. + */ +verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN); + + + +static int +esxLookupVMFSStoragePoolType(esxVI_Context *ctx, const char *poolName, + int *poolType) +{ + int result = -1; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *datastore = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_DatastoreInfo *datastoreInfo = NULL; + + if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 || + esxVI_LookupDatastoreByName(ctx, poolName, propertyNameList, &datastore, + esxVI_Occurrence_OptionalItem) < 0) { + goto cleanup; + } + + if (datastore == NULL) { + /* Not found, let the base storage driver handle error reporting */ + 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) { + *poolType = VIR_STORAGE_POOL_DIR; + } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) { + *poolType = VIR_STORAGE_POOL_NETFS; + } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) { + *poolType = VIR_STORAGE_POOL_FS; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("DatastoreInfo has unexpected type")); + goto cleanup; + } + + result = 0; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datastore); + esxVI_DatastoreInfo_Free(&datastoreInfo); + + return result; +} + + + +static int +esxStorageBackendVMFSNumberOfPools(virConnectPtr conn) +{ + int count = 0; + esxPrivate *priv = conn->storagePrivateData; + esxVI_ObjectContent *datastoreList = NULL; + esxVI_ObjectContent *datastore = NULL; + + if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0) { + return -1; + } + + for (datastore = datastoreList; datastore != NULL; + datastore = datastore->_next) { + ++count; + } + + esxVI_ObjectContent_Free(&datastoreList); + + return count; +} + + + +static int +esxStorageBackendVMFSListPools(virConnectPtr conn, char **const names, + const int maxnames) +{ + bool success = false; + esxPrivate *priv = conn->storagePrivateData; + esxVI_String *propertyNameList = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent *datastoreList = NULL; + esxVI_ObjectContent *datastore = NULL; + int count = 0; + int i; + + if (maxnames == 0) { + return 0; + } + + 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) { + for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "summary.name")) { + if (esxVI_AnyType_ExpectType(dynamicProperty->val, + esxVI_Type_String) < 0) { + goto cleanup; + } + + names[count] = strdup(dynamicProperty->val->string); + + if (names[count] == NULL) { + virReportOOMError(); + goto cleanup; + } + + ++count; + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + } + + success = true; + + cleanup: + if (! success) { + for (i = 0; i < count; ++i) { + VIR_FREE(names[i]); + } + + count = -1; + } + + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datastoreList); + + return count; +} + + + +static virStoragePoolPtr +esxStorageBackendVMFSPoolLookupByName(virConnectPtr conn, + const char *name) +{ + esxPrivate *priv = conn->storagePrivateData; + esxVI_ObjectContent *datastore = NULL; + esxVI_DatastoreHostMount *hostMount = NULL; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + virStoragePoolPtr pool = NULL; + + if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore, + esxVI_Occurrence_OptionalItem) < 0) { + goto cleanup; + } + + if (datastore == NULL) { + /* Not found, let the base storage driver handle error reporting */ + goto cleanup; + } + + /* + * Datastores don't have a UUID, but we can use the 'host.mountInfo.path' + * property as source for a UUID. The mount path is unique per host and + * cannot change during the lifetime of the datastore. + * + * The MD5 sum of the mount path can be used as UUID, assuming MD5 is + * considered to be collision-free enough for this use case. + */ + if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj, &hostMount, + esxVI_Occurrence_OptionalItem) < 0) { + goto cleanup; + } + + if (hostMount == NULL) { + /* Not found, let the base storage driver handle error reporting */ + goto cleanup; + } + + md5_buffer(hostMount->mountInfo->path, + strlen(hostMount->mountInfo->path), md5); + + pool = virGetStoragePool(conn, name, md5, &esxStorageBackendVMFS, NULL); + + cleanup: + esxVI_ObjectContent_Free(&datastore); + esxVI_DatastoreHostMount_Free(&hostMount); + + return pool; +} + + + +static virStoragePoolPtr +esxStorageBackendVMFSPoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + esxPrivate *priv = conn->storagePrivateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *datastoreList = NULL; + esxVI_ObjectContent *datastore = NULL; + esxVI_DatastoreHostMount *hostMount = NULL; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + char *name = NULL; + virStoragePoolPtr pool = NULL; + + + 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) { + esxVI_DatastoreHostMount_Free(&hostMount); + + if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj, + &hostMount, + esxVI_Occurrence_OptionalItem) < 0) { + goto cleanup; + } + + if (hostMount == NULL) { + /* + * Storage pool is not of VMFS type, leave error reporting to the + * base storage driver. + */ + goto cleanup; + } + + md5_buffer(hostMount->mountInfo->path, + strlen(hostMount->mountInfo->path), md5); + + if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) { + break; + } + } + + if (datastore == NULL) { + /* Not found, let the base storage driver handle error reporting */ + goto cleanup; + } + + if (esxVI_GetStringValue(datastore, "summary.name", &name, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + pool = virGetStoragePool(conn, name, uuid, &esxStorageBackendVMFS, NULL); + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datastoreList); + esxVI_DatastoreHostMount_Free(&hostMount); + + return pool; +} + + + +static int +esxStorageBackendVMFSPoolRefresh(virStoragePoolPtr pool, unsigned int flags) +{ + int result = -1; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_ObjectContent *datastore = NULL; + + virCheckFlags(0, -1); + + if (esxVI_LookupDatastoreByName(priv->primary, pool->name, NULL, &datastore, + esxVI_Occurrence_RequiredItem) < 0 || + esxVI_RefreshDatastore(priv->primary, datastore->obj) < 0) { + goto cleanup; + } + + result = 0; + + cleanup: + esxVI_ObjectContent_Free(&datastore); + + return result; +} + + + +static int +esxStorageBackendVMFSPoolGetInfo(virStoragePoolPtr pool, + virStoragePoolInfoPtr info) +{ + int result = -1; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *datastore = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_Boolean accessible = esxVI_Boolean_Undefined; + + if (esxVI_String_AppendValueListToList(&propertyNameList, + "summary.accessible\0" + "summary.capacity\0" + "summary.freeSpace\0") < 0 || + esxVI_LookupDatastoreByName(priv->primary, pool->name, + propertyNameList, &datastore, + esxVI_Occurrence_RequiredItem) < 0 || + esxVI_GetBoolean(datastore, "summary.accessible", + &accessible, esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + if (accessible == esxVI_Boolean_True) { + info->state = VIR_STORAGE_POOL_RUNNING; + + for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "summary.capacity")) { + if (esxVI_AnyType_ExpectType(dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto cleanup; + } + + info->capacity = dynamicProperty->val->int64; + } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) { + if (esxVI_AnyType_ExpectType(dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto cleanup; + } + + info->available = dynamicProperty->val->int64; + } + } + + info->allocation = info->capacity - info->available; + } else { + info->state = VIR_STORAGE_POOL_INACCESSIBLE; + } + + result = 0; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datastore); + + return result; +} + + + +static char * +esxStorageBackendVMFSPoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags) +{ + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *datastore = NULL; + esxVI_DatastoreHostMount *hostMount = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_Boolean accessible = esxVI_Boolean_Undefined; + virStoragePoolDef def; + esxVI_DatastoreInfo *info = NULL; + esxVI_NasDatastoreInfo *nasInfo = NULL; + char *xml = NULL; + + virCheckFlags(0, NULL); + + memset(&def, 0, sizeof(def)); + + if (esxVI_String_AppendValueListToList(&propertyNameList, + "summary.accessible\0" + "summary.capacity\0" + "summary.freeSpace\0" + "info\0") < 0 || + esxVI_LookupDatastoreByName(priv->primary, pool->name, + propertyNameList, &datastore, + esxVI_Occurrence_RequiredItem) < 0 || + esxVI_GetBoolean(datastore, "summary.accessible", + &accessible, esxVI_Occurrence_RequiredItem) < 0 || + esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj, &hostMount, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + def.name = pool->name; + memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN); + + def.target.path = hostMount->mountInfo->path; + + if (accessible == esxVI_Boolean_True) { + for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "summary.capacity")) { + if (esxVI_AnyType_ExpectType(dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto cleanup; + } + + def.capacity = dynamicProperty->val->int64; + } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) { + if (esxVI_AnyType_ExpectType(dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto cleanup; + } + + def.available = dynamicProperty->val->int64; + } + } + + def.allocation = def.capacity - def.available; + } + + for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "info")) { + if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val, + &info) < 0) { + goto cleanup; + } + + break; + } + } + + /* See vSphere API documentation about HostDatastoreSystem for details */ + if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) { + def.type = VIR_STORAGE_POOL_DIR; + } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) { + if (VIR_ALLOC_N(def.source.hosts, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + def.type = VIR_STORAGE_POOL_NETFS; + def.source.hosts[0].name = nasInfo->nas->remoteHost; + def.source.dir = nasInfo->nas->remotePath; + + if (STRCASEEQ(nasInfo->nas->type, "NFS")) { + def.source.format = VIR_STORAGE_POOL_NETFS_NFS; + } else if (STRCASEEQ(nasInfo->nas->type, "CIFS")) { + def.source.format = VIR_STORAGE_POOL_NETFS_CIFS; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Datastore has unexpected type '%s'"), + nasInfo->nas->type); + goto cleanup; + } + } else if (esxVI_VmfsDatastoreInfo_DynamicCast(info) != NULL) { + def.type = VIR_STORAGE_POOL_FS; + /* + * FIXME: I'm not sure how to represent the source and target of a + * VMFS based datastore in libvirt terms + */ + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("DatastoreInfo has unexpected type")); + goto cleanup; + } + + xml = virStoragePoolDefFormat(&def); + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datastore); + esxVI_DatastoreHostMount_Free(&hostMount); + esxVI_DatastoreInfo_Free(&info); + + return xml; +} + + + +static int +esxStorageBackendVMFSPoolNumberOfVolumes(virStoragePoolPtr pool) +{ + bool success = false; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL; + esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL; + esxVI_FileInfo *fileInfo = NULL; + int count = 0; + + if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name, + &searchResultsList) < 0) { + goto cleanup; + } + + /* Interpret search result */ + for (searchResults = searchResultsList; searchResults != NULL; + searchResults = searchResults->_next) { + for (fileInfo = searchResults->file; fileInfo != NULL; + fileInfo = fileInfo->_next) { + ++count; + } + } + + success = true; + + cleanup: + esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList); + + return success ? count : -1; +} + + + +static int +esxStorageBackendVMFSPoolListVolumes(virStoragePoolPtr pool, char **const names, + int maxnames) +{ + bool success = false; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL; + esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL; + esxVI_FileInfo *fileInfo = NULL; + char *directoryAndFileName = NULL; + size_t length; + int count = 0; + int i; + + if (names == NULL || maxnames < 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); + return -1; + } + + if (maxnames == 0) { + return 0; + } + + if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name, + &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 volume names */ + for (fileInfo = searchResults->file; fileInfo != NULL; + fileInfo = fileInfo->_next) { + if (length < 1) { + names[count] = strdup(fileInfo->path); + + if (names[count] == NULL) { + virReportOOMError(); + goto cleanup; + } + } else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName, + fileInfo->path) < 0) { + virReportOOMError(); + goto cleanup; + } + + ++count; + } + } + + success = true; + + cleanup: + if (! success) { + for (i = 0; i < count; ++i) { + VIR_FREE(names[i]); + } + + count = -1; + } + + esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList); + VIR_FREE(directoryAndFileName); + + return count; +} + + + +static virStorageVolPtr +esxStorageBackendVMFSVolumeLookupByName(virStoragePoolPtr pool, + const char *name) +{ + virStorageVolPtr volume = NULL; + esxPrivate *priv = pool->conn->storagePrivateData; + char *datastorePath = NULL; + char *key = NULL; + + if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, + datastorePath, &key) < 0) { + goto cleanup; + } + + volume = virGetStorageVol(pool->conn, pool->name, name, key, + &esxStorageBackendVMFS, NULL); + + cleanup: + VIR_FREE(datastorePath); + VIR_FREE(key); + + return volume; +} + + + +static virStorageVolPtr +esxStorageBackendVMFSVolumeLookupByPath(virConnectPtr conn, const char *path) +{ + virStorageVolPtr volume = NULL; + esxPrivate *priv = conn->storagePrivateData; + char *datastoreName = NULL; + char *directoryAndFileName = NULL; + char *key = NULL; + + if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL, + &directoryAndFileName) < 0) { + goto cleanup; + } + + if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path, + &key) < 0) { + goto cleanup; + } + + volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key, + &esxStorageBackendVMFS, NULL); + + cleanup: + VIR_FREE(datastoreName); + VIR_FREE(directoryAndFileName); + VIR_FREE(key); + + return volume; +} + + + +static virStorageVolPtr +esxStorageBackendVMFSVolumeLookupByKey(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 esxStorageBackendVMFSVolumeLookupByPath(conn, key); + } + + if (!priv->primary->hasQueryVirtualDiskUuid) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("QueryVirtualDiskUuid not available, " + "cannot lookup storage volume by UUID")); + 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, + &esxStorageBackendVMFS, NULL); + 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; +} + + + +static virStorageVolPtr +esxStorageBackendVMFSVolumeCreateXML(virStoragePoolPtr pool, + const char *xmldesc, + unsigned int flags) +{ + virStorageVolPtr volume = NULL; + esxPrivate *priv = pool->conn->storagePrivateData; + virStoragePoolDef poolDef; + 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_FileBackedVirtualDiskSpec *virtualDiskSpec = 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 (esxLookupVMFSStoragePoolType(priv->primary, pool->name, + &poolDef.type) < 0) { + goto cleanup; + } + + /* Parse config */ + def = virStorageVolDefParseString(&poolDef, xmldesc); + + if (def == NULL) { + goto cleanup; + } + + if (def->type != VIR_STORAGE_VOL_FILE) { + virReportError(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') { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Volume name '%s' doesn't have expected format " + "'/'"), def->name); + goto cleanup; + } + + if (! virFileHasSuffix(def->name, ".vmdk")) { + virReportError(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; + } + } + + /* 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 { + virReportError(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 specify it in the volume XML config. Therefore, + * default to 'busLogic' here. + */ + virtualDiskSpec->adapterType = (char *)"busLogic"; + + virtualDiskSpec->capacityKb->value = + VIR_DIV_UP(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->parsedUri->autoAnswer, + &taskInfoState, + &taskInfoErrorMessage) < 0) { + goto cleanup; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not create 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 { + virReportError(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, + &esxStorageBackendVMFS, NULL); + + cleanup: + if (virtualDiskSpec != NULL) { + virtualDiskSpec->diskType = NULL; + virtualDiskSpec->adapterType = NULL; + } + + 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_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec); + esxVI_ManagedObjectReference_Free(&task); + VIR_FREE(taskInfoErrorMessage); + VIR_FREE(uuid_string); + VIR_FREE(key); + + return volume; +} + + + +static virStorageVolPtr +esxStorageBackendVMFSVolumeCreateXMLFrom(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 (esxLookupVMFSStoragePoolType(priv->primary, pool->name, + &poolDef.type) < 0) { + goto cleanup; + } + + 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) { + virReportError(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') { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Volume name '%s' doesn't have expected format " + "'/'"), def->name); + goto cleanup; + } + + if (! virFileHasSuffix(def->name, ".vmdk")) { + virReportError(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->parsedUri->autoAnswer, + &taskInfoState, + &taskInfoErrorMessage) < 0) { + goto cleanup; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + virReportError(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 { + virReportError(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, + &esxStorageBackendVMFS, NULL); + + 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 +esxStorageBackendVMFSVolumeDelete(virStorageVolPtr volume, unsigned int flags) +{ + int result = -1; + esxPrivate *priv = volume->conn->storagePrivateData; + char *datastorePath = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + char *taskInfoErrorMessage = NULL; + + virCheckFlags(0, -1); + + if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (esxVI_DeleteVirtualDisk_Task(priv->primary, datastorePath, + priv->primary->datacenter->_reference, + &task) < 0 || + esxVI_WaitForTaskCompletion(priv->primary, task, NULL, + esxVI_Occurrence_None, + priv->parsedUri->autoAnswer, + &taskInfoState, &taskInfoErrorMessage) < 0) { + goto cleanup; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not delete volume: %s"), + taskInfoErrorMessage); + goto cleanup; + } + + result = 0; + + cleanup: + VIR_FREE(datastorePath); + esxVI_ManagedObjectReference_Free(&task); + VIR_FREE(taskInfoErrorMessage); + + return result; +} + + + +static int +esxStorageBackendVMFSVolumeWipe(virStorageVolPtr volume, unsigned int flags) +{ + int result = -1; + esxPrivate *priv = volume->conn->storagePrivateData; + char *datastorePath = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + char *taskInfoErrorMessage = NULL; + + virCheckFlags(0, -1); + + if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (esxVI_ZeroFillVirtualDisk_Task(priv->primary, datastorePath, + priv->primary->datacenter->_reference, + &task) < 0 || + esxVI_WaitForTaskCompletion(priv->primary, task, NULL, + esxVI_Occurrence_None, + priv->parsedUri->autoAnswer, + &taskInfoState, &taskInfoErrorMessage) < 0) { + goto cleanup; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not wipe volume: %s"), + taskInfoErrorMessage); + goto cleanup; + } + + result = 0; + + cleanup: + VIR_FREE(datastorePath); + esxVI_ManagedObjectReference_Free(&task); + VIR_FREE(taskInfoErrorMessage); + + return result; +} + + + +static int +esxStorageBackendVMFSVolumeGetInfo(virStorageVolPtr volume, + virStorageVolInfoPtr info) +{ + int result = -1; + esxPrivate *priv = volume->conn->storagePrivateData; + char *datastorePath = NULL; + esxVI_FileInfo *fileInfo = NULL; + esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL; + + memset(info, 0, sizeof(*info)); + + if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath, + false, &fileInfo, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo); + + info->type = VIR_STORAGE_VOL_FILE; + + if (vmDiskFileInfo != NULL) { + /* Scale from kilobyte to byte */ + info->capacity = vmDiskFileInfo->capacityKb->value * 1024; + info->allocation = vmDiskFileInfo->fileSize->value; + } else { + info->capacity = fileInfo->fileSize->value; + info->allocation = fileInfo->fileSize->value; + } + + result = 0; + + cleanup: + VIR_FREE(datastorePath); + esxVI_FileInfo_Free(&fileInfo); + + return result; +} + + + +static char * +esxStorageBackendVMFSVolumeGetXMLDesc(virStorageVolPtr volume, + unsigned int flags) +{ + esxPrivate *priv = volume->conn->storagePrivateData; + virStoragePoolDef pool; + char *datastorePath = NULL; + esxVI_FileInfo *fileInfo = NULL; + esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL; + esxVI_IsoImageFileInfo *isoImageFileInfo = NULL; + esxVI_FloppyImageFileInfo *floppyImageFileInfo = NULL; + virStorageVolDef def; + char *xml = NULL; + + virCheckFlags(0, NULL); + + memset(&pool, 0, sizeof(pool)); + memset(&def, 0, sizeof(def)); + + if (esxLookupVMFSStoragePoolType(priv->primary, volume->pool, + &pool.type) < 0) { + return NULL; + } + + /* Lookup file info */ + if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath, + false, &fileInfo, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo); + isoImageFileInfo = esxVI_IsoImageFileInfo_DynamicCast(fileInfo); + floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo); + + def.name = volume->name; + + if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath, + &def.key) < 0) { + goto cleanup; + } + + def.type = VIR_STORAGE_VOL_FILE; + def.target.path = datastorePath; + + if (vmDiskFileInfo != NULL) { + /* Scale from kilobyte to byte */ + def.capacity = vmDiskFileInfo->capacityKb->value * 1024; + def.allocation = vmDiskFileInfo->fileSize->value; + + def.target.format = VIR_STORAGE_FILE_VMDK; + } else if (isoImageFileInfo != NULL) { + def.capacity = fileInfo->fileSize->value; + def.allocation = fileInfo->fileSize->value; + + def.target.format = VIR_STORAGE_FILE_ISO; + } else if (floppyImageFileInfo != NULL) { + def.capacity = fileInfo->fileSize->value; + def.allocation = fileInfo->fileSize->value; + + def.target.format = VIR_STORAGE_FILE_RAW; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("File '%s' has unknown type"), datastorePath); + goto cleanup; + } + + xml = virStorageVolDefFormat(&pool, &def); + + cleanup: + VIR_FREE(datastorePath); + esxVI_FileInfo_Free(&fileInfo); + VIR_FREE(def.key); + + return xml; +} + + + +static char * +esxStorageBackendVMFSVolumeGetPath(virStorageVolPtr volume) +{ + char *path; + + if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) { + virReportOOMError(); + return NULL; + } + + return path; +} + + + +virStorageDriver esxStorageBackendVMFS = { + .numOfPools = esxStorageBackendVMFSNumberOfPools, /* 0.8.2 */ + .listPools = esxStorageBackendVMFSListPools, /* 0.8.2 */ + .poolLookupByName = esxStorageBackendVMFSPoolLookupByName, /* 0.8.2 */ + .poolLookupByUUID = esxStorageBackendVMFSPoolLookupByUUID, /* 0.8.2 */ + .poolRefresh = esxStorageBackendVMFSPoolRefresh, /* 0.8.2 */ + .poolGetInfo = esxStorageBackendVMFSPoolGetInfo, /* 0.8.2 */ + .poolGetXMLDesc = esxStorageBackendVMFSPoolGetXMLDesc, /* 0.8.2 */ + .poolNumOfVolumes = esxStorageBackendVMFSPoolNumberOfVolumes, /* 0.8.4 */ + .poolListVolumes = esxStorageBackendVMFSPoolListVolumes, /* 0.8.4 */ + .volLookupByName = esxStorageBackendVMFSVolumeLookupByName, /* 0.8.4 */ + .volLookupByPath = esxStorageBackendVMFSVolumeLookupByPath, /* 0.8.4 */ + .volLookupByKey = esxStorageBackendVMFSVolumeLookupByKey, /* 0.8.4 */ + .volCreateXML = esxStorageBackendVMFSVolumeCreateXML, /* 0.8.4 */ + .volCreateXMLFrom = esxStorageBackendVMFSVolumeCreateXMLFrom, /* 0.8.7 */ + .volDelete = esxStorageBackendVMFSVolumeDelete, /* 0.8.7 */ + .volWipe = esxStorageBackendVMFSVolumeWipe, /* 0.8.7 */ + .volGetInfo = esxStorageBackendVMFSVolumeGetInfo, /* 0.8.4 */ + .volGetXMLDesc = esxStorageBackendVMFSVolumeGetXMLDesc, /* 0.8.4 */ + .volGetPath = esxStorageBackendVMFSVolumeGetPath, /* 0.8.4 */ +}; diff --git a/src/esx/esx_storage_backend_vmfs.h b/src/esx/esx_storage_backend_vmfs.h new file mode 100644 index 0000000000..9071642db7 --- /dev/null +++ b/src/esx/esx_storage_backend_vmfs.h @@ -0,0 +1,31 @@ + +/* + * esx_storage_backend_vmfs.h: ESX storage driver backend for + * managing VMFS datastores + * + * Copyright (C) 2012 Ata E Husain Bohra + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#ifndef __ESX_STORAGE_BACKEND_VMFS_H__ +# define __ESX_STORAGE_BACKEND_VMFS_H__ + +# include "driver.h" + +extern virStorageDriver esxStorageBackendVMFS; + +#endif /* __ESX_STORAGE_BACKEND_VMFS_H__ */ diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index 53a1e24229..52f46b4c22 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -4,7 +4,8 @@ * host storage * * Copyright (C) 2010-2011 Red Hat, Inc. - * Copyright (C) 2010 Matthias Bolte + * Copyright (C) 2010-2012 Matthias Bolte + * Copyright (C) 2012 Ata E Husain Bohra * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,80 +25,29 @@ #include -#include "md5.h" -#include "verify.h" -#include "internal.h" -#include "util.h" -#include "memory.h" -#include "logging.h" #include "uuid.h" +#include "memory.h" #include "storage_conf.h" -#include "storage_file.h" #include "esx_private.h" #include "esx_storage_driver.h" -#include "esx_vi.h" -#include "esx_vi_methods.h" -#include "esx_util.h" +#include "esx_storage_backend_vmfs.h" #define VIR_FROM_THIS VIR_FROM_ESX /* - * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore, - * verify that UUID and MD5 sum match in size, because we rely on that. + * ESX storage driver implements a facade pattern; + * the driver exposes the routines supported by libvirt + * public interface to manage ESX storage devices. Internally + * it uses backend drivers to perform the required task. */ -verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN); +enum { + VMFS = 0, + LAST_BACKEND +}; - - -static int -esxStoragePoolLookupType(esxVI_Context *ctx, const char *poolName, - int *poolType) -{ - int result = -1; - esxVI_String *propertyNameList = NULL; - esxVI_ObjectContent *datastore = NULL; - esxVI_DynamicProperty *dynamicProperty = NULL; - esxVI_DatastoreInfo *datastoreInfo = NULL; - - if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 || - esxVI_LookupDatastoreByName(ctx, poolName, 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) { - *poolType = VIR_STORAGE_POOL_DIR; - } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) { - *poolType = VIR_STORAGE_POOL_NETFS; - } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) { - *poolType = VIR_STORAGE_POOL_FS; - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("DatastoreInfo has unexpected type")); - goto cleanup; - } - - result = 0; - - cleanup: - esxVI_String_Free(&propertyNameList); - esxVI_ObjectContent_Free(&datastore); - esxVI_DatastoreInfo_Free(&datastoreInfo); - - return result; -} +static virStorageDriverPtr backends[] = { + &esxStorageBackendVMFS +}; @@ -134,23 +84,22 @@ esxNumberOfStoragePools(virConnectPtr conn) { int count = 0; esxPrivate *priv = conn->storagePrivateData; - esxVI_ObjectContent *datastoreList = NULL; - esxVI_ObjectContent *datastore = NULL; + int i; + int tmp; if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } - if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0) { - return -1; - } + for (i = 0; i < LAST_BACKEND; ++i) { + tmp = backends[i]->numOfPools(conn); - for (datastore = datastoreList; datastore != NULL; - datastore = datastore->_next) { - ++count; - } + if (tmp < 0) { + return -1; + } - esxVI_ObjectContent_Free(&datastoreList); + count += tmp; + } return count; } @@ -162,12 +111,9 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames) { bool success = false; esxPrivate *priv = conn->storagePrivateData; - esxVI_String *propertyNameList = NULL; - esxVI_DynamicProperty *dynamicProperty = NULL; - esxVI_ObjectContent *datastoreList = NULL; - esxVI_ObjectContent *datastore = NULL; int count = 0; int i; + int tmp; if (maxnames == 0) { return 0; @@ -177,36 +123,14 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames) return -1; } - if (esxVI_String_AppendValueToList(&propertyNameList, - "summary.name") < 0 || - esxVI_LookupDatastoreList(priv->primary, propertyNameList, - &datastoreList) < 0) { - goto cleanup; - } + for (i = 0; i < LAST_BACKEND; ++i) { + tmp = backends[i]->listPools(conn, &names[count], maxnames - count); - for (datastore = datastoreList; datastore != NULL; - datastore = datastore->_next) { - for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; - dynamicProperty = dynamicProperty->_next) { - if (STREQ(dynamicProperty->name, "summary.name")) { - if (esxVI_AnyType_ExpectType(dynamicProperty->val, - esxVI_Type_String) < 0) { - goto cleanup; - } - - names[count] = strdup(dynamicProperty->val->string); - - if (names[count] == NULL) { - virReportOOMError(); - goto cleanup; - } - - ++count; - break; - } else { - VIR_WARN("Unexpected '%s' property", dynamicProperty->name); - } + if (tmp < 0) { + goto cleanup; } + + count += tmp; } success = true; @@ -220,9 +144,6 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames) count = -1; } - esxVI_String_Free(&propertyNameList); - esxVI_ObjectContent_Free(&datastoreList); - return count; } @@ -252,43 +173,27 @@ static virStoragePoolPtr esxStoragePoolLookupByName(virConnectPtr conn, const char *name) { esxPrivate *priv = conn->storagePrivateData; - esxVI_ObjectContent *datastore = NULL; - esxVI_DatastoreHostMount *hostMount = NULL; - unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ - virStoragePoolPtr pool = NULL; + int i; + virStoragePoolPtr pool; + + virCheckNonNullArgReturn(name, NULL); if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore, - esxVI_Occurrence_RequiredItem) < 0) { - goto cleanup; + for (i = 0; i < LAST_BACKEND; ++i) { + pool = backends[i]->poolLookupByName(conn, name); + + if (pool != NULL) { + return pool; + } } - /* - * Datastores don't have a UUID, but we can use the 'host.mountInfo.path' - * property as source for a UUID. The mount path is unique per host and - * cannot change during the lifetime of the datastore. - * - * The MD5 sum of the mount path can be used as UUID, assuming MD5 is - * considered to be collision-free enough for this use case. - */ - if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj, - &hostMount) < 0) { - goto cleanup; - } + virReportError(VIR_ERR_NO_STORAGE_POOL, + _("Could not find storage pool with name '%s'"), name); - md5_buffer(hostMount->mountInfo->path, - strlen(hostMount->mountInfo->path), md5); - - pool = virGetStoragePool(conn, name, md5, NULL, NULL); - - cleanup: - esxVI_ObjectContent_Free(&datastore); - esxVI_DatastoreHostMount_Free(&hostMount); - - return pool; + return NULL; } @@ -297,65 +202,29 @@ static virStoragePoolPtr esxStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { esxPrivate *priv = conn->storagePrivateData; - esxVI_String *propertyNameList = NULL; - esxVI_ObjectContent *datastoreList = NULL; - esxVI_ObjectContent *datastore = NULL; - esxVI_DatastoreHostMount *hostMount = NULL; - unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + int i; + virStoragePoolPtr pool; char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; - char *name = NULL; - virStoragePoolPtr pool = NULL; if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 || - esxVI_LookupDatastoreList(priv->primary, propertyNameList, - &datastoreList) < 0) { - goto cleanup; - } + /* invoke backend drive method to search all known pools */ + for (i = 0; i < LAST_BACKEND; ++i) { + pool = backends[i]->poolLookupByUUID(conn, uuid); - for (datastore = datastoreList; datastore != NULL; - datastore = datastore->_next) { - esxVI_DatastoreHostMount_Free(&hostMount); - - if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj, - &hostMount) < 0) { - goto cleanup; - } - - md5_buffer(hostMount->mountInfo->path, - strlen(hostMount->mountInfo->path), md5); - - if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) { - break; + if (pool != NULL) { + return pool; } } - if (datastore == NULL) { - virUUIDFormat(uuid, uuid_string); + virUUIDFormat(uuid, uuid_string); + virReportError(VIR_ERR_NO_STORAGE_POOL, + _("Could not find storage pool with uuid '%s'"), + uuid_string); - virReportError(VIR_ERR_NO_STORAGE_POOL, - _("Could not find datastore with UUID '%s'"), - uuid_string); - - goto cleanup; - } - - if (esxVI_GetStringValue(datastore, "summary.name", &name, - esxVI_Occurrence_RequiredItem) < 0) { - goto cleanup; - } - - pool = virGetStoragePool(conn, name, uuid, NULL, NULL); - - cleanup: - esxVI_String_Free(&propertyNameList); - esxVI_ObjectContent_Free(&datastoreList); - esxVI_DatastoreHostMount_Free(&hostMount); - - return pool; + return NULL; } @@ -371,28 +240,16 @@ esxStoragePoolLookupByVolume(virStorageVolPtr volume) static int esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags) { - int result = -1; esxPrivate *priv = pool->conn->storagePrivateData; - esxVI_ObjectContent *datastore = NULL; + virStorageDriverPtr backend = pool->privateData; - virCheckFlags(0, -1); + virCheckNonNullArgReturn(pool->privateData, -1); if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } - if (esxVI_LookupDatastoreByName(priv->primary, pool->name, NULL, &datastore, - esxVI_Occurrence_RequiredItem) < 0 || - esxVI_RefreshDatastore(priv->primary, datastore->obj) < 0) { - goto cleanup; - } - - result = 0; - - cleanup: - esxVI_ObjectContent_Free(&datastore); - - return result; + return backend->poolRefresh(pool, flags); } @@ -400,12 +257,10 @@ esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags) static int esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info) { - int result = -1; esxPrivate *priv = pool->conn->storagePrivateData; - esxVI_String *propertyNameList = NULL; - esxVI_ObjectContent *datastore = NULL; - esxVI_DynamicProperty *dynamicProperty = NULL; - esxVI_Boolean accessible = esxVI_Boolean_Undefined; + virStorageDriverPtr backend = pool->privateData; + + virCheckNonNullArgReturn(pool->privateData, -1); memset(info, 0, sizeof(*info)); @@ -413,52 +268,7 @@ esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info) return -1; } - if (esxVI_String_AppendValueListToList(&propertyNameList, - "summary.accessible\0" - "summary.capacity\0" - "summary.freeSpace\0") < 0 || - esxVI_LookupDatastoreByName(priv->primary, pool->name, - propertyNameList, &datastore, - esxVI_Occurrence_RequiredItem) < 0 || - esxVI_GetBoolean(datastore, "summary.accessible", - &accessible, esxVI_Occurrence_RequiredItem) < 0) { - goto cleanup; - } - - if (accessible == esxVI_Boolean_True) { - info->state = VIR_STORAGE_POOL_RUNNING; - - for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; - dynamicProperty = dynamicProperty->_next) { - if (STREQ(dynamicProperty->name, "summary.capacity")) { - if (esxVI_AnyType_ExpectType(dynamicProperty->val, - esxVI_Type_Long) < 0) { - goto cleanup; - } - - info->capacity = dynamicProperty->val->int64; - } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) { - if (esxVI_AnyType_ExpectType(dynamicProperty->val, - esxVI_Type_Long) < 0) { - goto cleanup; - } - - info->available = dynamicProperty->val->int64; - } - } - - info->allocation = info->capacity - info->available; - } else { - info->state = VIR_STORAGE_POOL_INACCESSIBLE; - } - - result = 0; - - cleanup: - esxVI_String_Free(&propertyNameList); - esxVI_ObjectContent_Free(&datastore); - - return result; + return backend->poolGetInfo(pool, info); } @@ -467,122 +277,15 @@ static char * esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags) { esxPrivate *priv = pool->conn->storagePrivateData; - esxVI_String *propertyNameList = NULL; - esxVI_ObjectContent *datastore = NULL; - esxVI_DatastoreHostMount *hostMount = NULL; - esxVI_DynamicProperty *dynamicProperty = NULL; - esxVI_Boolean accessible = esxVI_Boolean_Undefined; - virStoragePoolDef def; - esxVI_DatastoreInfo *info = NULL; - esxVI_NasDatastoreInfo *nasInfo = NULL; - char *xml = NULL; + virStorageDriverPtr backend = pool->privateData; - virCheckFlags(0, NULL); - - memset(&def, 0, sizeof(def)); + virCheckNonNullArgReturn(pool->privateData, NULL); if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (esxVI_String_AppendValueListToList(&propertyNameList, - "summary.accessible\0" - "summary.capacity\0" - "summary.freeSpace\0" - "info\0") < 0 || - esxVI_LookupDatastoreByName(priv->primary, pool->name, - propertyNameList, &datastore, - esxVI_Occurrence_RequiredItem) < 0 || - esxVI_GetBoolean(datastore, "summary.accessible", - &accessible, esxVI_Occurrence_RequiredItem) < 0 || - esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj, - &hostMount) < 0) { - goto cleanup; - } - - def.name = pool->name; - memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN); - - def.target.path = hostMount->mountInfo->path; - - if (accessible == esxVI_Boolean_True) { - for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; - dynamicProperty = dynamicProperty->_next) { - if (STREQ(dynamicProperty->name, "summary.capacity")) { - if (esxVI_AnyType_ExpectType(dynamicProperty->val, - esxVI_Type_Long) < 0) { - goto cleanup; - } - - def.capacity = dynamicProperty->val->int64; - } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) { - if (esxVI_AnyType_ExpectType(dynamicProperty->val, - esxVI_Type_Long) < 0) { - goto cleanup; - } - - def.available = dynamicProperty->val->int64; - } - } - - def.allocation = def.capacity - def.available; - } - - for (dynamicProperty = datastore->propSet; dynamicProperty != NULL; - dynamicProperty = dynamicProperty->_next) { - if (STREQ(dynamicProperty->name, "info")) { - if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val, - &info) < 0) { - goto cleanup; - } - - break; - } - } - - /* See vSphere API documentation about HostDatastoreSystem for details */ - if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) { - def.type = VIR_STORAGE_POOL_DIR; - } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) { - if (VIR_ALLOC_N(def.source.hosts, 1) < 0) { - virReportOOMError(); - goto cleanup; - } - def.type = VIR_STORAGE_POOL_NETFS; - def.source.hosts[0].name = nasInfo->nas->remoteHost; - def.source.dir = nasInfo->nas->remotePath; - - if (STRCASEEQ(nasInfo->nas->type, "NFS")) { - def.source.format = VIR_STORAGE_POOL_NETFS_NFS; - } else if (STRCASEEQ(nasInfo->nas->type, "CIFS")) { - def.source.format = VIR_STORAGE_POOL_NETFS_CIFS; - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Datastore has unexpected type '%s'"), - nasInfo->nas->type); - goto cleanup; - } - } else if (esxVI_VmfsDatastoreInfo_DynamicCast(info) != NULL) { - def.type = VIR_STORAGE_POOL_FS; - /* - * FIXME: I'm not sure how to represent the source and target of a - * VMFS based datastore in libvirt terms - */ - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("DatastoreInfo has unexpected type")); - goto cleanup; - } - - xml = virStoragePoolDefFormat(&def); - - cleanup: - esxVI_String_Free(&propertyNameList); - esxVI_ObjectContent_Free(&datastore); - esxVI_DatastoreHostMount_Free(&hostMount); - esxVI_DatastoreInfo_Free(&info); - - return xml; + return backend->poolGetXMLDesc(pool, flags); } @@ -620,37 +323,16 @@ esxStoragePoolSetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED, static int esxStoragePoolNumberOfStorageVolumes(virStoragePoolPtr pool) { - bool success = false; esxPrivate *priv = pool->conn->storagePrivateData; - esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL; - esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL; - esxVI_FileInfo *fileInfo = NULL; - int count = 0; + virStorageDriverPtr backend = pool->privateData; + + virCheckNonNullArgReturn(pool->privateData, -1); if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } - if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name, - &searchResultsList) < 0) { - goto cleanup; - } - - /* Interpret search result */ - for (searchResults = searchResultsList; searchResults != NULL; - searchResults = searchResults->_next) { - for (fileInfo = searchResults->file; fileInfo != NULL; - fileInfo = fileInfo->_next) { - ++count; - } - } - - success = true; - - cleanup: - esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList); - - return success ? count : -1; + return backend->poolNumOfVolumes(pool); } @@ -659,87 +341,16 @@ static int esxStoragePoolListStorageVolumes(virStoragePoolPtr pool, char **const names, int maxnames) { - bool success = false; esxPrivate *priv = pool->conn->storagePrivateData; - esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL; - esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL; - esxVI_FileInfo *fileInfo = NULL; - char *directoryAndFileName = NULL; - size_t length; - int count = 0; - int i; + virStorageDriverPtr backend = pool->privateData; - if (names == NULL || maxnames < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); - return -1; - } - - if (maxnames == 0) { - return 0; - } + virCheckNonNullArgReturn(pool->privateData, -1); if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } - if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name, - &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 volume names */ - for (fileInfo = searchResults->file; fileInfo != NULL; - fileInfo = fileInfo->_next) { - if (length < 1) { - names[count] = strdup(fileInfo->path); - - if (names[count] == NULL) { - virReportOOMError(); - goto cleanup; - } - } else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName, - fileInfo->path) < 0) { - virReportOOMError(); - goto cleanup; - } - - ++count; - } - } - - success = true; - - cleanup: - if (! success) { - for (i = 0; i < count; ++i) { - VIR_FREE(names[i]); - } - - count = -1; - } - - esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList); - VIR_FREE(directoryAndFileName); - - return count; + return backend->poolListVolumes(pool, names, maxnames); } @@ -747,32 +358,16 @@ esxStoragePoolListStorageVolumes(virStoragePoolPtr pool, char **const names, static virStorageVolPtr esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name) { - virStorageVolPtr volume = NULL; esxPrivate *priv = pool->conn->storagePrivateData; - char *datastorePath = NULL; - char *key = NULL; + virStorageDriverPtr backend = pool->privateData; + + virCheckNonNullArgReturn(pool->privateData, NULL); if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, - datastorePath, &key) < 0) { - goto cleanup; - } - - volume = virGetStorageVol(pool->conn, pool->name, name, key, NULL, NULL); - - cleanup: - VIR_FREE(datastorePath); - VIR_FREE(key); - - return volume; + return backend->volLookupByName(pool, name); } @@ -780,34 +375,26 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name) static virStorageVolPtr esxStorageVolumeLookupByPath(virConnectPtr conn, const char *path) { - virStorageVolPtr volume = NULL; esxPrivate *priv = conn->storagePrivateData; - char *datastoreName = NULL; - char *directoryAndFileName = NULL; - char *key = NULL; if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL, - &directoryAndFileName) < 0) { - goto cleanup; + /* + * FIXME: calling backends blindly may set unwanted error codes + * + * VMFS Datastore path follows cannonical format i.e.: + * [] + */ + if (STRPREFIX(path, "[")) { + return backends[VMFS]->volLookupByPath(conn, path); + } else { + virReportError(VIR_ERR_INVALID_ARG, + _("Unexpected volume path format: %s"), path); + + return NULL; } - - if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path, - &key) < 0) { - goto cleanup; - } - - volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key, NULL, NULL); - - cleanup: - VIR_FREE(datastoreName); - VIR_FREE(directoryAndFileName); - VIR_FREE(key); - - return volume; } @@ -815,142 +402,27 @@ esxStorageVolumeLookupByPath(virConnectPtr conn, const char *path) static virStorageVolPtr esxStorageVolumeLookupByKey(virConnectPtr conn, const char *key) { - virStorageVolPtr volume = NULL; + virStorageVolPtr volume; 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 (!priv->primary->hasQueryVirtualDiskUuid) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("QueryVirtualDiskUuid not available, cannot lookup storage " - "volume by UUID")); - return NULL; - } + int i; 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 (i = 0; i < LAST_BACKEND; ++i) { + volume = backends[i]->volLookupByKey(conn, key); - 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, NULL, NULL); - goto cleanup; - } - } + if (volume != NULL) { + return volume; } } - 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); + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("Could not find storage volume with key '%s'"), + key); - return volume; + return NULL; } @@ -959,226 +431,16 @@ static virStorageVolPtr esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc, unsigned int flags) { - virStorageVolPtr volume = NULL; esxPrivate *priv = pool->conn->storagePrivateData; - virStoragePoolDef poolDef; - 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_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL; - esxVI_ManagedObjectReference *task = NULL; - esxVI_TaskInfoState taskInfoState; - char *taskInfoErrorMessage = NULL; - char *uuid_string = NULL; - char *key = NULL; + virStorageDriverPtr backend = pool->privateData; - virCheckFlags(0, NULL); - - memset(&poolDef, 0, sizeof(poolDef)); + virCheckNonNullArgReturn(pool->privateData, NULL); if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) { - return NULL; - } - - /* Parse config */ - def = virStorageVolDefParseString(&poolDef, xmldesc); - - if (def == NULL) { - goto cleanup; - } - - if (def->type != VIR_STORAGE_VOL_FILE) { - virReportError(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') { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Volume name '%s' doesn't have expected format " - "'/'"), def->name); - goto cleanup; - } - - if (! virFileHasSuffix(def->name, ".vmdk")) { - virReportError(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; - } - } - - /* 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 { - virReportError(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 specify it in the volume XML config. Therefore, - * default to 'busLogic' here. - */ - virtualDiskSpec->adapterType = (char *)"busLogic"; - - virtualDiskSpec->capacityKb->value = - VIR_DIV_UP(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->parsedUri->autoAnswer, - &taskInfoState, - &taskInfoErrorMessage) < 0) { - goto cleanup; - } - - if (taskInfoState != esxVI_TaskInfoState_Success) { - virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create 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 { - virReportError(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, NULL, NULL); - - cleanup: - if (virtualDiskSpec != NULL) { - virtualDiskSpec->diskType = NULL; - virtualDiskSpec->adapterType = NULL; - } - - 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_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec); - esxVI_ManagedObjectReference_Free(&task); - VIR_FREE(taskInfoErrorMessage); - VIR_FREE(uuid_string); - VIR_FREE(key); - - return volume; + return backend->volCreateXML(pool, xmldesc, flags); } @@ -1187,195 +449,16 @@ 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; + virStorageDriverPtr backend = pool->privateData; - virCheckFlags(0, NULL); - - memset(&poolDef, 0, sizeof(poolDef)); + virCheckNonNullArgReturn(pool->privateData, NULL); 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) { - virReportError(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') { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Volume name '%s' doesn't have expected format " - "'/'"), def->name); - goto cleanup; - } - - if (! virFileHasSuffix(def->name, ".vmdk")) { - virReportError(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->parsedUri->autoAnswer, - &taskInfoState, - &taskInfoErrorMessage) < 0) { - goto cleanup; - } - - if (taskInfoState != esxVI_TaskInfoState_Success) { - virReportError(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 { - virReportError(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, NULL, NULL); - - 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; + return backend->volCreateXMLFrom(pool, xmldesc, sourceVolume, flags); } @@ -1383,48 +466,16 @@ esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc, static int esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags) { - int result = -1; esxPrivate *priv = volume->conn->storagePrivateData; - char *datastorePath = NULL; - esxVI_ManagedObjectReference *task = NULL; - esxVI_TaskInfoState taskInfoState; - char *taskInfoErrorMessage = NULL; + virStorageDriverPtr backend = volume->privateData; - virCheckFlags(0, -1); + virCheckNonNullArgReturn(volume->privateData, -1); if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } - if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (esxVI_DeleteVirtualDisk_Task(priv->primary, datastorePath, - priv->primary->datacenter->_reference, - &task) < 0 || - esxVI_WaitForTaskCompletion(priv->primary, task, NULL, - esxVI_Occurrence_None, - priv->parsedUri->autoAnswer, - &taskInfoState, &taskInfoErrorMessage) < 0) { - goto cleanup; - } - - if (taskInfoState != esxVI_TaskInfoState_Success) { - virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not delete volume: %s"), - taskInfoErrorMessage); - goto cleanup; - } - - result = 0; - - cleanup: - VIR_FREE(datastorePath); - esxVI_ManagedObjectReference_Free(&task); - VIR_FREE(taskInfoErrorMessage); - - return result; + return backend->volDelete(volume, flags); } @@ -1432,48 +483,16 @@ esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags) static int esxStorageVolumeWipe(virStorageVolPtr volume, unsigned int flags) { - int result = -1; esxPrivate *priv = volume->conn->storagePrivateData; - char *datastorePath = NULL; - esxVI_ManagedObjectReference *task = NULL; - esxVI_TaskInfoState taskInfoState; - char *taskInfoErrorMessage = NULL; + virStorageDriverPtr backend = volume->privateData; - virCheckFlags(0, -1); + virCheckNonNullArgReturn(volume->privateData, -1); if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } - if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (esxVI_ZeroFillVirtualDisk_Task(priv->primary, datastorePath, - priv->primary->datacenter->_reference, - &task) < 0 || - esxVI_WaitForTaskCompletion(priv->primary, task, NULL, - esxVI_Occurrence_None, - priv->parsedUri->autoAnswer, - &taskInfoState, &taskInfoErrorMessage) < 0) { - goto cleanup; - } - - if (taskInfoState != esxVI_TaskInfoState_Success) { - virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not wipe volume: %s"), - taskInfoErrorMessage); - goto cleanup; - } - - result = 0; - - cleanup: - VIR_FREE(datastorePath); - esxVI_ManagedObjectReference_Free(&task); - VIR_FREE(taskInfoErrorMessage); - - return result; + return backend->volWipe(volume, flags); } @@ -1481,48 +500,16 @@ esxStorageVolumeWipe(virStorageVolPtr volume, unsigned int flags) static int esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info) { - int result = -1; esxPrivate *priv = volume->conn->storagePrivateData; - char *datastorePath = NULL; - esxVI_FileInfo *fileInfo = NULL; - esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL; + virStorageDriverPtr backend = volume->privateData; - memset(info, 0, sizeof(*info)); + virCheckNonNullArgReturn(volume->privateData, -1); if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } - if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath, - false, &fileInfo, - esxVI_Occurrence_RequiredItem) < 0) { - goto cleanup; - } - - vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo); - - info->type = VIR_STORAGE_VOL_FILE; - - if (vmDiskFileInfo != NULL) { - info->capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */ - info->allocation = vmDiskFileInfo->fileSize->value; - } else { - info->capacity = fileInfo->fileSize->value; - info->allocation = fileInfo->fileSize->value; - } - - result = 0; - - cleanup: - VIR_FREE(datastorePath); - esxVI_FileInfo_Free(&fileInfo); - - return result; + return backend->volGetInfo(volume, info); } @@ -1531,83 +518,15 @@ static char * esxStorageVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags) { esxPrivate *priv = volume->conn->storagePrivateData; - virStoragePoolDef pool; - char *datastorePath = NULL; - esxVI_FileInfo *fileInfo = NULL; - esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL; - esxVI_IsoImageFileInfo *isoImageFileInfo = NULL; - esxVI_FloppyImageFileInfo *floppyImageFileInfo = NULL; - virStorageVolDef def; - char *xml = NULL; + virStorageDriverPtr backend = volume->privateData; - virCheckFlags(0, NULL); - - memset(&pool, 0, sizeof(pool)); - memset(&def, 0, sizeof(def)); + virCheckNonNullArgReturn(volume->privateData, NULL); if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - if (esxStoragePoolLookupType(priv->primary, volume->pool, &pool.type) < 0) { - return NULL; - } - - /* Lookup file info */ - if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath, - false, &fileInfo, - esxVI_Occurrence_RequiredItem) < 0) { - goto cleanup; - } - - vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo); - isoImageFileInfo = esxVI_IsoImageFileInfo_DynamicCast(fileInfo); - floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo); - - def.name = volume->name; - - if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath, - &def.key) < 0) { - goto cleanup; - } - - def.type = VIR_STORAGE_VOL_FILE; - def.target.path = datastorePath; - - if (vmDiskFileInfo != NULL) { - def.capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */ - def.allocation = vmDiskFileInfo->fileSize->value; - - def.target.format = VIR_STORAGE_FILE_VMDK; - } else if (isoImageFileInfo != NULL) { - def.capacity = fileInfo->fileSize->value; - def.allocation = fileInfo->fileSize->value; - - def.target.format = VIR_STORAGE_FILE_ISO; - } else if (floppyImageFileInfo != NULL) { - def.capacity = fileInfo->fileSize->value; - def.allocation = fileInfo->fileSize->value; - - def.target.format = VIR_STORAGE_FILE_RAW; - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("File '%s' has unknown type"), datastorePath); - goto cleanup; - } - - xml = virStorageVolDefFormat(&pool, &def); - - cleanup: - VIR_FREE(datastorePath); - esxVI_FileInfo_Free(&fileInfo); - VIR_FREE(def.key); - - return xml; + return backend->volGetXMLDesc(volume, flags); } @@ -1615,14 +534,16 @@ esxStorageVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags) static char * esxStorageVolumeGetPath(virStorageVolPtr volume) { - char *path; + esxPrivate *priv = volume->conn->storagePrivateData; + virStorageDriverPtr backend = volume->privateData; - if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) { - virReportOOMError(); + virCheckNonNullArgReturn(volume->privateData, NULL); + + if (esxVI_EnsureSession(priv->primary) < 0) { return NULL; } - return path; + return backend->volGetPath(volume); } @@ -1664,8 +585,8 @@ static virStorageDriver esxStorageDriver = { .poolNumOfVolumes = esxStoragePoolNumberOfStorageVolumes, /* 0.8.4 */ .poolListVolumes = esxStoragePoolListStorageVolumes, /* 0.8.4 */ .volLookupByName = esxStorageVolumeLookupByName, /* 0.8.4 */ - .volLookupByKey = esxStorageVolumeLookupByKey, /* 0.8.4 */ .volLookupByPath = esxStorageVolumeLookupByPath, /* 0.8.4 */ + .volLookupByKey = esxStorageVolumeLookupByKey, /* 0.8.4 */ .volCreateXML = esxStorageVolumeCreateXML, /* 0.8.4 */ .volCreateXMLFrom = esxStorageVolumeCreateXMLFrom, /* 0.8.7 */ .volDelete = esxStorageVolumeDelete, /* 0.8.7 */ diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index f3224f8f03..9fb2c11daf 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -3107,7 +3107,8 @@ esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx, int esxVI_LookupDatastoreHostMount(esxVI_Context *ctx, esxVI_ManagedObjectReference *datastore, - esxVI_DatastoreHostMount **hostMount) + esxVI_DatastoreHostMount **hostMount, + esxVI_Occurrence occurrence) { int result = -1; esxVI_String *propertyNameList = NULL; @@ -3155,7 +3156,7 @@ esxVI_LookupDatastoreHostMount(esxVI_Context *ctx, break; } - if (*hostMount == NULL) { + if (*hostMount == NULL && occurrence == esxVI_Occurrence_RequiredItem) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not lookup datastore host mount")); goto cleanup; diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index a9c12c8a00..d7895a0013 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -441,7 +441,8 @@ int esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx, int esxVI_LookupDatastoreHostMount(esxVI_Context *ctx, esxVI_ManagedObjectReference *datastore, - esxVI_DatastoreHostMount **hostMount); + esxVI_DatastoreHostMount **hostMount, + esxVI_Occurrence occurrence); int esxVI_LookupTaskInfoByTask(esxVI_Context *ctx, esxVI_ManagedObjectReference *task,