libvirt/src/esx/esx_storage_driver.c

1037 lines
30 KiB
C
Raw Normal View History

/*
* esx_storage_driver.c: storage driver functions for managing VMware ESX
* host storage
*
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
* Copyright (C) 2010 Red Hat, Inc.
* Copyright (C) 2010 Matthias Bolte <matthias.bolte@googlemail.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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include "md5.h"
#include "verify.h"
#include "internal.h"
#include "util.h"
#include "memory.h"
#include "logging.h"
#include "uuid.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"
#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 virDrvOpenStatus
esxStorageOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED)
{
if (conn->driver->no != VIR_DRV_ESX) {
return VIR_DRV_OPEN_DECLINED;
}
conn->storagePrivateData = conn->privateData;
return VIR_DRV_OPEN_SUCCESS;
}
static int
esxStorageClose(virConnectPtr conn)
{
conn->storagePrivateData = NULL;
return 0;
}
static int
esxNumberOfStoragePools(virConnectPtr conn)
{
int count = 0;
esxPrivate *priv = conn->storagePrivateData;
esxVI_ObjectContent *datastoreList = NULL;
esxVI_ObjectContent *datastore = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
}
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
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;
if (names == NULL || maxnames < 0) {
ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
return -1;
}
if (maxnames == 0) {
return 0;
}
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
}
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 int
esxNumberOfDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* ESX storage pools are always active */
return 0;
}
static int
esxListDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
char **const names ATTRIBUTE_UNUSED,
int maxnames ATTRIBUTE_UNUSED)
{
/* ESX storage pools are always active */
return 0;
}
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;
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
}
if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore,
esxVI_Occurrence_RequiredItem) < 0) {
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) < 0) {
goto cleanup;
}
md5_buffer(hostMount->mountInfo->path,
strlen(hostMount->mountInfo->path), md5);
pool = virGetStoragePool(conn, name, md5);
cleanup:
esxVI_ObjectContent_Free(&datastore);
esxVI_DatastoreHostMount_Free(&hostMount);
return pool;
}
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 */
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;
}
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 (datastore == NULL) {
virUUIDFormat(uuid, uuid_string);
ESX_VI_ERROR(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);
cleanup:
esxVI_String_Free(&propertyNameList);
esxVI_ObjectContent_Free(&datastoreList);
esxVI_DatastoreHostMount_Free(&hostMount);
return pool;
}
static virStoragePoolPtr
esxStoragePoolLookupByVolume(virStorageVolPtr volume)
{
return esxStoragePoolLookupByName(volume->conn, volume->pool);
}
static int
esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
{
int result = -1;
esxPrivate *priv = pool->conn->storagePrivateData;
esxVI_ObjectContent *datastore = NULL;
virCheckFlags(0, -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;
}
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;
memset(info, 0, sizeof (*info));
if (esxVI_EnsureSession(priv->primary) < 0) {
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;
}
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;
virCheckFlags(0, NULL);
memset(&def, 0, sizeof (def));
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) {
def.type = VIR_STORAGE_POOL_NETFS;
def.source.host.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 {
ESX_ERROR(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 {
ESX_ERROR(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
esxStoragePoolGetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
int *autostart)
{
/* ESX storage pools are always active */
*autostart = 1;
return 0;
}
static int
esxStoragePoolSetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
int autostart)
{
/* Just accept autostart activation, but fail on autostart deactivation */
autostart = (autostart != 0);
if (! autostart) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot deactivate storage pool autostart"));
return -1;
}
return 0;
}
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;
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;
}
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 *datastoreName = NULL;
char *directoryName = NULL;
char *fileName = NULL;
char *prefix = NULL;
int count = 0;
int i;
if (names == NULL || maxnames < 0) {
ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
return -1;
}
if (maxnames == 0) {
return 0;
}
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(datastoreName);
VIR_FREE(directoryName);
VIR_FREE(fileName);
VIR_FREE(prefix);
if (esxUtil_ParseDatastorePath(searchResults->folderPath, &datastoreName,
&directoryName, &fileName) < 0) {
goto cleanup;
}
if (directoryName != NULL) {
if (virAsprintf(&prefix, "%s/%s", directoryName, fileName) < 0) {
virReportOOMError();
goto cleanup;
}
} else {
prefix = strdup(fileName);
if (prefix == NULL) {
virReportOOMError();
goto cleanup;
}
}
for (fileInfo = searchResults->file; fileInfo != NULL;
fileInfo = fileInfo->_next) {
if (*prefix == '\0') {
names[count] = strdup(fileInfo->path);
if (names[count] == NULL) {
virReportOOMError();
goto cleanup;
}
} else if (virAsprintf(&names[count], "%s/%s", prefix,
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(datastoreName);
VIR_FREE(directoryName);
VIR_FREE(fileName);
VIR_FREE(prefix);
return count;
}
static virStorageVolPtr
esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->storagePrivateData;
char *datastorePath = NULL;
esxVI_FileInfo *fileInfo = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
}
if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) {
virReportOOMError();
goto cleanup;
}
if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
&fileInfo,
esxVI_Occurrence_RequiredItem) < 0) {
goto cleanup;
}
volume = virGetStorageVol(pool->conn, pool->name, name, datastorePath);
cleanup:
VIR_FREE(datastorePath);
esxVI_FileInfo_Free(&fileInfo);
return volume;
}
static virStorageVolPtr
esxStorageVolumeLookupByKeyOrPath(virConnectPtr conn, const char *keyOrPath)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = conn->storagePrivateData;
char *datastoreName = NULL;
char *directoryName = NULL;
char *fileName = NULL;
char *volumeName = NULL;
esxVI_FileInfo *fileInfo = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
}
if (esxUtil_ParseDatastorePath(keyOrPath, &datastoreName, &directoryName,
&fileName) < 0) {
goto cleanup;
}
if (directoryName != NULL) {
if (virAsprintf(&volumeName, "%s/%s", directoryName, fileName) < 0) {
virReportOOMError();
goto cleanup;
}
} else {
volumeName = strdup(fileName);
if (volumeName == NULL) {
virReportOOMError();
goto cleanup;
}
}
if (esxVI_LookupFileInfoByDatastorePath(priv->primary, keyOrPath, &fileInfo,
esxVI_Occurrence_RequiredItem) < 0) {
goto cleanup;
}
volume = virGetStorageVol(conn, datastoreName, volumeName, keyOrPath);
cleanup:
VIR_FREE(datastoreName);
VIR_FREE(directoryName);
VIR_FREE(fileName);
VIR_FREE(volumeName);
esxVI_FileInfo_Free(&fileInfo);
return volume;
}
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;
memset(info, 0, sizeof (*info));
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,
&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;
}
static char *
esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags)
{
esxPrivate *priv = volume->conn->storagePrivateData;
esxVI_String *propertyNameList = NULL;
esxVI_ObjectContent *datastore = NULL;
esxVI_DynamicProperty *dynamicProperty = NULL;
esxVI_DatastoreInfo *datastoreInfo = NULL;
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 (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
}
/* Lookup storage pool type */
if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
esxVI_LookupDatastoreByName(priv->primary, volume->pool,
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) {
pool.type = VIR_STORAGE_POOL_DIR;
} else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
pool.type = VIR_STORAGE_POOL_NETFS;
} else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
pool.type = VIR_STORAGE_POOL_FS;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
_("DatastoreInfo has unexpected type"));
goto cleanup;
}
/* Lookup file info */
if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
virReportOOMError();
goto cleanup;
}
if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
&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;
def.key = datastorePath;
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 {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("File '%s' has unknown type"), datastorePath);
goto cleanup;
}
xml = virStorageVolDefFormat(&pool, &def);
cleanup:
esxVI_String_Free(&propertyNameList);
esxVI_ObjectContent_Free(&datastore);
esxVI_DatastoreInfo_Free(&datastoreInfo);
VIR_FREE(datastorePath);
esxVI_FileInfo_Free(&fileInfo);
return xml;
}
static char *
esxStorageVolumeGetPath(virStorageVolPtr volume)
{
char *path;
if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) {
virReportOOMError();
return NULL;
}
return path;
}
static int
esxStoragePoolIsActive(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
{
/* ESX storage pools are always active */
return 1;
}
static int
esxStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
{
/* ESX has no concept of transient pools, so all of them are persistent */
return 1;
}
static virStorageDriver esxStorageDriver = {
"ESX", /* name */
esxStorageOpen, /* open */
esxStorageClose, /* close */
esxNumberOfStoragePools, /* numOfPools */
esxListStoragePools, /* listPools */
esxNumberOfDefinedStoragePools, /* numOfDefinedPools */
esxListDefinedStoragePools, /* listDefinedPools */
NULL, /* findPoolSources */
esxStoragePoolLookupByName, /* poolLookupByName */
esxStoragePoolLookupByUUID, /* poolLookupByUUID */
esxStoragePoolLookupByVolume, /* poolLookupByVolume */
NULL, /* poolCreateXML */
NULL, /* poolDefineXML */
NULL, /* poolBuild */
NULL, /* poolUndefine */
NULL, /* poolCreate */
NULL, /* poolDestroy */
NULL, /* poolDelete */
esxStoragePoolRefresh, /* poolRefresh */
esxStoragePoolGetInfo, /* poolGetInfo */
esxStoragePoolGetXMLDesc, /* poolGetXMLDesc */
esxStoragePoolGetAutostart, /* poolGetAutostart */
esxStoragePoolSetAutostart, /* poolSetAutostart */
esxStoragePoolNumberOfStorageVolumes, /* poolNumOfVolumes */
esxStoragePoolListStorageVolumes, /* poolListVolumes */
esxStorageVolumeLookupByName, /* volLookupByName */
esxStorageVolumeLookupByKeyOrPath, /* volLookupByKey */
esxStorageVolumeLookupByKeyOrPath, /* volLookupByPath */
NULL, /* volCreateXML */
NULL, /* volCreateXMLFrom */
NULL, /* volDelete */
NULL, /* volWipe */
esxStorageVolumeGetInfo, /* volGetInfo */
esxStorageVolumeDumpXML, /* volGetXMLDesc */
esxStorageVolumeGetPath, /* volGetPath */
esxStoragePoolIsActive, /* poolIsActive */
esxStoragePoolIsPersistent, /* poolIsPersistent */
};
int
esxStorageRegister(void)
{
return virRegisterStorageDriver(&esxStorageDriver);
}