2010-01-15 15:01:02 +00:00
|
|
|
|
|
|
|
/*
|
2010-03-02 21:19:24 +00:00
|
|
|
* esx_storage_driver.c: storage driver functions for managing VMware ESX
|
2010-01-15 15:01:02 +00:00
|
|
|
* host storage
|
|
|
|
*
|
2010-03-01 23:38:28 +00:00
|
|
|
* Copyright (C) 2010 Red Hat, Inc.
|
2010-01-15 15:01:02 +00:00
|
|
|
* 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>
|
|
|
|
|
2010-08-08 18:45:12 +00:00
|
|
|
#include "md5.h"
|
|
|
|
#include "verify.h"
|
2010-01-15 15:01:02 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "uuid.h"
|
2010-05-18 16:11:59 +00:00
|
|
|
#include "storage_conf.h"
|
2010-08-07 22:24:29 +00:00
|
|
|
#include "storage_file.h"
|
2010-01-15 15:01:02 +00:00
|
|
|
#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
|
|
|
|
|
2010-08-08 18:45:12 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2010-01-15 15:01:02 +00:00
|
|
|
|
|
|
|
|
2010-12-06 19:40:59 +00:00
|
|
|
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 {
|
|
|
|
ESX_ERROR(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-01-15 15:01:02 +00:00
|
|
|
static virDrvOpenStatus
|
|
|
|
esxStorageOpen(virConnectPtr conn,
|
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
|
|
|
int flags ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2010-07-25 17:04:22 +00:00
|
|
|
if (conn->driver->no != VIR_DRV_ESX) {
|
2010-01-15 15:01:02 +00:00
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->storagePrivateData = conn->privateData;
|
|
|
|
|
|
|
|
return VIR_DRV_OPEN_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
esxStorageClose(virConnectPtr conn)
|
|
|
|
{
|
|
|
|
conn->storagePrivateData = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-05-18 16:11:59 +00:00
|
|
|
static int
|
|
|
|
esxNumberOfStoragePools(virConnectPtr conn)
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
esxPrivate *priv = conn->storagePrivateData;
|
|
|
|
esxVI_ObjectContent *datastoreList = NULL;
|
|
|
|
esxVI_ObjectContent *datastore = NULL;
|
|
|
|
|
2010-07-18 15:27:05 +00:00
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-07-31 21:57:42 +00:00
|
|
|
if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-07-18 15:27:05 +00:00
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxVI_String_AppendValueToList(&propertyNameList,
|
|
|
|
"summary.name") < 0 ||
|
2010-07-31 21:57:42 +00:00
|
|
|
esxVI_LookupDatastoreList(priv->primary, propertyNameList,
|
|
|
|
&datastoreList) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
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;
|
2010-08-01 20:11:38 +00:00
|
|
|
esxVI_DatastoreHostMount *hostMount = NULL;
|
2010-08-08 18:45:12 +00:00
|
|
|
unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
|
2010-05-18 16:11:59 +00:00
|
|
|
virStoragePoolPtr pool = NULL;
|
|
|
|
|
2010-07-18 15:27:05 +00:00
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-01 20:11:38 +00:00
|
|
|
if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore,
|
2010-08-01 17:53:00 +00:00
|
|
|
esxVI_Occurrence_RequiredItem) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-08-08 18:45:12 +00:00
|
|
|
* 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.
|
2010-05-18 16:11:59 +00:00
|
|
|
*
|
2010-08-08 18:45:12 +00:00
|
|
|
* 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.
|
2010-05-18 16:11:59 +00:00
|
|
|
*/
|
2010-08-01 20:11:38 +00:00
|
|
|
if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
|
|
|
|
&hostMount) < 0) {
|
|
|
|
goto cleanup;
|
2010-08-01 17:53:00 +00:00
|
|
|
}
|
|
|
|
|
2010-08-08 18:45:12 +00:00
|
|
|
md5_buffer(hostMount->mountInfo->path,
|
|
|
|
strlen(hostMount->mountInfo->path), md5);
|
2010-05-18 16:11:59 +00:00
|
|
|
|
2010-08-08 18:45:12 +00:00
|
|
|
pool = virGetStoragePool(conn, name, md5);
|
2010-05-18 16:11:59 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
esxVI_ObjectContent_Free(&datastore);
|
2010-08-01 20:11:38 +00:00
|
|
|
esxVI_DatastoreHostMount_Free(&hostMount);
|
2010-05-18 16:11:59 +00:00
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static virStoragePoolPtr
|
|
|
|
esxStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
|
|
|
|
{
|
|
|
|
esxPrivate *priv = conn->storagePrivateData;
|
|
|
|
esxVI_String *propertyNameList = NULL;
|
2010-08-08 18:45:12 +00:00
|
|
|
esxVI_ObjectContent *datastoreList = NULL;
|
2010-05-18 16:11:59 +00:00
|
|
|
esxVI_ObjectContent *datastore = NULL;
|
2010-08-08 18:45:12 +00:00
|
|
|
esxVI_DatastoreHostMount *hostMount = NULL;
|
|
|
|
unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
|
2010-05-18 16:11:59 +00:00
|
|
|
char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
|
|
|
|
char *name = NULL;
|
|
|
|
virStoragePoolPtr pool = NULL;
|
|
|
|
|
2010-07-31 21:57:42 +00:00
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
|
2010-08-08 18:45:12 +00:00
|
|
|
esxVI_LookupDatastoreList(priv->primary, propertyNameList,
|
|
|
|
&datastoreList) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-08 18:45:12 +00:00
|
|
|
for (datastore = datastoreList; datastore != NULL;
|
|
|
|
datastore = datastore->_next) {
|
|
|
|
esxVI_DatastoreHostMount_Free(&hostMount);
|
2010-08-01 17:53:00 +00:00
|
|
|
|
2010-08-08 18:45:12 +00:00
|
|
|
if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
|
|
|
|
&hostMount) < 0) {
|
2010-08-01 17:53:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-08 18:45:12 +00:00
|
|
|
md5_buffer(hostMount->mountInfo->path,
|
|
|
|
strlen(hostMount->mountInfo->path), md5);
|
|
|
|
|
|
|
|
if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) {
|
|
|
|
break;
|
2010-05-18 16:11:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (datastore == NULL) {
|
|
|
|
virUUIDFormat(uuid, uuid_string);
|
|
|
|
|
2010-08-01 17:53:00 +00:00
|
|
|
ESX_VI_ERROR(VIR_ERR_NO_STORAGE_POOL,
|
2010-05-18 16:11:59 +00:00
|
|
|
_("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);
|
2010-08-08 18:45:12 +00:00
|
|
|
esxVI_ObjectContent_Free(&datastoreList);
|
|
|
|
esxVI_DatastoreHostMount_Free(&hostMount);
|
2010-05-18 16:11:59 +00:00
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-07 22:24:29 +00:00
|
|
|
static virStoragePoolPtr
|
|
|
|
esxStoragePoolLookupByVolume(virStorageVolPtr volume)
|
|
|
|
{
|
|
|
|
return esxStoragePoolLookupByName(volume->conn, volume->pool);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-05-18 16:11:59 +00:00
|
|
|
static int
|
|
|
|
esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
|
|
|
|
{
|
|
|
|
int result = -1;
|
|
|
|
esxPrivate *priv = pool->conn->storagePrivateData;
|
|
|
|
esxVI_ObjectContent *datastore = NULL;
|
|
|
|
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2010-07-18 15:27:05 +00:00
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-07-18 15:27:05 +00:00
|
|
|
if (esxVI_LookupDatastoreByName(priv->primary, pool->name, NULL, &datastore,
|
2010-05-18 16:11:59 +00:00
|
|
|
esxVI_Occurrence_RequiredItem) < 0 ||
|
2010-07-18 15:27:05 +00:00
|
|
|
esxVI_RefreshDatastore(priv->primary, datastore->obj) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
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));
|
|
|
|
|
2010-07-18 15:27:05 +00:00
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxVI_String_AppendValueListToList(&propertyNameList,
|
|
|
|
"summary.accessible\0"
|
|
|
|
"summary.capacity\0"
|
|
|
|
"summary.freeSpace\0") < 0 ||
|
2010-07-18 15:27:05 +00:00
|
|
|
esxVI_LookupDatastoreByName(priv->primary, pool->name,
|
2010-05-18 16:11:59 +00:00
|
|
|
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;
|
2010-08-01 20:11:38 +00:00
|
|
|
esxVI_DatastoreHostMount *hostMount = NULL;
|
2010-05-18 16:11:59 +00:00
|
|
|
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));
|
|
|
|
|
2010-07-18 15:27:05 +00:00
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxVI_String_AppendValueListToList(&propertyNameList,
|
|
|
|
"summary.accessible\0"
|
|
|
|
"summary.capacity\0"
|
|
|
|
"summary.freeSpace\0"
|
|
|
|
"info\0") < 0 ||
|
2010-07-18 15:27:05 +00:00
|
|
|
esxVI_LookupDatastoreByName(priv->primary, pool->name,
|
2010-05-18 16:11:59 +00:00
|
|
|
propertyNameList, &datastore,
|
|
|
|
esxVI_Occurrence_RequiredItem) < 0 ||
|
|
|
|
esxVI_GetBoolean(datastore, "summary.accessible",
|
2010-08-01 20:11:38 +00:00
|
|
|
&accessible, esxVI_Occurrence_RequiredItem) < 0 ||
|
|
|
|
esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
|
|
|
|
&hostMount) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
def.name = pool->name;
|
|
|
|
memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
|
|
|
|
|
2010-08-01 20:11:38 +00:00
|
|
|
def.target.path = hostMount->mountInfo->path;
|
|
|
|
|
2010-05-18 16:11:59 +00:00
|
|
|
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;
|
2010-08-01 20:11:38 +00:00
|
|
|
}
|
2010-05-18 16:11:59 +00:00
|
|
|
|
2010-08-01 20:11:38 +00:00
|
|
|
for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
|
|
|
|
dynamicProperty = dynamicProperty->_next) {
|
|
|
|
if (STREQ(dynamicProperty->name, "info")) {
|
|
|
|
if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
|
|
|
|
&info) < 0) {
|
2010-05-18 16:11:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-08-01 20:11:38 +00:00
|
|
|
|
|
|
|
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;
|
2010-05-18 16:11:59 +00:00
|
|
|
} else {
|
2010-08-01 20:11:38 +00:00
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Datastore has unexpected type '%s'"),
|
|
|
|
nasInfo->nas->type);
|
2010-05-18 16:11:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-08-01 20:11:38 +00:00
|
|
|
} 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;
|
2010-05-18 16:11:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xml = virStoragePoolDefFormat(&def);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
esxVI_String_Free(&propertyNameList);
|
|
|
|
esxVI_ObjectContent_Free(&datastore);
|
2010-08-01 20:11:38 +00:00
|
|
|
esxVI_DatastoreHostMount_Free(&hostMount);
|
2010-05-18 16:11:59 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-07 22:24:29 +00:00
|
|
|
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;
|
2010-08-25 09:44:57 +00:00
|
|
|
char *directoryAndFileName = NULL;
|
|
|
|
size_t length;
|
2010-08-07 22:24:29 +00:00
|
|
|
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) {
|
2010-08-25 09:44:57 +00:00
|
|
|
VIR_FREE(directoryAndFileName);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
2010-08-25 09:44:57 +00:00
|
|
|
if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL, NULL,
|
|
|
|
&directoryAndFileName) < 0) {
|
2010-08-07 22:24:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-25 09:44:57 +00:00
|
|
|
/* Strip trailing separators */
|
|
|
|
length = strlen(directoryAndFileName);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
2010-08-25 09:44:57 +00:00
|
|
|
while (length > 0 && directoryAndFileName[length - 1] == '/') {
|
|
|
|
directoryAndFileName[length - 1] = '\0';
|
|
|
|
--length;
|
2010-08-07 22:24:29 +00:00
|
|
|
}
|
|
|
|
|
2010-08-25 09:44:57 +00:00
|
|
|
/* Build volume names */
|
2010-08-07 22:24:29 +00:00
|
|
|
for (fileInfo = searchResults->file; fileInfo != NULL;
|
|
|
|
fileInfo = fileInfo->_next) {
|
2010-08-25 09:44:57 +00:00
|
|
|
if (length < 1) {
|
2010-08-07 22:24:29 +00:00
|
|
|
names[count] = strdup(fileInfo->path);
|
|
|
|
|
|
|
|
if (names[count] == NULL) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-08-25 09:44:57 +00:00
|
|
|
} else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName,
|
2010-08-07 22:24:29 +00:00
|
|
|
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);
|
2010-08-25 09:44:57 +00:00
|
|
|
VIR_FREE(directoryAndFileName);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static virStorageVolPtr
|
|
|
|
esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name)
|
|
|
|
{
|
|
|
|
virStorageVolPtr volume = NULL;
|
|
|
|
esxPrivate *priv = pool->conn->storagePrivateData;
|
|
|
|
char *datastorePath = NULL;
|
2010-08-29 17:33:49 +00:00
|
|
|
char *key = NULL;
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:33:49 +00:00
|
|
|
if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary,
|
|
|
|
datastorePath, &key) < 0) {
|
2010-08-07 22:24:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:33:49 +00:00
|
|
|
volume = virGetStorageVol(pool->conn, pool->name, name, key);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(datastorePath);
|
2010-08-29 17:33:49 +00:00
|
|
|
VIR_FREE(key);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
return volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static virStorageVolPtr
|
2010-08-29 17:33:49 +00:00
|
|
|
esxStorageVolumeLookupByPath(virConnectPtr conn, const char *path)
|
2010-08-07 22:24:29 +00:00
|
|
|
{
|
|
|
|
virStorageVolPtr volume = NULL;
|
|
|
|
esxPrivate *priv = conn->storagePrivateData;
|
|
|
|
char *datastoreName = NULL;
|
2010-08-25 09:44:57 +00:00
|
|
|
char *directoryAndFileName = NULL;
|
2010-08-29 17:33:49 +00:00
|
|
|
char *key = NULL;
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:33:49 +00:00
|
|
|
if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL,
|
2010-08-25 09:44:57 +00:00
|
|
|
&directoryAndFileName) < 0) {
|
2010-08-07 22:24:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:33:49 +00:00
|
|
|
if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path,
|
|
|
|
&key) < 0) {
|
2010-08-07 22:24:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:33:49 +00:00
|
|
|
volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(datastoreName);
|
2010-08-25 09:44:57 +00:00
|
|
|
VIR_FREE(directoryAndFileName);
|
2010-08-29 17:33:49 +00:00
|
|
|
VIR_FREE(key);
|
|
|
|
|
|
|
|
return volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static virStorageVolPtr
|
|
|
|
esxStorageVolumeLookupByKey(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 esxStorageVolumeLookupByPath(conn, key);
|
|
|
|
}
|
|
|
|
|
2010-09-03 23:30:04 +00:00
|
|
|
if (!priv->primary->hasQueryVirtualDiskUuid) {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("QueryVirtualDiskUuid not avialable, cannot lookup storage "
|
|
|
|
"volume by UUID"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:33:49 +00:00
|
|
|
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 (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);
|
|
|
|
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);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
return volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-28 19:49:07 +00:00
|
|
|
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;
|
2010-10-12 17:37:39 +00:00
|
|
|
char *unescapedDatastorePath = NULL;
|
|
|
|
char *unescapedDirectoryName = NULL;
|
|
|
|
char *unescapedDirectoryAndFileName = NULL;
|
2010-08-28 19:49:07 +00:00
|
|
|
char *directoryName = NULL;
|
2010-10-12 17:37:39 +00:00
|
|
|
char *fileName = NULL;
|
2010-08-28 19:49:07 +00:00
|
|
|
char *datastorePathWithoutFileName = NULL;
|
2010-10-12 17:37:39 +00:00
|
|
|
char *datastorePath = NULL;
|
2010-08-28 19:49:07 +00:00
|
|
|
esxVI_FileInfo *fileInfo = NULL;
|
|
|
|
esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
|
|
|
|
esxVI_ManagedObjectReference *task = NULL;
|
|
|
|
esxVI_TaskInfoState taskInfoState;
|
2010-12-06 12:53:36 +00:00
|
|
|
char *taskInfoErrorMessage = NULL;
|
2010-08-29 17:33:49 +00:00
|
|
|
char *uuid_string = NULL;
|
2010-09-03 23:30:04 +00:00
|
|
|
char *key = NULL;
|
2010-08-28 19:49:07 +00:00
|
|
|
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
|
|
|
|
memset(&poolDef, 0, sizeof (poolDef));
|
|
|
|
|
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-12-06 19:40:59 +00:00
|
|
|
if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) {
|
|
|
|
return NULL;
|
2010-08-28 19:49:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse config */
|
|
|
|
def = virStorageVolDefParseString(&poolDef, xmldesc);
|
|
|
|
|
|
|
|
if (def == NULL) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->type != VIR_STORAGE_VOL_FILE) {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Creating non-file volumes is not supported"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Validate config */
|
|
|
|
tmp = strrchr(def->name, '/');
|
|
|
|
|
|
|
|
if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Volume name '%s' doesn't have expected format "
|
|
|
|
"'<directory>/<file>'"), def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! virFileHasSuffix(def->name, ".vmdk")) {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
|
|
|
|
def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-10-12 17:37:39 +00:00
|
|
|
if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
|
|
|
|
def->name) < 0) {
|
2010-08-28 19:49:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->target.format == VIR_STORAGE_FILE_VMDK) {
|
2010-10-12 17:37:39 +00:00
|
|
|
/* 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) {
|
2010-08-28 19:49:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
|
|
|
|
directoryName) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-10-12 17:37:39 +00:00
|
|
|
if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
|
|
|
|
fileName) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create directory, if it doesn't exist yet */
|
2010-08-28 19:49:07 +00:00
|
|
|
if (esxVI_LookupFileInfoByDatastorePath
|
|
|
|
(priv->primary, datastorePathWithoutFileName, true, &fileInfo,
|
|
|
|
esxVI_Occurrence_OptionalItem) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fileInfo == NULL) {
|
|
|
|
if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
|
|
|
|
priv->primary->datacenter->_reference,
|
|
|
|
esxVI_Boolean_True) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create VirtualDisk */
|
|
|
|
if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 ||
|
|
|
|
esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* From the vSphere API documentation about VirtualDiskType ... */
|
|
|
|
if (def->allocation == def->capacity) {
|
|
|
|
/*
|
|
|
|
* "A preallocated disk has all space allocated at creation time
|
|
|
|
* and the space is zeroed on demand as the space is used."
|
|
|
|
*/
|
|
|
|
virtualDiskSpec->diskType = (char *)"preallocated";
|
|
|
|
} else if (def->allocation == 0) {
|
|
|
|
/*
|
|
|
|
* "Space required for thin-provisioned virtual disk is allocated
|
|
|
|
* and zeroed on demand as the space is used."
|
|
|
|
*/
|
|
|
|
virtualDiskSpec->diskType = (char *)"thin";
|
|
|
|
} else {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unsupported capacity-to-allocation relation"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: The adapter type is a required parameter, but there is no
|
|
|
|
* way to let the user specify it in the volume XML config. Therefore,
|
|
|
|
* default to 'busLogic' here.
|
|
|
|
*/
|
|
|
|
virtualDiskSpec->adapterType = (char *)"busLogic";
|
|
|
|
|
2011-01-28 21:03:24 +00:00
|
|
|
virtualDiskSpec->capacityKb->value =
|
|
|
|
VIR_DIV_UP(def->capacity, 1024); /* Scale from byte to kilobyte */
|
2010-08-28 19:49:07 +00:00
|
|
|
|
|
|
|
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,
|
2010-12-06 12:53:36 +00:00
|
|
|
priv->autoAnswer, &taskInfoState,
|
|
|
|
&taskInfoErrorMessage) < 0) {
|
2010-08-28 19:49:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (taskInfoState != esxVI_TaskInfoState_Success) {
|
2010-12-06 12:53:36 +00:00
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not create volume: %s"),
|
|
|
|
taskInfoErrorMessage);
|
2010-08-28 19:49:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-08-29 17:33:49 +00:00
|
|
|
|
2010-09-03 23:30:04 +00:00
|
|
|
if (priv->primary->hasQueryVirtualDiskUuid) {
|
|
|
|
if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-08-29 17:33:49 +00:00
|
|
|
|
2010-09-03 23:30:04 +00:00
|
|
|
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;
|
|
|
|
}
|
2010-08-29 17:33:49 +00:00
|
|
|
}
|
2010-08-28 19:49:07 +00:00
|
|
|
} else {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Creation of %s volumes is not supported"),
|
|
|
|
virStorageFileFormatTypeToString(def->target.format));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-29 17:33:49 +00:00
|
|
|
volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
|
2010-08-28 19:49:07 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (virtualDiskSpec != NULL) {
|
|
|
|
virtualDiskSpec->diskType = NULL;
|
|
|
|
virtualDiskSpec->adapterType = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virStorageVolDefFree(def);
|
2010-10-12 17:37:39 +00:00
|
|
|
VIR_FREE(unescapedDatastorePath);
|
|
|
|
VIR_FREE(unescapedDirectoryName);
|
|
|
|
VIR_FREE(unescapedDirectoryAndFileName);
|
2010-08-28 19:49:07 +00:00
|
|
|
VIR_FREE(directoryName);
|
2010-10-12 17:37:39 +00:00
|
|
|
VIR_FREE(fileName);
|
2010-08-28 19:49:07 +00:00
|
|
|
VIR_FREE(datastorePathWithoutFileName);
|
2010-10-12 17:37:39 +00:00
|
|
|
VIR_FREE(datastorePath);
|
2010-08-28 19:49:07 +00:00
|
|
|
esxVI_FileInfo_Free(&fileInfo);
|
|
|
|
esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
|
|
|
|
esxVI_ManagedObjectReference_Free(&task);
|
2010-12-06 12:53:36 +00:00
|
|
|
VIR_FREE(taskInfoErrorMessage);
|
2010-08-29 17:33:49 +00:00
|
|
|
VIR_FREE(uuid_string);
|
2010-09-03 23:30:04 +00:00
|
|
|
VIR_FREE(key);
|
2010-08-28 19:49:07 +00:00
|
|
|
|
|
|
|
return volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-06 20:07:35 +00:00
|
|
|
static virStorageVolPtr
|
|
|
|
esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
|
|
|
|
virStorageVolPtr sourceVolume, unsigned int flags)
|
|
|
|
{
|
|
|
|
virStorageVolPtr volume = NULL;
|
|
|
|
esxPrivate *priv = pool->conn->storagePrivateData;
|
|
|
|
virStoragePoolDef poolDef;
|
|
|
|
char *sourceDatastorePath = NULL;
|
|
|
|
virStorageVolDefPtr def = NULL;
|
|
|
|
char *tmp;
|
|
|
|
char *unescapedDatastorePath = NULL;
|
|
|
|
char *unescapedDirectoryName = NULL;
|
|
|
|
char *unescapedDirectoryAndFileName = NULL;
|
|
|
|
char *directoryName = NULL;
|
|
|
|
char *fileName = NULL;
|
|
|
|
char *datastorePathWithoutFileName = NULL;
|
|
|
|
char *datastorePath = NULL;
|
|
|
|
esxVI_FileInfo *fileInfo = NULL;
|
|
|
|
esxVI_ManagedObjectReference *task = NULL;
|
|
|
|
esxVI_TaskInfoState taskInfoState;
|
|
|
|
char *taskInfoErrorMessage = NULL;
|
|
|
|
char *uuid_string = NULL;
|
|
|
|
char *key = NULL;
|
|
|
|
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
|
|
|
|
memset(&poolDef, 0, sizeof (poolDef));
|
|
|
|
|
|
|
|
if (esxVI_EnsureSession(priv->primary) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&sourceDatastorePath, "[%s] %s", sourceVolume->pool,
|
|
|
|
sourceVolume->name) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse config */
|
|
|
|
def = virStorageVolDefParseString(&poolDef, xmldesc);
|
|
|
|
|
|
|
|
if (def == NULL) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->type != VIR_STORAGE_VOL_FILE) {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Creating non-file volumes is not supported"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Validate config */
|
|
|
|
tmp = strrchr(def->name, '/');
|
|
|
|
|
|
|
|
if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Volume name '%s' doesn't have expected format "
|
|
|
|
"'<directory>/<file>'"), def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! virFileHasSuffix(def->name, ".vmdk")) {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
|
|
|
|
def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
|
|
|
|
def->name) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->target.format == VIR_STORAGE_FILE_VMDK) {
|
|
|
|
/* Parse and escape datastore path */
|
|
|
|
if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
|
|
|
|
&unescapedDirectoryName,
|
|
|
|
&unescapedDirectoryAndFileName) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
|
|
|
|
|
|
|
|
if (directoryName == NULL) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
|
|
|
|
strlen(unescapedDirectoryName) + 1);
|
|
|
|
|
|
|
|
if (fileName == NULL) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
|
|
|
|
directoryName) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
|
|
|
|
fileName) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create directory, if it doesn't exist yet */
|
|
|
|
if (esxVI_LookupFileInfoByDatastorePath
|
|
|
|
(priv->primary, datastorePathWithoutFileName, true, &fileInfo,
|
|
|
|
esxVI_Occurrence_OptionalItem) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fileInfo == NULL) {
|
|
|
|
if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
|
|
|
|
priv->primary->datacenter->_reference,
|
|
|
|
esxVI_Boolean_True) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy VirtualDisk */
|
|
|
|
if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath,
|
|
|
|
priv->primary->datacenter->_reference,
|
|
|
|
datastorePath,
|
|
|
|
priv->primary->datacenter->_reference,
|
|
|
|
NULL, esxVI_Boolean_False, &task) < 0 ||
|
|
|
|
esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
|
|
|
|
esxVI_Occurrence_None,
|
|
|
|
priv->autoAnswer, &taskInfoState,
|
|
|
|
&taskInfoErrorMessage) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (taskInfoState != esxVI_TaskInfoState_Success) {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"),
|
|
|
|
taskInfoErrorMessage);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->primary->hasQueryVirtualDiskUuid) {
|
|
|
|
if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
|
|
|
|
priv->primary->datacenter->_reference,
|
|
|
|
&uuid_string) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Fall back to the path as key */
|
|
|
|
if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Creation of %s volumes is not supported"),
|
|
|
|
virStorageFileFormatTypeToString(def->target.format));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(sourceDatastorePath);
|
|
|
|
virStorageVolDefFree(def);
|
|
|
|
VIR_FREE(unescapedDatastorePath);
|
|
|
|
VIR_FREE(unescapedDirectoryName);
|
|
|
|
VIR_FREE(unescapedDirectoryAndFileName);
|
|
|
|
VIR_FREE(directoryName);
|
|
|
|
VIR_FREE(fileName);
|
|
|
|
VIR_FREE(datastorePathWithoutFileName);
|
|
|
|
VIR_FREE(datastorePath);
|
|
|
|
esxVI_FileInfo_Free(&fileInfo);
|
|
|
|
esxVI_ManagedObjectReference_Free(&task);
|
|
|
|
VIR_FREE(taskInfoErrorMessage);
|
|
|
|
VIR_FREE(uuid_string);
|
|
|
|
VIR_FREE(key);
|
|
|
|
|
|
|
|
return volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-22 15:45:50 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
virCheckFlags(0, -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->autoAnswer,
|
|
|
|
&taskInfoState, &taskInfoErrorMessage) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (taskInfoState != esxVI_TaskInfoState_Success) {
|
|
|
|
ESX_ERROR(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-22 16:24:45 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
virCheckFlags(0, -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->autoAnswer,
|
|
|
|
&taskInfoState, &taskInfoErrorMessage) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (taskInfoState != esxVI_TaskInfoState_Success) {
|
|
|
|
ESX_ERROR(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-07 22:24:29 +00:00
|
|
|
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,
|
2010-08-28 19:49:07 +00:00
|
|
|
false, &fileInfo,
|
2010-08-07 22:24:29 +00:00
|
|
|
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;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-12-06 19:40:59 +00:00
|
|
|
if (esxStoragePoolLookupType(priv->primary, volume->pool, &pool.type) < 0) {
|
|
|
|
return NULL;
|
2010-08-07 22:24:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Lookup file info */
|
|
|
|
if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
|
2010-08-28 19:49:07 +00:00
|
|
|
false, &fileInfo,
|
2010-08-07 22:24:29 +00:00
|
|
|
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;
|
2010-08-29 17:33:49 +00:00
|
|
|
|
|
|
|
if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath,
|
|
|
|
&def.key) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-07 22:24:29 +00:00
|
|
|
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:
|
|
|
|
VIR_FREE(datastorePath);
|
|
|
|
esxVI_FileInfo_Free(&fileInfo);
|
2010-08-29 17:33:49 +00:00
|
|
|
VIR_FREE(def.key);
|
2010-08-07 22:24:29 +00:00
|
|
|
|
|
|
|
return xml;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
esxStorageVolumeGetPath(virStorageVolPtr volume)
|
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-05-18 16:11:59 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-07 22:24:29 +00:00
|
|
|
|
2010-01-15 15:01:02 +00:00
|
|
|
static virStorageDriver esxStorageDriver = {
|
|
|
|
"ESX", /* name */
|
|
|
|
esxStorageOpen, /* open */
|
|
|
|
esxStorageClose, /* close */
|
2010-05-18 16:11:59 +00:00
|
|
|
esxNumberOfStoragePools, /* numOfPools */
|
|
|
|
esxListStoragePools, /* listPools */
|
|
|
|
esxNumberOfDefinedStoragePools, /* numOfDefinedPools */
|
|
|
|
esxListDefinedStoragePools, /* listDefinedPools */
|
2010-01-15 15:01:02 +00:00
|
|
|
NULL, /* findPoolSources */
|
2010-05-18 16:11:59 +00:00
|
|
|
esxStoragePoolLookupByName, /* poolLookupByName */
|
|
|
|
esxStoragePoolLookupByUUID, /* poolLookupByUUID */
|
2010-08-07 22:24:29 +00:00
|
|
|
esxStoragePoolLookupByVolume, /* poolLookupByVolume */
|
2010-01-15 15:01:02 +00:00
|
|
|
NULL, /* poolCreateXML */
|
|
|
|
NULL, /* poolDefineXML */
|
|
|
|
NULL, /* poolBuild */
|
|
|
|
NULL, /* poolUndefine */
|
|
|
|
NULL, /* poolCreate */
|
|
|
|
NULL, /* poolDestroy */
|
|
|
|
NULL, /* poolDelete */
|
2010-05-18 16:11:59 +00:00
|
|
|
esxStoragePoolRefresh, /* poolRefresh */
|
|
|
|
esxStoragePoolGetInfo, /* poolGetInfo */
|
|
|
|
esxStoragePoolGetXMLDesc, /* poolGetXMLDesc */
|
|
|
|
esxStoragePoolGetAutostart, /* poolGetAutostart */
|
|
|
|
esxStoragePoolSetAutostart, /* poolSetAutostart */
|
2010-08-07 22:24:29 +00:00
|
|
|
esxStoragePoolNumberOfStorageVolumes, /* poolNumOfVolumes */
|
|
|
|
esxStoragePoolListStorageVolumes, /* poolListVolumes */
|
|
|
|
esxStorageVolumeLookupByName, /* volLookupByName */
|
2010-08-29 17:33:49 +00:00
|
|
|
esxStorageVolumeLookupByKey, /* volLookupByKey */
|
|
|
|
esxStorageVolumeLookupByPath, /* volLookupByPath */
|
2010-08-28 19:49:07 +00:00
|
|
|
esxStorageVolumeCreateXML, /* volCreateXML */
|
2010-12-06 20:07:35 +00:00
|
|
|
esxStorageVolumeCreateXMLFrom, /* volCreateXMLFrom */
|
2010-12-22 15:45:50 +00:00
|
|
|
esxStorageVolumeDelete, /* volDelete */
|
2010-12-22 16:24:45 +00:00
|
|
|
esxStorageVolumeWipe, /* volWipe */
|
2010-08-07 22:24:29 +00:00
|
|
|
esxStorageVolumeGetInfo, /* volGetInfo */
|
|
|
|
esxStorageVolumeDumpXML, /* volGetXMLDesc */
|
|
|
|
esxStorageVolumeGetPath, /* volGetPath */
|
2010-05-18 16:11:59 +00:00
|
|
|
esxStoragePoolIsActive, /* poolIsActive */
|
|
|
|
esxStoragePoolIsPersistent, /* poolIsPersistent */
|
2010-01-15 15:01:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
esxStorageRegister(void)
|
|
|
|
{
|
|
|
|
return virRegisterStorageDriver(&esxStorageDriver);
|
|
|
|
}
|