libvirt/src/esx/esx_storage_backend_vmfs.c

1475 lines
47 KiB
C
Raw Normal View History

/*
* esx_storage_backend_vmfs.c: ESX storage driver backend for
* managing VMFS datastores
*
conf: track sizes directly in source struct One of the features of qcow2 is that a wrapper file can have more capacity than its backing file from the guest's perspective; what's more, sparse files make tracking allocation of both the active and backing file worthwhile. As such, it makes more sense to show allocation numbers for each file in a chain, and not just the top-level file. This sets up the fields for the tracking, although it does not modify XML to display any new information. * src/util/virstoragefile.h (_virStorageSource): Add fields. * src/conf/storage_conf.h (_virStorageVolDef): Drop redundant fields. * src/storage/storage_backend.c (virStorageBackendCreateBlockFrom) (createRawFile, virStorageBackendCreateQemuImgCmd) (virStorageBackendCreateQcowCreate): Update clients. * src/storage/storage_driver.c (storageVolDelete) (storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize) (storageVolWipeInternal, storageVolGetInfo): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendProbeTarget) (virStorageBackendFileSystemRefresh) (virStorageBackendFileSystemVolResize) (virStorageBackendFileSystemVolRefresh): Likewise. * src/storage/storage_backend_logical.c (virStorageBackendLogicalMakeVol) (virStorageBackendLogicalCreateVol): Likewise. * src/storage/storage_backend_scsi.c (virStorageBackendSCSINewLun): Likewise. * src/storage/storage_backend_mpath.c (virStorageBackendMpathNewVol): Likewise. * src/storage/storage_backend_rbd.c (volStorageBackendRBDRefreshVolInfo) (virStorageBackendRBDCreateImage): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskMakeDataVol) (virStorageBackendDiskCreateVol): Likewise. * src/storage/storage_backend_sheepdog.c (virStorageBackendSheepdogBuildVol) (virStorageBackendSheepdogParseVdiList): Likewise. * src/storage/storage_backend_gluster.c (virStorageBackendGlusterRefreshVol): Likewise. * src/conf/storage_conf.c (virStorageVolDefFormat) (virStorageVolDefParseXML): Likewise. * src/test/test_driver.c (testOpenVolumesForPool) (testStorageVolCreateXML, testStorageVolCreateXMLFrom) (testStorageVolDelete, testStorageVolGetInfo): Likewise. * src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc): Likewise. * src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc) (esxStorageVolCreateXML): Likewise. * src/parallels/parallels_driver.c (parallelsAddHddByVolume): Likewise. * src/parallels/parallels_storage.c (parallelsDiskDescParseNode) (parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom) (parallelsStorageVolDefRemove, parallelsStorageVolGetInfo): Likewise. * src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML) (vboxStorageVolGetXMLDesc): Likewise. * tests/storagebackendsheepdogtest.c (test_vdi_list_parser): Likewise. * src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
* Copyright (C) 2010-2014 Red Hat, Inc.
* Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte@googlemail.com>
* Copyright (C) 2012 Ata E Husain Bohra <ata.husain@hotmail.com>
*
* 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
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "internal.h"
#include "md5.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
#include "virfile.h"
2012-12-12 17:59:27 +00:00
#include "virlog.h"
2012-12-13 18:01:25 +00:00
#include "viruuid.h"
#include "storage_conf.h"
#include "virstoragefile.h"
#include "esx_storage_backend_vmfs.h"
#include "esx_private.h"
#include "esx_vi.h"
#include "esx_vi_methods.h"
#include "esx_util.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_ESX
VIR_LOG_INIT("esx.esx_storage_backend_vmfs");
/*
* The UUID of a storage pool is the MD5 sum of its 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) {
/* Not found, let the base storage driver handle error reporting */
goto cleanup;
}
for (dynamicProperty = datastore->propSet; dynamicProperty;
dynamicProperty = dynamicProperty->_next) {
if (STREQ(dynamicProperty->name, "info")) {
if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
&datastoreInfo) < 0) {
goto cleanup;
}
break;
}
}
if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo)) {
*poolType = VIR_STORAGE_POOL_DIR;
} else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo)) {
*poolType = VIR_STORAGE_POOL_NETFS;
} else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo)) {
*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
esxConnectNumOfStoragePools(virConnectPtr conn)
{
int count = 0;
esxPrivate *priv = conn->privateData;
esxVI_ObjectContent *datastoreList = NULL;
esxVI_ObjectContent *datastore = NULL;
if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0)
return -1;
for (datastore = datastoreList; datastore;
datastore = datastore->_next) {
++count;
}
esxVI_ObjectContent_Free(&datastoreList);
return count;
}
static int
esxConnectListStoragePools(virConnectPtr conn, char **const names,
const int maxnames)
{
bool success = false;
esxPrivate *priv = conn->privateData;
esxVI_String *propertyNameList = NULL;
esxVI_DynamicProperty *dynamicProperty = NULL;
esxVI_ObjectContent *datastoreList = NULL;
esxVI_ObjectContent *datastore = NULL;
int count = 0;
size_t 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;
datastore = datastore->_next) {
for (dynamicProperty = datastore->propSet; dynamicProperty;
dynamicProperty = dynamicProperty->_next) {
if (STREQ(dynamicProperty->name, "summary.name")) {
if (esxVI_AnyType_ExpectType(dynamicProperty->val,
esxVI_Type_String) < 0) {
goto cleanup;
}
if (VIR_STRDUP(names[count], dynamicProperty->val->string) < 0)
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
esxStoragePoolLookupByName(virConnectPtr conn,
const char *name)
{
esxPrivate *priv = conn->privateData;
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) {
/* 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) {
/* 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
esxStoragePoolLookupByUUID(virConnectPtr conn,
const unsigned char *uuid)
{
esxPrivate *priv = conn->privateData;
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;
datastore = datastore->_next) {
esxVI_DatastoreHostMount_Free(&hostMount);
if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
&hostMount,
esxVI_Occurrence_OptionalItem) < 0) {
goto cleanup;
}
if (!hostMount) {
/*
* 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) {
/* 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
esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
{
int result = -1;
esxPrivate *priv = pool->conn->privateData;
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
esxStoragePoolGetInfo(virStoragePoolPtr pool,
virStoragePoolInfoPtr info)
{
int result = -1;
esxPrivate *priv = pool->conn->privateData;
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;
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 *
esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
{
esxPrivate *priv = pool->conn->privateData;
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;
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;
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)) {
def.type = VIR_STORAGE_POOL_DIR;
} else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info))) {
if (VIR_ALLOC_N(def.source.hosts, 1) < 0)
goto cleanup;
def.type = VIR_STORAGE_POOL_NETFS;
def.source.nhost = 1;
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)) {
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
esxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
bool success = false;
esxPrivate *priv = pool->conn->privateData;
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;
searchResults = searchResults->_next) {
for (fileInfo = searchResults->file; fileInfo;
fileInfo = fileInfo->_next) {
++count;
}
}
success = true;
cleanup:
esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
return success ? count : -1;
}
static int
esxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names,
int maxnames)
{
bool success = false;
esxPrivate *priv = pool->conn->privateData;
esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
esxVI_FileInfo *fileInfo = NULL;
char *directoryAndFileName = NULL;
size_t length;
int count = 0;
size_t i;
if (!names || 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;
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;
fileInfo = fileInfo->_next) {
if (length < 1) {
if (VIR_STRDUP(names[count], fileInfo->path) < 0)
goto cleanup;
} else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName,
fileInfo->path) < 0) {
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
esxStorageVolLookupByName(virStoragePoolPtr pool,
const char *name)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->privateData;
char *datastorePath = NULL;
char *key = NULL;
if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0)
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
esxStorageVolLookupByPath(virConnectPtr conn, const char *path)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = conn->privateData;
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
esxStorageVolLookupByKey(virConnectPtr conn, const char *key)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = conn->privateData;
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 esxStorageVolLookupByPath(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;
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;
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;
fileInfo = fileInfo->_next) {
VIR_FREE(datastorePath);
if (length < 1) {
if (VIR_STRDUP(volumeName, fileInfo->path) < 0)
goto cleanup;
} else if (virAsprintf(&volumeName, "%s/%s",
directoryAndFileName,
fileInfo->path) < 0) {
goto cleanup;
}
if (virAsprintf(&datastorePath, "[%s] %s", datastoreName,
volumeName) < 0)
goto cleanup;
if (!esxVI_VmDiskFileInfo_DynamicCast(fileInfo)) {
/* 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
esxStorageVolCreateXML(virStoragePoolPtr pool,
const char *xmldesc,
unsigned int flags)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->privateData;
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, 0);
if (!def)
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 || *def->name == '/' || tmp[1] == '\0') {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Volume name '%s' doesn't have expected format "
"'<directory>/<file>'"), 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)
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)
goto cleanup;
fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
strlen(unescapedDirectoryName) + 1);
if (!fileName)
goto cleanup;
if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
directoryName) < 0)
goto cleanup;
if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
fileName) < 0)
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) {
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 ... */
conf: track sizes directly in source struct One of the features of qcow2 is that a wrapper file can have more capacity than its backing file from the guest's perspective; what's more, sparse files make tracking allocation of both the active and backing file worthwhile. As such, it makes more sense to show allocation numbers for each file in a chain, and not just the top-level file. This sets up the fields for the tracking, although it does not modify XML to display any new information. * src/util/virstoragefile.h (_virStorageSource): Add fields. * src/conf/storage_conf.h (_virStorageVolDef): Drop redundant fields. * src/storage/storage_backend.c (virStorageBackendCreateBlockFrom) (createRawFile, virStorageBackendCreateQemuImgCmd) (virStorageBackendCreateQcowCreate): Update clients. * src/storage/storage_driver.c (storageVolDelete) (storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize) (storageVolWipeInternal, storageVolGetInfo): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendProbeTarget) (virStorageBackendFileSystemRefresh) (virStorageBackendFileSystemVolResize) (virStorageBackendFileSystemVolRefresh): Likewise. * src/storage/storage_backend_logical.c (virStorageBackendLogicalMakeVol) (virStorageBackendLogicalCreateVol): Likewise. * src/storage/storage_backend_scsi.c (virStorageBackendSCSINewLun): Likewise. * src/storage/storage_backend_mpath.c (virStorageBackendMpathNewVol): Likewise. * src/storage/storage_backend_rbd.c (volStorageBackendRBDRefreshVolInfo) (virStorageBackendRBDCreateImage): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskMakeDataVol) (virStorageBackendDiskCreateVol): Likewise. * src/storage/storage_backend_sheepdog.c (virStorageBackendSheepdogBuildVol) (virStorageBackendSheepdogParseVdiList): Likewise. * src/storage/storage_backend_gluster.c (virStorageBackendGlusterRefreshVol): Likewise. * src/conf/storage_conf.c (virStorageVolDefFormat) (virStorageVolDefParseXML): Likewise. * src/test/test_driver.c (testOpenVolumesForPool) (testStorageVolCreateXML, testStorageVolCreateXMLFrom) (testStorageVolDelete, testStorageVolGetInfo): Likewise. * src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc): Likewise. * src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc) (esxStorageVolCreateXML): Likewise. * src/parallels/parallels_driver.c (parallelsAddHddByVolume): Likewise. * src/parallels/parallels_storage.c (parallelsDiskDescParseNode) (parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom) (parallelsStorageVolDefRemove, parallelsStorageVolGetInfo): Likewise. * src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML) (vboxStorageVolGetXMLDesc): Likewise. * tests/storagebackendsheepdogtest.c (test_vdi_list_parser): Likewise. * src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
if (def->target.allocation == def->target.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";
conf: track sizes directly in source struct One of the features of qcow2 is that a wrapper file can have more capacity than its backing file from the guest's perspective; what's more, sparse files make tracking allocation of both the active and backing file worthwhile. As such, it makes more sense to show allocation numbers for each file in a chain, and not just the top-level file. This sets up the fields for the tracking, although it does not modify XML to display any new information. * src/util/virstoragefile.h (_virStorageSource): Add fields. * src/conf/storage_conf.h (_virStorageVolDef): Drop redundant fields. * src/storage/storage_backend.c (virStorageBackendCreateBlockFrom) (createRawFile, virStorageBackendCreateQemuImgCmd) (virStorageBackendCreateQcowCreate): Update clients. * src/storage/storage_driver.c (storageVolDelete) (storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize) (storageVolWipeInternal, storageVolGetInfo): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendProbeTarget) (virStorageBackendFileSystemRefresh) (virStorageBackendFileSystemVolResize) (virStorageBackendFileSystemVolRefresh): Likewise. * src/storage/storage_backend_logical.c (virStorageBackendLogicalMakeVol) (virStorageBackendLogicalCreateVol): Likewise. * src/storage/storage_backend_scsi.c (virStorageBackendSCSINewLun): Likewise. * src/storage/storage_backend_mpath.c (virStorageBackendMpathNewVol): Likewise. * src/storage/storage_backend_rbd.c (volStorageBackendRBDRefreshVolInfo) (virStorageBackendRBDCreateImage): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskMakeDataVol) (virStorageBackendDiskCreateVol): Likewise. * src/storage/storage_backend_sheepdog.c (virStorageBackendSheepdogBuildVol) (virStorageBackendSheepdogParseVdiList): Likewise. * src/storage/storage_backend_gluster.c (virStorageBackendGlusterRefreshVol): Likewise. * src/conf/storage_conf.c (virStorageVolDefFormat) (virStorageVolDefParseXML): Likewise. * src/test/test_driver.c (testOpenVolumesForPool) (testStorageVolCreateXML, testStorageVolCreateXMLFrom) (testStorageVolDelete, testStorageVolGetInfo): Likewise. * src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc): Likewise. * src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc) (esxStorageVolCreateXML): Likewise. * src/parallels/parallels_driver.c (parallelsAddHddByVolume): Likewise. * src/parallels/parallels_storage.c (parallelsDiskDescParseNode) (parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom) (parallelsStorageVolDefRemove, parallelsStorageVolGetInfo): Likewise. * src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML) (vboxStorageVolGetXMLDesc): Likewise. * tests/storagebackendsheepdogtest.c (test_vdi_list_parser): Likewise. * src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
} else if (def->target.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 =
conf: track sizes directly in source struct One of the features of qcow2 is that a wrapper file can have more capacity than its backing file from the guest's perspective; what's more, sparse files make tracking allocation of both the active and backing file worthwhile. As such, it makes more sense to show allocation numbers for each file in a chain, and not just the top-level file. This sets up the fields for the tracking, although it does not modify XML to display any new information. * src/util/virstoragefile.h (_virStorageSource): Add fields. * src/conf/storage_conf.h (_virStorageVolDef): Drop redundant fields. * src/storage/storage_backend.c (virStorageBackendCreateBlockFrom) (createRawFile, virStorageBackendCreateQemuImgCmd) (virStorageBackendCreateQcowCreate): Update clients. * src/storage/storage_driver.c (storageVolDelete) (storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize) (storageVolWipeInternal, storageVolGetInfo): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendProbeTarget) (virStorageBackendFileSystemRefresh) (virStorageBackendFileSystemVolResize) (virStorageBackendFileSystemVolRefresh): Likewise. * src/storage/storage_backend_logical.c (virStorageBackendLogicalMakeVol) (virStorageBackendLogicalCreateVol): Likewise. * src/storage/storage_backend_scsi.c (virStorageBackendSCSINewLun): Likewise. * src/storage/storage_backend_mpath.c (virStorageBackendMpathNewVol): Likewise. * src/storage/storage_backend_rbd.c (volStorageBackendRBDRefreshVolInfo) (virStorageBackendRBDCreateImage): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskMakeDataVol) (virStorageBackendDiskCreateVol): Likewise. * src/storage/storage_backend_sheepdog.c (virStorageBackendSheepdogBuildVol) (virStorageBackendSheepdogParseVdiList): Likewise. * src/storage/storage_backend_gluster.c (virStorageBackendGlusterRefreshVol): Likewise. * src/conf/storage_conf.c (virStorageVolDefFormat) (virStorageVolDefParseXML): Likewise. * src/test/test_driver.c (testOpenVolumesForPool) (testStorageVolCreateXML, testStorageVolCreateXMLFrom) (testStorageVolDelete, testStorageVolGetInfo): Likewise. * src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc): Likewise. * src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc) (esxStorageVolCreateXML): Likewise. * src/parallels/parallels_driver.c (parallelsAddHddByVolume): Likewise. * src/parallels/parallels_storage.c (parallelsDiskDescParseNode) (parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom) (parallelsStorageVolDefRemove, parallelsStorageVolGetInfo): Likewise. * src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML) (vboxStorageVolGetXMLDesc): Likewise. * tests/storagebackendsheepdogtest.c (test_vdi_list_parser): Likewise. * src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
VIR_DIV_UP(def->target.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)
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 (VIR_STRDUP(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) {
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
esxStorageVolCreateXMLFrom(virStoragePoolPtr pool,
const char *xmldesc,
virStorageVolPtr sourceVolume,
unsigned int flags)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->privateData;
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)
goto cleanup;
/* Parse config */
def = virStorageVolDefParseString(&poolDef, xmldesc, 0);
if (!def)
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 || *def->name == '/' || tmp[1] == '\0') {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Volume name '%s' doesn't have expected format "
"'<directory>/<file>'"), 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)
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)
goto cleanup;
fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
strlen(unescapedDirectoryName) + 1);
if (!fileName)
goto cleanup;
if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
directoryName) < 0)
goto cleanup;
if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
fileName) < 0)
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) {
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)
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 (VIR_STRDUP(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
esxStorageVolDelete(virStorageVolPtr volume, unsigned int flags)
{
int result = -1;
esxPrivate *priv = volume->conn->privateData;
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)
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
esxStorageVolWipe(virStorageVolPtr volume, unsigned int flags)
{
int result = -1;
esxPrivate *priv = volume->conn->privateData;
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)
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
esxStorageVolGetInfo(virStorageVolPtr volume,
virStorageVolInfoPtr info)
{
int result = -1;
esxPrivate *priv = volume->conn->privateData;
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)
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) {
/* 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 *
esxStorageVolGetXMLDesc(virStorageVolPtr volume,
unsigned int flags)
{
esxPrivate *priv = volume->conn->privateData;
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)
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) {
/* Scale from kilobyte to byte */
conf: track sizes directly in source struct One of the features of qcow2 is that a wrapper file can have more capacity than its backing file from the guest's perspective; what's more, sparse files make tracking allocation of both the active and backing file worthwhile. As such, it makes more sense to show allocation numbers for each file in a chain, and not just the top-level file. This sets up the fields for the tracking, although it does not modify XML to display any new information. * src/util/virstoragefile.h (_virStorageSource): Add fields. * src/conf/storage_conf.h (_virStorageVolDef): Drop redundant fields. * src/storage/storage_backend.c (virStorageBackendCreateBlockFrom) (createRawFile, virStorageBackendCreateQemuImgCmd) (virStorageBackendCreateQcowCreate): Update clients. * src/storage/storage_driver.c (storageVolDelete) (storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize) (storageVolWipeInternal, storageVolGetInfo): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendProbeTarget) (virStorageBackendFileSystemRefresh) (virStorageBackendFileSystemVolResize) (virStorageBackendFileSystemVolRefresh): Likewise. * src/storage/storage_backend_logical.c (virStorageBackendLogicalMakeVol) (virStorageBackendLogicalCreateVol): Likewise. * src/storage/storage_backend_scsi.c (virStorageBackendSCSINewLun): Likewise. * src/storage/storage_backend_mpath.c (virStorageBackendMpathNewVol): Likewise. * src/storage/storage_backend_rbd.c (volStorageBackendRBDRefreshVolInfo) (virStorageBackendRBDCreateImage): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskMakeDataVol) (virStorageBackendDiskCreateVol): Likewise. * src/storage/storage_backend_sheepdog.c (virStorageBackendSheepdogBuildVol) (virStorageBackendSheepdogParseVdiList): Likewise. * src/storage/storage_backend_gluster.c (virStorageBackendGlusterRefreshVol): Likewise. * src/conf/storage_conf.c (virStorageVolDefFormat) (virStorageVolDefParseXML): Likewise. * src/test/test_driver.c (testOpenVolumesForPool) (testStorageVolCreateXML, testStorageVolCreateXMLFrom) (testStorageVolDelete, testStorageVolGetInfo): Likewise. * src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc): Likewise. * src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc) (esxStorageVolCreateXML): Likewise. * src/parallels/parallels_driver.c (parallelsAddHddByVolume): Likewise. * src/parallels/parallels_storage.c (parallelsDiskDescParseNode) (parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom) (parallelsStorageVolDefRemove, parallelsStorageVolGetInfo): Likewise. * src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML) (vboxStorageVolGetXMLDesc): Likewise. * tests/storagebackendsheepdogtest.c (test_vdi_list_parser): Likewise. * src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
def.target.capacity = vmDiskFileInfo->capacityKb->value * 1024;
def.target.allocation = vmDiskFileInfo->fileSize->value;
def.target.format = VIR_STORAGE_FILE_VMDK;
} else if (isoImageFileInfo) {
conf: track sizes directly in source struct One of the features of qcow2 is that a wrapper file can have more capacity than its backing file from the guest's perspective; what's more, sparse files make tracking allocation of both the active and backing file worthwhile. As such, it makes more sense to show allocation numbers for each file in a chain, and not just the top-level file. This sets up the fields for the tracking, although it does not modify XML to display any new information. * src/util/virstoragefile.h (_virStorageSource): Add fields. * src/conf/storage_conf.h (_virStorageVolDef): Drop redundant fields. * src/storage/storage_backend.c (virStorageBackendCreateBlockFrom) (createRawFile, virStorageBackendCreateQemuImgCmd) (virStorageBackendCreateQcowCreate): Update clients. * src/storage/storage_driver.c (storageVolDelete) (storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize) (storageVolWipeInternal, storageVolGetInfo): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendProbeTarget) (virStorageBackendFileSystemRefresh) (virStorageBackendFileSystemVolResize) (virStorageBackendFileSystemVolRefresh): Likewise. * src/storage/storage_backend_logical.c (virStorageBackendLogicalMakeVol) (virStorageBackendLogicalCreateVol): Likewise. * src/storage/storage_backend_scsi.c (virStorageBackendSCSINewLun): Likewise. * src/storage/storage_backend_mpath.c (virStorageBackendMpathNewVol): Likewise. * src/storage/storage_backend_rbd.c (volStorageBackendRBDRefreshVolInfo) (virStorageBackendRBDCreateImage): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskMakeDataVol) (virStorageBackendDiskCreateVol): Likewise. * src/storage/storage_backend_sheepdog.c (virStorageBackendSheepdogBuildVol) (virStorageBackendSheepdogParseVdiList): Likewise. * src/storage/storage_backend_gluster.c (virStorageBackendGlusterRefreshVol): Likewise. * src/conf/storage_conf.c (virStorageVolDefFormat) (virStorageVolDefParseXML): Likewise. * src/test/test_driver.c (testOpenVolumesForPool) (testStorageVolCreateXML, testStorageVolCreateXMLFrom) (testStorageVolDelete, testStorageVolGetInfo): Likewise. * src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc): Likewise. * src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc) (esxStorageVolCreateXML): Likewise. * src/parallels/parallels_driver.c (parallelsAddHddByVolume): Likewise. * src/parallels/parallels_storage.c (parallelsDiskDescParseNode) (parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom) (parallelsStorageVolDefRemove, parallelsStorageVolGetInfo): Likewise. * src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML) (vboxStorageVolGetXMLDesc): Likewise. * tests/storagebackendsheepdogtest.c (test_vdi_list_parser): Likewise. * src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
def.target.capacity = fileInfo->fileSize->value;
def.target.allocation = fileInfo->fileSize->value;
def.target.format = VIR_STORAGE_FILE_ISO;
} else if (floppyImageFileInfo) {
conf: track sizes directly in source struct One of the features of qcow2 is that a wrapper file can have more capacity than its backing file from the guest's perspective; what's more, sparse files make tracking allocation of both the active and backing file worthwhile. As such, it makes more sense to show allocation numbers for each file in a chain, and not just the top-level file. This sets up the fields for the tracking, although it does not modify XML to display any new information. * src/util/virstoragefile.h (_virStorageSource): Add fields. * src/conf/storage_conf.h (_virStorageVolDef): Drop redundant fields. * src/storage/storage_backend.c (virStorageBackendCreateBlockFrom) (createRawFile, virStorageBackendCreateQemuImgCmd) (virStorageBackendCreateQcowCreate): Update clients. * src/storage/storage_driver.c (storageVolDelete) (storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize) (storageVolWipeInternal, storageVolGetInfo): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendProbeTarget) (virStorageBackendFileSystemRefresh) (virStorageBackendFileSystemVolResize) (virStorageBackendFileSystemVolRefresh): Likewise. * src/storage/storage_backend_logical.c (virStorageBackendLogicalMakeVol) (virStorageBackendLogicalCreateVol): Likewise. * src/storage/storage_backend_scsi.c (virStorageBackendSCSINewLun): Likewise. * src/storage/storage_backend_mpath.c (virStorageBackendMpathNewVol): Likewise. * src/storage/storage_backend_rbd.c (volStorageBackendRBDRefreshVolInfo) (virStorageBackendRBDCreateImage): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskMakeDataVol) (virStorageBackendDiskCreateVol): Likewise. * src/storage/storage_backend_sheepdog.c (virStorageBackendSheepdogBuildVol) (virStorageBackendSheepdogParseVdiList): Likewise. * src/storage/storage_backend_gluster.c (virStorageBackendGlusterRefreshVol): Likewise. * src/conf/storage_conf.c (virStorageVolDefFormat) (virStorageVolDefParseXML): Likewise. * src/test/test_driver.c (testOpenVolumesForPool) (testStorageVolCreateXML, testStorageVolCreateXMLFrom) (testStorageVolDelete, testStorageVolGetInfo): Likewise. * src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc): Likewise. * src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc) (esxStorageVolCreateXML): Likewise. * src/parallels/parallels_driver.c (parallelsAddHddByVolume): Likewise. * src/parallels/parallels_storage.c (parallelsDiskDescParseNode) (parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom) (parallelsStorageVolDefRemove, parallelsStorageVolGetInfo): Likewise. * src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML) (vboxStorageVolGetXMLDesc): Likewise. * tests/storagebackendsheepdogtest.c (test_vdi_list_parser): Likewise. * src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
def.target.capacity = fileInfo->fileSize->value;
def.target.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 *
esxStorageVolGetPath(virStorageVolPtr volume)
{
char *path;
ignore_value(virAsprintf(&path, "[%s] %s", volume->pool, volume->name));
return path;
}
virStorageDriver esxStorageBackendVMFS = {
.connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 0.8.2 */
.connectListStoragePools = esxConnectListStoragePools, /* 0.8.2 */
.storagePoolLookupByName = esxStoragePoolLookupByName, /* 0.8.2 */
.storagePoolLookupByUUID = esxStoragePoolLookupByUUID, /* 0.8.2 */
.storagePoolRefresh = esxStoragePoolRefresh, /* 0.8.2 */
.storagePoolGetInfo = esxStoragePoolGetInfo, /* 0.8.2 */
.storagePoolGetXMLDesc = esxStoragePoolGetXMLDesc, /* 0.8.2 */
.storagePoolNumOfVolumes = esxStoragePoolNumOfVolumes, /* 0.8.4 */
.storagePoolListVolumes = esxStoragePoolListVolumes, /* 0.8.4 */
.storageVolLookupByName = esxStorageVolLookupByName, /* 0.8.4 */
.storageVolLookupByPath = esxStorageVolLookupByPath, /* 0.8.4 */
.storageVolLookupByKey = esxStorageVolLookupByKey, /* 0.8.4 */
.storageVolCreateXML = esxStorageVolCreateXML, /* 0.8.4 */
.storageVolCreateXMLFrom = esxStorageVolCreateXMLFrom, /* 0.8.7 */
.storageVolDelete = esxStorageVolDelete, /* 0.8.7 */
.storageVolWipe = esxStorageVolWipe, /* 0.8.7 */
.storageVolGetInfo = esxStorageVolGetInfo, /* 0.8.4 */
.storageVolGetXMLDesc = esxStorageVolGetXMLDesc, /* 0.8.4 */
.storageVolGetPath = esxStorageVolGetPath, /* 0.8.4 */
};