[libvirt] [PATCH] Refactor ESX storage driver and add iSCSI support
by Ata E Husain Bohra
The patch refactors the current ESX storage driver due to following reasons:
1. Given most of the public APIs exposed by the storage driver in Libvirt
remains same, ESX storage driver should not implement logic specific
for only one supported format (current implementation only supports VMFS).
2. Decoupling interface from specific storage implementation gives us an
extensible design to hook implementation for other supported storage
formats.
This patch refactors the current driver to implement it as a facade pattern i.e.
the driver exposes all the public libvirt APIs, but uses backend drivers to get
the required task done. The backend drivers provide implementation specific to
the type of storage device.
File changes:
------------------
esx_storage_driver.c ----> esx_storage_driver.c (base storage driver)
|
|---> esx_storage_backend_vmfs.c (VMFS backend)
|
|---> esx_storage_backend_iscsi.c (iSCSI backend)
The patch adds the backend driver to support iSCSI format storage pools
and volumes for ESX host. The mapping of ESX iSCSI specifics to Libvirt
is as follows:
1. ESX static iSCSI target <------> Libvirt Storage Pools
2. ESX iSCSI LUNs <------> Libvirt Storage Volumes.
The above understanding is based on http://libvirt.org/storage.html.
The operation supported on iSCSI pools includes:
1. List storage pools & volumes.
2. Get xml descriptor operaion on pools & volumes.
3. Lookup operation on pools & volumes by name, uuid and path (if applicable).
iSCSI pools does not support operations such as: Create / remove pools
and volumes
---
src/Makefile.am | 16 +-
src/esx/esx_driver.c | 4 +-
src/esx/esx_storage_backend_iscsi.c | 794 +++++++++++++++++++
src/esx/esx_storage_backend_iscsi.h | 31 +
src/esx/esx_storage_backend_vmfs.c | 1471 +++++++++++++++++++++++++++++++++++
src/esx/esx_storage_backend_vmfs.h | 31 +
src/esx/esx_storage_driver.c | 1303 +++++--------------------------
src/esx/esx_vi.c | 341 +++++++-
src/esx/esx_vi.h | 21 +-
src/esx/esx_vi_generator.input | 308 +++++++-
src/esx/esx_vi_generator.py | 19 +
11 files changed, 3218 insertions(+), 1121 deletions(-)
create mode 100644 src/esx/esx_storage_backend_iscsi.c
create mode 100644 src/esx/esx_storage_backend_iscsi.h
create mode 100644 src/esx/esx_storage_backend_vmfs.c
create mode 100644 src/esx/esx_storage_backend_vmfs.h
diff --git a/src/Makefile.am b/src/Makefile.am
index d35edd6..8f58a8a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -475,13 +475,15 @@ UML_DRIVER_SOURCES = \
uml/uml_conf.c uml/uml_conf.h \
uml/uml_driver.c uml/uml_driver.h
-ESX_DRIVER_SOURCES = \
- esx/esx_private.h \
- esx/esx_driver.c esx/esx_driver.h \
- esx/esx_interface_driver.c esx/esx_interface_driver.h \
- esx/esx_network_driver.c esx/esx_network_driver.h \
- esx/esx_storage_driver.c esx/esx_storage_driver.h \
- esx/esx_device_monitor.c esx/esx_device_monitor.h \
+ESX_DRIVER_SOURCES = \
+ esx/esx_private.h \
+ esx/esx_driver.c esx/esx_driver.h \
+ esx/esx_interface_driver.c esx/esx_interface_driver.h \
+ esx/esx_network_driver.c esx/esx_network_driver.h \
+ esx/esx_storage_driver.c esx/esx_storage_driver.h \
+ esx/esx_storage_backend_vmfs.c esx/esx_storage_backend_vmfs.h \
+ esx/esx_storage_backend_iscsi.c esx/esx_storage_backend_iscsi.h \
+ esx/esx_device_monitor.c esx/esx_device_monitor.h \
esx/esx_secret_driver.c esx/esx_secret_driver.h \
esx/esx_nwfilter_driver.c esx/esx_nwfilter_driver.h \
esx/esx_util.c esx/esx_util.h \
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 72a7acc..359de53 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -162,7 +162,7 @@ esxParseVMXFileName(const char *fileName, void *opaque)
datastoreName = NULL;
if (esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
- &hostMount) < 0 ||
+ &hostMount, esxVI_Occurrence_RequiredItem) < 0 ||
esxVI_GetStringValue(datastore, "summary.name", &datastoreName,
esxVI_Occurrence_RequiredItem) < 0) {
goto cleanup;
@@ -306,7 +306,7 @@ esxFormatVMXFileName(const char *fileName, void *opaque)
if (esxVI_LookupDatastoreByName(data->ctx, datastoreName, NULL, &datastore,
esxVI_Occurrence_RequiredItem) < 0 ||
esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
- &hostMount) < 0) {
+ &hostMount, esxVI_Occurrence_RequiredItem) < 0) {
goto cleanup;
}
diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c
new file mode 100644
index 0000000..4f79a0f
--- /dev/null
+++ b/src/esx/esx_storage_backend_iscsi.c
@@ -0,0 +1,794 @@
+/*
+ * esx_storage_backend_iscsi.c: ESX storage backend for iSCSI handling
+ *
+ * Copyright (C) 2007-2008, 2010-2012 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Author: Ata E Husain Bohra (ata.husain(a)hotmail.com)
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "internal.h"
+#include "md5.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+
+#include "storage_conf.h"
+#include "storage_file.h"
+#include "esx_private.h"
+#include "esx_vi.h"
+#include "esx_vi_methods.h"
+#include "esx_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+/*
+ * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore,
+ * verify that UUID and MD5 sum match in size, because we rely on that.
+ */
+verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
+
+
+
+static int
+esxStorageBackendISCSINumberOfStoragePools(virConnectPtr conn)
+{
+ int count = 0;
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+ bool success = false;
+
+ if (esxVI_LookupHostInternetScsiHba(
+ priv->primary, &hostInternetScsiHba) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to obtain iSCSI adapter"));
+ goto cleanup;
+ }
+
+ if (hostInternetScsiHba == NULL) {
+ /* iSCSI adapter may not be enabled for this host */
+ return 0;
+ }
+
+ /**
+ * ESX has two kind of targets:
+ * 1. staticIscsiTargets
+ * 2. dynamicIscsiTargets
+ * For each dynamic target if its reachable a static target is added.
+ * return iSCSI names for all static targets to avoid duplicate names.
+ */
+ if (hostInternetScsiHba->configuredStaticTarget) {
+ const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+ for (target = hostInternetScsiHba->configuredStaticTarget;
+ target != NULL; target = target->_next) {
+ ++count;
+ }
+ }
+
+ success = true;
+
+cleanup:
+
+ esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+ return success ? count : -1;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIListStoragePools(virConnectPtr conn,
+ char **const names,
+ const int maxnames)
+{
+ int count = 0;
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+ bool success = false;
+ int i = 0;
+
+ if (maxnames ==0) {
+ return 0;
+ }
+
+ if (esxVI_LookupHostInternetScsiHba(
+ priv->primary, &hostInternetScsiHba) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to obtain iSCSI adapter"));
+ goto cleanup;
+ }
+
+ if (hostInternetScsiHba == NULL) {
+ /* iSCSI adapter may not be enabled for this host */
+ return 0;
+ }
+
+ /**
+ * ESX has two kind of targets:
+ * 1. staticIscsiTargets
+ * 2. dynamicIscsiTargets
+ * For each dynamic target if its reachable a static target is added.
+ * return iSCSI names for all static targets to avoid duplicate names.
+ */
+ if (hostInternetScsiHba->configuredStaticTarget) {
+ const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+ for (target = hostInternetScsiHba->configuredStaticTarget;
+ target != NULL && count < maxnames;
+ target = target->_next, ++count) {
+ names[count] = strdup(target->iScsiName);
+
+ if (names[count] == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+ }
+
+ success = true;
+
+cleanup:
+ if (! success) {
+ for (i = 0; i < count; ++i) {
+ VIR_FREE(names[i]);
+ }
+ count = -1;
+ }
+
+ esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+ return success ? count : -1;
+}
+
+
+
+static virStoragePoolPtr
+esxStorageBackendISCSIPoolLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+ /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ unsigned char md5[MD5_DIGEST_SIZE];
+ virStoragePoolPtr pool = NULL;
+
+ if (esxVI_LookupHostInternetScsiHbaStaticTargetByName(
+ priv->primary, name, &target, esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ /**
+ * HostInternetScsiHbaStaticTarget does not provide a uuid field,
+ * but iSsiName (or widely known as IQN) is unique across the multiple
+ * hosts, using it to compute key
+ */
+
+ md5_buffer(target->iScsiName, strlen(target->iScsiName), md5);
+
+ pool = virGetStoragePool(conn, name, md5);
+
+ cleanup:
+
+ esxVI_HostInternetScsiHbaStaticTarget_Free(&target);
+
+ return pool;
+
+}
+
+
+
+static virStoragePoolPtr
+esxStorageBackendISCSIPoolLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ virStoragePoolPtr pool = NULL;
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+ const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+ /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ unsigned char md5[MD5_DIGEST_SIZE];
+
+ if (esxVI_LookupHostInternetScsiHba(
+ priv->primary, &hostInternetScsiHba) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to obtain iSCSI adapter"));
+ goto cleanup;
+ }
+
+ if (hostInternetScsiHba == NULL) {
+ /* iSCSI adapter may not be enabled for this host */
+ return NULL;
+ }
+
+ if (hostInternetScsiHba->configuredStaticTarget) {
+ for (target = hostInternetScsiHba->configuredStaticTarget;
+ target != NULL; target = target->_next) {
+ md5_buffer(target->iScsiName, strlen(target->iScsiName), md5);
+
+ if (memcmp(uuid, md5, VIR_UUID_STRING_BUFLEN) == 0) {
+ break;
+ }
+ }
+ }
+
+ if (target == NULL) {
+ /* pool not found */
+ goto cleanup;
+ }
+
+ pool = virGetStoragePool(conn, target->iScsiName, md5);
+
+ cleanup:
+ esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+ return pool;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIPoolRefresh(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ int result = -1;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_ManagedObjectReference *hostStorageSystem = NULL;
+ esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+ esxVI_ObjectContent *hostSystem = NULL;
+ esxVI_String *propertyNameList = NULL;
+
+ virCheckFlags(0, -1);
+
+ if (esxVI_String_AppendValueToList(&propertyNameList,
+ "configManager.storageSystem\0") < 0 ||
+ esxVI_LookupHostSystemProperties(priv->primary,
+ propertyNameList, &hostSystem) < 0 ||
+ esxVI_GetManagedObjectReference(hostSystem,
+ "configManager.storageSystem", &hostStorageSystem,
+ esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_LookupHostInternetScsiHba(
+ priv->primary, &hostInternetScsiHba) < 0) {
+ goto cleanup;
+ }
+
+ /**
+ * ESX does not allow rescan on a particular target,
+ * rescan all the static targets
+ */
+ if (esxVI_RescanHba(priv->primary, hostStorageSystem,
+ hostInternetScsiHba->device) < 0) {
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ManagedObjectReference_Free(&hostStorageSystem);
+ esxVI_ObjectContent_Free(&hostSystem);
+ esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+ return result;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIPoolGetInfo(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+ virStoragePoolInfoPtr info)
+{
+ /* these fields are not valid for iSCSI pool */
+ info->allocation = info->capacity = info->available = 0;
+ info->state = esxVI_Boolean_True;
+
+ return 0;
+}
+
+
+
+static char *
+esxStorageBackendISCSIPoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
+{
+ char *xml = NULL;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+ const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+ virStoragePoolDef def;
+
+ virCheckFlags(0, NULL);
+
+ memset(&def, 0, sizeof(def));
+
+ if (esxVI_LookupHostInternetScsiHba(priv->primary, &hostInternetScsiHba)) {
+ goto cleanup;
+ }
+
+ if (hostInternetScsiHba->configuredStaticTarget) {
+ for (target = hostInternetScsiHba->configuredStaticTarget;
+ target != NULL; target = target->_next) {
+ if (STREQ(target->iScsiName, pool->name)) {
+ break;
+ }
+ }
+ }
+
+ if (target == NULL) {
+ goto cleanup;
+ }
+
+ def.name = pool->name;
+ memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+ def.type = VIR_STORAGE_POOL_ISCSI;
+
+ def.source.initiator.iqn = target->iScsiName;
+
+ def.source.nhost = 1;
+ if (VIR_ALLOC_N(def.source.hosts, def.source.nhost) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ def.source.hosts[0].name = target->address;
+ if (target->port) {
+ def.source.hosts[0].port = target->port->value;
+ }
+
+ /* TODO: add CHAP authentication params */
+
+ xml = virStoragePoolDefFormat(&def);
+
+ cleanup:
+
+ VIR_FREE(def.source.hosts);
+ esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+ return xml;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIPoolNumberOfStorageVolumes(virStoragePoolPtr pool)
+{
+ int count = 0;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_HostScsiTopologyLun *hostScsiTopologyLunList = NULL;
+ const esxVI_HostScsiTopologyLun *hostScsiTopologyLun = NULL;
+ bool success = false;
+
+ if (esxVI_LookupHostScsiTopologyLunListByTargetName(
+ priv->primary, pool->name, &hostScsiTopologyLunList) < 0) {
+ goto cleanup;
+ }
+
+ for (hostScsiTopologyLun = hostScsiTopologyLunList ;
+ hostScsiTopologyLun != NULL;
+ hostScsiTopologyLun = hostScsiTopologyLun->_next) {
+ ++count;
+ }
+
+ success = true;
+
+ cleanup:
+
+ esxVI_HostScsiTopologyLun_Free(&hostScsiTopologyLunList);
+
+ return success ? count : -1;
+
+}
+
+
+static int
+esxStorageBackendISCSIPoolListStorageVolumes(virStoragePoolPtr pool,
+ char **const names,
+ int maxnames)
+{
+ int count = 0;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_HostScsiTopologyLun *hostScsiTopologyLunList = NULL;
+ const esxVI_HostScsiTopologyLun *hostScsiTopologyLun = NULL;
+ esxVI_ScsiLun *scsiLunList = NULL;
+ const esxVI_ScsiLun *scsiLun = NULL;
+ bool success = false;
+ int i = 0;
+
+ if (esxVI_LookupHostScsiTopologyLunListByTargetName(
+ priv->primary, pool->name, &hostScsiTopologyLunList) < 0) {
+ goto cleanup;
+ }
+
+ if (hostScsiTopologyLunList == NULL) {
+ /* iSCSI adapter may not be enabled on ESX host */
+ return 0;
+ }
+
+ if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+ goto cleanup;
+ }
+
+ /* O^2 but still faster than hash given N is not that large */
+ for (scsiLun = scsiLunList; scsiLun != NULL && count < maxnames;
+ scsiLun = scsiLun->_next) {
+ for (hostScsiTopologyLun = hostScsiTopologyLunList;
+ hostScsiTopologyLun != NULL && count < maxnames;
+ hostScsiTopologyLun = hostScsiTopologyLun->_next) {
+ if (STREQ(hostScsiTopologyLun->scsiLun, scsiLun->key)) {
+ names[count] = strdup(scsiLun->deviceName);
+
+ if (names[count] == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ ++count;
+ }
+ }
+ }
+
+ success = true;
+
+ cleanup:
+ if (! success) {
+ for (i = 0; i < count; ++i) {
+ VIR_FREE(names[i]);
+ }
+ count = -1;
+ }
+
+ esxVI_HostScsiTopologyLun_Free(&hostScsiTopologyLunList);
+ esxVI_ScsiLun_Free(&scsiLunList);
+
+ return count;
+}
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeLookupByName(virStoragePoolPtr pool,
+ const char *name)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_ScsiLun *scsiLunList = NULL;
+ const esxVI_ScsiLun *scsiLun = NULL;
+ /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ unsigned char md5[MD5_DIGEST_SIZE];
+ char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+ if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+ goto cleanup;
+ }
+
+ for (scsiLun = scsiLunList; scsiLun != NULL;
+ scsiLun = scsiLun->_next) {
+ if (STREQ(scsiLun->deviceName, name)) {
+ /**
+ * ScsiLun provides an UUID field that is unique accross
+ * multiple servers. But this field length is ~55 characters
+ * compute MD5 hash to transform it to an acceptable
+ * libvirt format
+ */
+ md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5);
+
+ virUUIDFormat(md5, uuid_string);
+
+ /**
+ * ScsiLun provides displayName and canonicalName but both are
+ * optional and its observed that they can be NULL, using
+ * deviceName to create volume.
+ */
+ volume = virGetStorageVol(pool->conn, pool->name, name, uuid_string);
+ break;
+ }
+ }
+
+ cleanup:
+
+ esxVI_ScsiLun_Free(&scsiLunList);
+
+ return volume;
+
+}
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeLookupByPath(virConnectPtr conn, const char *path)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = conn->storagePrivateData;
+ char *poolName = NULL;
+ esxVI_ScsiLun *scsiLunList = NULL;
+ const esxVI_ScsiLun *scsiLun = NULL;
+ const esxVI_HostScsiDisk *hostScsiDisk = NULL;
+ /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ unsigned char md5[MD5_DIGEST_SIZE];
+ char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+ if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+ goto cleanup;
+ }
+
+ for (scsiLun = scsiLunList ; scsiLun != NULL;
+ scsiLun = scsiLun->_next) {
+ hostScsiDisk =
+ esxVI_HostScsiDisk_DynamicCast((esxVI_ScsiLun *)scsiLun);
+
+ if (hostScsiDisk != NULL &&
+ STREQ(hostScsiDisk->devicePath, path)) {
+ /* Found matching device */
+ if (esxVI_LookupStoragePoolNameByScsiLunKey(
+ priv->primary, hostScsiDisk->key, &poolName) < 0) {
+ goto cleanup;
+ }
+
+ md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5);
+
+ virUUIDFormat(md5, uuid_string);
+
+ volume = virGetStorageVol(conn, poolName, path, uuid_string);
+ break;
+ }
+ }
+
+ cleanup:
+
+ esxVI_ScsiLun_Free(&scsiLunList);
+ VIR_FREE(poolName);
+
+ return volume;
+
+}
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeLookupByKey(virConnectPtr conn, const char *key)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = conn->storagePrivateData;
+ char *poolName = NULL;
+ esxVI_ScsiLun *scsiLunList = NULL;
+ const esxVI_ScsiLun *scsiLun = NULL;
+ /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ unsigned char md5[MD5_DIGEST_SIZE];
+ char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+
+ /* key may be LUN device path */
+ if (STRPREFIX(key, "/")) {
+ return esxStorageBackendISCSIVolumeLookupByPath(conn, key);
+ }
+
+ if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+ goto cleanup;
+ }
+
+ for (scsiLun = scsiLunList; scsiLun != NULL;
+ scsiLun = scsiLun->_next) {
+
+ memset(uuid_string, '\0', sizeof(uuid_string));
+ memset(md5, '\0', sizeof(md5));
+
+ md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5);
+
+ virUUIDFormat(md5, uuid_string);
+
+ if (STREQ(key, uuid_string)) {
+ /* Found matching UUID */
+ if (esxVI_LookupStoragePoolNameByScsiLunKey(
+ priv->primary, scsiLun->key, &poolName) < 0) {
+ goto cleanup;
+ }
+
+ volume = virGetStorageVol(conn, poolName,
+ scsiLun->deviceName, uuid_string);
+ break;
+ }
+ }
+
+ cleanup:
+
+ esxVI_ScsiLun_Free(&scsiLunList);
+ VIR_FREE(poolName);
+
+ return volume;
+
+}
+
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeCreateXML(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+ const char *xmldesc ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virCheckFlags(0, NULL);
+
+ /* not supported operation for iSCSI pools */
+ return NULL;
+}
+
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeCreateXMLFrom(
+ virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+ const char *xmldesc ATTRIBUTE_UNUSED,
+ virStorageVolPtr sourceVolume ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virCheckFlags(0, NULL);
+
+ /* not supported operation for iSCSI pools */
+ return NULL;
+}
+
+
+
+static char*
+esxStorageBackendISCSIVolumeGetXMLDesc(virStorageVolPtr volume,
+ unsigned int flags)
+{
+ char *xml = NULL;
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ virStoragePoolDef pool;
+ esxVI_ScsiLun *scsiLunList = NULL;
+ const esxVI_ScsiLun *scsiLun = NULL;
+ const esxVI_HostScsiDisk *hostScsiDisk = NULL;
+ virStorageVolDef def;
+ /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ unsigned char md5[MD5_DIGEST_SIZE];
+ char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+ virCheckFlags(0, NULL);
+
+ memset(&pool, 0, sizeof(pool));
+ memset(&def, 0, sizeof(def));
+
+ if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+ goto cleanup;
+ }
+
+ for (scsiLun = scsiLunList; scsiLun != NULL;
+ scsiLun = scsiLun->_next) {
+ hostScsiDisk =
+ esxVI_HostScsiDisk_DynamicCast((esxVI_ScsiLun *)scsiLun);
+
+ if (hostScsiDisk != NULL &&
+ STREQ(hostScsiDisk->deviceName, volume->name)) {
+ break;
+ }
+ }
+
+ if (hostScsiDisk == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could find volume with name: %s"), volume->name);
+ goto cleanup;
+ }
+
+ pool.type = VIR_STORAGE_POOL_ISCSI;
+
+ def.name = volume->name;
+
+ md5_buffer(scsiLun->uuid, strlen(hostScsiDisk->uuid), md5);
+
+ virUUIDFormat(md5, uuid_string);
+
+ if (esxVI_String_DeepCopyValue(&def.key, uuid_string) < 0) {
+ goto cleanup;
+ }
+
+ /* iSCSI LUN exposes a block device */
+ def.type = VIR_STORAGE_VOL_BLOCK;
+
+ def.target.path = hostScsiDisk->devicePath;
+
+ def.capacity = hostScsiDisk->capacity->block->value *
+ hostScsiDisk->capacity->blockSize->value;
+
+ def.allocation = def.capacity;
+
+ /* iSCSI LUN(s) hosting a datastore will be auto-mounted by
+ * ESX host
+ */
+ def.target.format = VIR_STORAGE_FILE_RAW;
+
+ xml = virStorageVolDefFormat(&pool, &def);
+
+ cleanup:
+
+ esxVI_ScsiLun_Free(&scsiLunList);
+ VIR_FREE(def.key);
+
+ return xml;
+
+}
+
+static int
+esxStorageBackendISCSIVolumeDelete(virStorageVolPtr volume ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ /* unsupported operation for iSCSI volume */
+ return 1;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIVolumeWipe(virStorageVolPtr volume ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ /* unsupported operation for iSCSI volume */
+ return 1;
+
+}
+
+
+
+static char*
+esxStorageBackendISCSIVolumeGetPath(virStorageVolPtr volume)
+{
+ char *path;
+
+ if (virAsprintf(&path, "%s", volume->name) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ return path;
+
+}
+
+
+
+virStorageDriver esxStorageBackendISCSIDrv = {
+ .name = "ESX ISCSI backend",
+ .open = NULL, /* 0.10.0 */
+ .close = NULL, /* 0.10.0 */
+ .numOfPools = esxStorageBackendISCSINumberOfStoragePools, /* 0.10.0 */
+ .listPools = esxStorageBackendISCSIListStoragePools, /* 0.10.0 */
+ .poolLookupByName = esxStorageBackendISCSIPoolLookupByName, /* 0.10.0 */
+ .poolLookupByUUID = esxStorageBackendISCSIPoolLookupByUUID, /* 0.10.0 */
+ .poolRefresh = esxStorageBackendISCSIPoolRefresh, /* 0.10.0 */
+ .poolGetInfo = esxStorageBackendISCSIPoolGetInfo, /* 0.10.0 */
+ .poolGetXMLDesc = esxStorageBackendISCSIPoolGetXMLDesc, /* 0.10.0 */
+ .poolNumOfVolumes = esxStorageBackendISCSIPoolNumberOfStorageVolumes, /* 0.10.0 */
+ .poolListVolumes = esxStorageBackendISCSIPoolListStorageVolumes, /* 0.10.0 */
+ .volLookupByName = esxStorageBackendISCSIVolumeLookupByName, /* 0.10.0 */
+ .volLookupByKey = esxStorageBackendISCSIVolumeLookupByKey, /* 0.10.0 */
+ .volLookupByPath = esxStorageBackendISCSIVolumeLookupByPath, /* 0.10.0 */
+ .volCreateXML = esxStorageBackendISCSIVolumeCreateXML, /* 0.10.0 */
+ .volCreateXMLFrom = esxStorageBackendISCSIVolumeCreateXMLFrom, /* 0.10.0 */
+ .volGetXMLDesc = esxStorageBackendISCSIVolumeGetXMLDesc, /* 0.10.0 */
+ .volDelete = esxStorageBackendISCSIVolumeDelete, /* 0.10.0 */
+ .volWipe = esxStorageBackendISCSIVolumeWipe, /* 0.10.0 */
+ .volGetPath = esxStorageBackendISCSIVolumeGetPath, /* 0.10.0 */
+
+};
diff --git a/src/esx/esx_storage_backend_iscsi.h b/src/esx/esx_storage_backend_iscsi.h
new file mode 100644
index 0000000..ca756ac
--- /dev/null
+++ b/src/esx/esx_storage_backend_iscsi.h
@@ -0,0 +1,31 @@
+/*
+ * esx_storage_backend_iscsi.h: ESX storage backend for iSCSI handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Author: Ata E Husain Bohra (ata.husain(a)hotmail.com)
+ */
+
+#ifndef __ESX_STORAGE_BACKEND_ISCSI_H__
+# define __ESX_STORAGE_BACKEND_ISCSI_H__
+
+#include "driver.h"
+
+extern virStorageDriver esxStorageBackendISCSIDrv;
+
+#endif /* __ESX_STORAGE_BACKEND_ISCSI_H__ */
+
diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c
new file mode 100644
index 0000000..6550196
--- /dev/null
+++ b/src/esx/esx_storage_backend_vmfs.c
@@ -0,0 +1,1471 @@
+
+/*
+ * esx_storage_backend_vmfs.c: ESX storage backend for VMFS datastores
+ *
+ * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010 Matthias Bolte <matthias.bolte(a)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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ata E Husain Bohra (ata.husain(a)hotmail.com)
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "internal.h"
+#include "md5.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+
+#include "storage_conf.h"
+#include "storage_file.h"
+#include "esx_storage_backend_vmfs.h"
+#include "esx_private.h"
+#include "esx_vi.h"
+#include "esx_vi_methods.h"
+#include "esx_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+/*
+ * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore,
+ * verify that UUID and MD5 sum match in size, because we rely on that.
+ */
+verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
+
+
+
+static int
+esxStorageBackendVMFSPoolLookupType(virConnectPtr conn, const char *poolName,
+ int *poolType)
+{
+ int result = -1;
+ esxPrivate *priv = conn->storagePrivateData;
+ 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(priv->primary, poolName,
+ propertyNameList, &datastore,
+ esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ if (datastore == NULL) {
+ /* not found */
+ goto cleanup;
+ }
+
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "info")) {
+ if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+ &datastoreInfo) < 0) {
+ goto cleanup;
+ }
+
+ break;
+ }
+ }
+
+ if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+ *poolType = VIR_STORAGE_POOL_DIR;
+ } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+ *poolType = VIR_STORAGE_POOL_NETFS;
+ } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+ *poolType = VIR_STORAGE_POOL_FS;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("DatastoreInfo has unexpected type"));
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastore);
+ esxVI_DatastoreInfo_Free(&datastoreInfo);
+
+ return result;
+}
+
+
+
+
+static int
+esxStorageBackendVMFSNumberOfStoragePools(virConnectPtr conn)
+{
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_ObjectContent *datastoreList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ int count = 0;
+
+ if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0) {
+ goto cleanup;
+ }
+
+ for (datastore = datastoreList; datastore != NULL;
+ datastore = datastore->_next) {
+ ++count;
+ }
+
+ cleanup:
+ esxVI_ObjectContent_Free(&datastoreList);
+
+ return count;
+}
+
+static int
+esxStorageBackendVMFSListStoragePools(virConnectPtr conn,
+ char **const names,
+ const int maxnames)
+{
+ 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 = 0;
+ bool success = false;
+
+ if (maxnames == 0) {
+ return 0;
+ }
+
+ if (esxVI_String_AppendValueToList(&propertyNameList,
+ "summary.name") < 0 ||
+ esxVI_LookupDatastoreList(priv->primary, propertyNameList,
+ &datastoreList) < 0) {
+ goto cleanup;
+ }
+
+ for (datastore = datastoreList; datastore != NULL;
+ datastore = datastore->_next) {
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "summary.name")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_String) < 0) {
+ goto cleanup;
+ }
+
+ names[count] = strdup(dynamicProperty->val->string);
+
+ if (names[count] == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ++count;
+ break;
+ } else {
+ VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+ }
+ }
+ }
+
+ success = true;
+
+ cleanup:
+ if (! success) {
+ for (i = 0; i < count; ++i) {
+ VIR_FREE(names[i]);
+ }
+
+ count = -1;
+ }
+
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastoreList);
+
+ return count;
+}
+
+static virStoragePoolPtr
+esxStorageBackendVMFSPoolLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_DatastoreHostMount *hostMount = NULL;
+ /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ unsigned char md5[MD5_DIGEST_SIZE];
+ virStoragePoolPtr pool = NULL;
+
+ virCheckNonNullArgReturn(name, NULL);
+
+ if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore,
+ esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ if (datastore == NULL) {
+ /* not found */
+ 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_RequiredItem) < 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
+esxStorageBackendVMFSPoolLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastoreList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_DatastoreHostMount *hostMount = NULL;
+ unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+ char *name = NULL;
+ virStoragePoolPtr pool = NULL;
+
+
+ if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
+ esxVI_LookupDatastoreList(priv->primary, propertyNameList,
+ &datastoreList) < 0) {
+ goto cleanup;
+ }
+
+ for (datastore = datastoreList; datastore != NULL;
+ datastore = datastore->_next) {
+ esxVI_DatastoreHostMount_Free(&hostMount);
+
+ if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
+ &hostMount, esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ if (hostMount == NULL) {
+ /* not found */
+ goto cleanup;
+ }
+
+ md5_buffer(hostMount->mountInfo->path,
+ strlen(hostMount->mountInfo->path), md5);
+
+ if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) {
+ break;
+ }
+ }
+
+ if (datastore == NULL) {
+ 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 int
+esxStorageBackendVMFSPoolRefresh(virStoragePoolPtr pool, unsigned int flags)
+{
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_ObjectContent *datastore = NULL;
+ int result = -1;
+
+ virCheckFlags(0, -1);
+
+ if (esxVI_LookupDatastoreByName(priv->primary, pool->name, NULL, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_RefreshDatastore(priv->primary, datastore->obj) < 0) {
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ esxVI_ObjectContent_Free(&datastore);
+
+ return result;
+}
+
+
+static int
+esxStorageBackendVMFSPoolGetInfo(virStoragePoolPtr pool,
+ virStoragePoolInfoPtr info)
+{
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+ int result = -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 *
+esxStorageBackendVMFSPoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
+{
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_DatastoreHostMount *hostMount = NULL;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+ virStoragePoolDef def;
+ esxVI_DatastoreInfo *info = NULL;
+ esxVI_NasDatastoreInfo *nasInfo = NULL;
+ char *xml = NULL;
+
+ virCheckFlags(0, NULL);
+
+ memset(&def, 0, sizeof(def));
+
+ if (esxVI_String_AppendValueListToList(&propertyNameList,
+ "summary.accessible\0"
+ "summary.capacity\0"
+ "summary.freeSpace\0"
+ "info\0") < 0 ||
+ esxVI_LookupDatastoreByName(priv->primary, pool->name,
+ propertyNameList, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_GetBoolean(datastore, "summary.accessible",
+ &accessible, esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
+ &hostMount, esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ def.name = pool->name;
+ memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+ def.target.path = hostMount->mountInfo->path;
+
+ if (accessible == esxVI_Boolean_True) {
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "summary.capacity")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_Long) < 0) {
+ goto cleanup;
+ }
+
+ def.capacity = dynamicProperty->val->int64;
+ } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_Long) < 0) {
+ goto cleanup;
+ }
+
+ def.available = dynamicProperty->val->int64;
+ }
+ }
+
+ def.allocation = def.capacity - def.available;
+ }
+
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "info")) {
+ if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+ &info) < 0) {
+ goto cleanup;
+ }
+
+ break;
+ }
+ }
+
+ /* See vSphere API documentation about HostDatastoreSystem for details */
+ if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) {
+ def.type = VIR_STORAGE_POOL_DIR;
+ } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
+ if (VIR_ALLOC_N(def.source.hosts, 1) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ def.type = VIR_STORAGE_POOL_NETFS;
+ def.source.hosts[0].name = nasInfo->nas->remoteHost;
+ def.source.dir = nasInfo->nas->remotePath;
+
+ if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
+ def.source.format = VIR_STORAGE_POOL_NETFS_NFS;
+ } else if (STRCASEEQ(nasInfo->nas->type, "CIFS")) {
+ def.source.format = VIR_STORAGE_POOL_NETFS_CIFS;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Datastore has unexpected type '%s'"),
+ nasInfo->nas->type);
+ goto cleanup;
+ }
+ } else if (esxVI_VmfsDatastoreInfo_DynamicCast(info) != NULL) {
+ def.type = VIR_STORAGE_POOL_FS;
+ /*
+ * FIXME: I'm not sure how to represent the source and target of a
+ * VMFS based datastore in libvirt terms
+ */
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("DatastoreInfo has unexpected type"));
+ goto cleanup;
+ }
+
+ xml = virStoragePoolDefFormat(&def);
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastore);
+ esxVI_DatastoreHostMount_Free(&hostMount);
+ esxVI_DatastoreInfo_Free(&info);
+
+ return xml;
+}
+
+
+static int
+esxStorageBackendVMFSPoolNumberOfStorageVolumes(virStoragePoolPtr pool)
+{
+ bool success = false;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
+ esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
+ esxVI_FileInfo *fileInfo = NULL;
+ int count = 0;
+
+ if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
+ &searchResultsList) < 0) {
+ goto cleanup;
+ }
+
+ /* Interpret search result */
+ for (searchResults = searchResultsList; searchResults != NULL;
+ searchResults = searchResults->_next) {
+ for (fileInfo = searchResults->file; fileInfo != NULL;
+ fileInfo = fileInfo->_next) {
+ ++count;
+ }
+ }
+
+ success = true;
+
+ cleanup:
+ esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+
+ return success ? count : -1;
+}
+
+static int
+esxStorageBackendVMFSPoolListStorageVolumes(virStoragePoolPtr pool, char **const names,
+ int maxnames)
+
+{
+ bool success = false;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
+ esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
+ esxVI_FileInfo *fileInfo = NULL;
+ char *directoryAndFileName = NULL;
+ size_t length;
+ int count = 0;
+ int i;
+
+ if (names == NULL || maxnames < 0) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
+ return -1;
+ }
+
+ if (maxnames == 0) {
+ return 0;
+ }
+
+ if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
+ &searchResultsList) < 0) {
+ goto cleanup;
+ }
+
+ /* Interpret search result */
+ for (searchResults = searchResultsList; searchResults != NULL;
+ searchResults = searchResults->_next) {
+ VIR_FREE(directoryAndFileName);
+
+ if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL, NULL,
+ &directoryAndFileName) < 0) {
+ goto cleanup;
+ }
+
+ /* Strip trailing separators */
+ length = strlen(directoryAndFileName);
+
+ while (length > 0 && directoryAndFileName[length - 1] == '/') {
+ directoryAndFileName[length - 1] = '\0';
+ --length;
+ }
+
+ /* Build volume names */
+ for (fileInfo = searchResults->file; fileInfo != NULL;
+ fileInfo = fileInfo->_next) {
+ if (length < 1) {
+ names[count] = strdup(fileInfo->path);
+
+ if (names[count] == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ } else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName,
+ fileInfo->path) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ++count;
+ }
+ }
+
+ success = true;
+
+ cleanup:
+ if (! success) {
+ for (i = 0; i < count; ++i) {
+ VIR_FREE(names[i]);
+ }
+
+ count = -1;
+ }
+
+ esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+ VIR_FREE(directoryAndFileName);
+
+ return count;
+
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeLookupByName(virStoragePoolPtr pool,
+ const char *name)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ char *datastorePath = NULL;
+ char *key = NULL;
+
+ if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary,
+ datastorePath, &key) < 0) {
+ goto cleanup;
+ }
+
+ volume = virGetStorageVol(pool->conn, pool->name, name, key);
+
+ cleanup:
+ VIR_FREE(datastorePath);
+ VIR_FREE(key);
+
+ return volume;
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeLookupByPath(virConnectPtr conn, const char *path)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = conn->storagePrivateData;
+ char *datastoreName = NULL;
+ char *directoryAndFileName = NULL;
+ char *key = NULL;
+
+ if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL,
+ &directoryAndFileName) < 0) {
+ goto cleanup;
+ }
+
+ if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path,
+ &key) < 0) {
+ goto cleanup;
+ }
+
+ volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key);
+
+ cleanup:
+ VIR_FREE(datastoreName);
+ VIR_FREE(directoryAndFileName);
+ VIR_FREE(key);
+
+ return volume;
+}
+
+
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeLookupByKey(virConnectPtr conn, const char *key)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastoreList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ char *datastoreName = NULL;
+ esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
+ esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
+ char *directoryAndFileName = NULL;
+ size_t length;
+ char *datastorePath = NULL;
+ char *volumeName = NULL;
+ esxVI_FileInfo *fileInfo = NULL;
+ char *uuid_string = NULL;
+ char key_candidate[VIR_UUID_STRING_BUFLEN] = "";
+
+ if (STRPREFIX(key, "[")) {
+ /* Key is probably a datastore path */
+ return esxStorageBackendVMFSVolumeLookupByPath(conn, key);
+ }
+
+ if (!priv->primary->hasQueryVirtualDiskUuid) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("QueryVirtualDiskUuid not available, cannot lookup storage "
+ "volume by UUID"));
+ return NULL;
+ }
+
+ /* Lookup all datastores */
+ if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
+ esxVI_LookupDatastoreList(priv->primary, propertyNameList,
+ &datastoreList) < 0) {
+ goto cleanup;
+ }
+
+ for (datastore = datastoreList; datastore != NULL;
+ datastore = datastore->_next) {
+ datastoreName = NULL;
+
+ if (esxVI_GetStringValue(datastore, "summary.name", &datastoreName,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ /* Lookup datastore content */
+ esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+
+ if (esxVI_LookupDatastoreContentByDatastoreName
+ (priv->primary, datastoreName, &searchResultsList) < 0) {
+ goto cleanup;
+ }
+
+ /* Interpret search result */
+ for (searchResults = searchResultsList; searchResults != NULL;
+ searchResults = searchResults->_next) {
+ VIR_FREE(directoryAndFileName);
+
+ if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL,
+ NULL, &directoryAndFileName) < 0) {
+ goto cleanup;
+ }
+
+ /* Strip trailing separators */
+ length = strlen(directoryAndFileName);
+
+ while (length > 0 && directoryAndFileName[length - 1] == '/') {
+ directoryAndFileName[length - 1] = '\0';
+ --length;
+ }
+
+ /* Build datastore path and query the UUID */
+ for (fileInfo = searchResults->file; fileInfo != NULL;
+ fileInfo = fileInfo->_next) {
+ VIR_FREE(datastorePath);
+
+ if (length < 1) {
+ if (virAsprintf(&volumeName, "%s",
+ fileInfo->path) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ } else if (virAsprintf(&volumeName, "%s/%s",
+ directoryAndFileName,
+ fileInfo->path) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virAsprintf(&datastorePath, "[%s] %s", datastoreName,
+ volumeName) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (esxVI_VmDiskFileInfo_DynamicCast(fileInfo) == NULL) {
+ /* Only a VirtualDisk has a UUID */
+ continue;
+ }
+
+ VIR_FREE(uuid_string);
+
+ if (esxVI_QueryVirtualDiskUuid
+ (priv->primary, datastorePath,
+ priv->primary->datacenter->_reference,
+ &uuid_string) < 0) {
+ goto cleanup;
+ }
+
+ if (esxUtil_ReformatUuid(uuid_string, key_candidate) < 0) {
+ goto cleanup;
+ }
+
+ if (STREQ(key, key_candidate)) {
+ /* Found matching UUID */
+ volume = virGetStorageVol(conn, datastoreName,
+ volumeName, key);
+ goto cleanup;
+ }
+ }
+ }
+ }
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastoreList);
+ esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+ VIR_FREE(directoryAndFileName);
+ VIR_FREE(datastorePath);
+ VIR_FREE(volumeName);
+ VIR_FREE(uuid_string);
+
+ return volume;
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
+ unsigned int flags)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ virStoragePoolDef poolDef;
+ virStorageVolDefPtr def = NULL;
+ char *tmp;
+ char *unescapedDatastorePath = NULL;
+ char *unescapedDirectoryName = NULL;
+ char *unescapedDirectoryAndFileName = NULL;
+ char *directoryName = NULL;
+ char *fileName = NULL;
+ char *datastorePathWithoutFileName = NULL;
+ char *datastorePath = NULL;
+ esxVI_FileInfo *fileInfo = NULL;
+ esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
+ esxVI_ManagedObjectReference *task = NULL;
+ esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
+ char *uuid_string = NULL;
+ char *key = NULL;
+
+ virCheckFlags(0, NULL);
+
+ memset(&poolDef, 0, sizeof(poolDef));
+
+ if (esxVI_EnsureSession(priv->primary) < 0) {
+ return NULL;
+ }
+
+ if (esxStorageBackendVMFSPoolLookupType(
+ pool->conn, pool->name, &poolDef.type) < 0) {
+ return NULL;
+ }
+
+ /* Parse config */
+ def = virStorageVolDefParseString(&poolDef, xmldesc);
+
+ if (def == NULL) {
+ goto cleanup;
+ }
+
+ if (def->type != VIR_STORAGE_VOL_FILE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Creating non-file volumes is not supported"));
+ goto cleanup;
+ }
+
+ /* Validate config */
+ tmp = strrchr(def->name, '/');
+
+ if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Volume name '%s' doesn't have expected format "
+ "'<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) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (def->target.format == VIR_STORAGE_FILE_VMDK) {
+ /* Parse and escape datastore path */
+ if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
+ &unescapedDirectoryName,
+ &unescapedDirectoryAndFileName) < 0) {
+ goto cleanup;
+ }
+
+ directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
+
+ if (directoryName == NULL) {
+ goto cleanup;
+ }
+
+ fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
+ strlen(unescapedDirectoryName) + 1);
+
+ if (fileName == NULL) {
+ goto cleanup;
+ }
+
+ if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
+ directoryName) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
+ fileName) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* Create directory, if it doesn't exist yet */
+ if (esxVI_LookupFileInfoByDatastorePath
+ (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
+ esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ if (fileInfo == NULL) {
+ if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
+ priv->primary->datacenter->_reference,
+ esxVI_Boolean_True) < 0) {
+ goto cleanup;
+ }
+ }
+
+ /* Create VirtualDisk */
+ if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 ||
+ esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) {
+ goto cleanup;
+ }
+
+ /* From the vSphere API documentation about VirtualDiskType ... */
+ if (def->allocation == def->capacity) {
+ /*
+ * "A preallocated disk has all space allocated at creation time
+ * and the space is zeroed on demand as the space is used."
+ */
+ virtualDiskSpec->diskType = (char *)"preallocated";
+ } else if (def->allocation == 0) {
+ /*
+ * "Space required for thin-provisioned virtual disk is allocated
+ * and zeroed on demand as the space is used."
+ */
+ virtualDiskSpec->diskType = (char *)"thin";
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unsupported capacity-to-allocation relation"));
+ goto cleanup;
+ }
+
+ /*
+ * FIXME: The adapter type is a required parameter, but there is no
+ * way to let the user specify it in the volume XML config. Therefore,
+ * default to 'busLogic' here.
+ */
+ virtualDiskSpec->adapterType = (char *)"busLogic";
+
+ virtualDiskSpec->capacityKb->value =
+ VIR_DIV_UP(def->capacity, 1024); /* Scale from byte to kilobyte */
+
+ if (esxVI_CreateVirtualDisk_Task
+ (priv->primary, datastorePath, priv->primary->datacenter->_reference,
+ esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 ||
+ esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+ esxVI_Occurrence_None,
+ priv->parsedUri->autoAnswer,
+ &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
+ goto cleanup;
+ }
+
+ if (taskInfoState != esxVI_TaskInfoState_Success) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create volume: %s"),
+ taskInfoErrorMessage);
+ goto cleanup;
+ }
+
+ if (priv->primary->hasQueryVirtualDiskUuid) {
+ if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
+ priv->primary->datacenter->_reference,
+ &uuid_string) < 0) {
+ goto cleanup;
+ }
+
+ if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
+ goto cleanup;
+ }
+ } else {
+ /* Fall back to the path as key */
+ if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
+ goto cleanup;
+ }
+ }
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Creation of %s volumes is not supported"),
+ virStorageFileFormatTypeToString(def->target.format));
+ goto cleanup;
+ }
+
+ volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+
+ cleanup:
+ if (virtualDiskSpec != NULL) {
+ virtualDiskSpec->diskType = NULL;
+ virtualDiskSpec->adapterType = NULL;
+ }
+
+ virStorageVolDefFree(def);
+ VIR_FREE(unescapedDatastorePath);
+ VIR_FREE(unescapedDirectoryName);
+ VIR_FREE(unescapedDirectoryAndFileName);
+ VIR_FREE(directoryName);
+ VIR_FREE(fileName);
+ VIR_FREE(datastorePathWithoutFileName);
+ VIR_FREE(datastorePath);
+ esxVI_FileInfo_Free(&fileInfo);
+ esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
+ esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
+ VIR_FREE(uuid_string);
+ VIR_FREE(key);
+
+ return volume;
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeCreateXMLFrom(virStoragePoolPtr pool,
+ const char *xmldesc,
+ virStorageVolPtr sourceVolume,
+ unsigned int flags)
+{
+ virStorageVolPtr volume = NULL;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ virStoragePoolDef poolDef;
+ char *sourceDatastorePath = NULL;
+ virStorageVolDefPtr def = NULL;
+ char *tmp;
+ char *unescapedDatastorePath = NULL;
+ char *unescapedDirectoryName = NULL;
+ char *unescapedDirectoryAndFileName = NULL;
+ char *directoryName = NULL;
+ char *fileName = NULL;
+ char *datastorePathWithoutFileName = NULL;
+ char *datastorePath = NULL;
+ esxVI_FileInfo *fileInfo = NULL;
+ esxVI_ManagedObjectReference *task = NULL;
+ esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
+ char *uuid_string = NULL;
+ char *key = NULL;
+
+ virCheckFlags(0, NULL);
+
+ memset(&poolDef, 0, sizeof(poolDef));
+
+ if (esxVI_EnsureSession(priv->primary) < 0) {
+ return NULL;
+ }
+
+ if (esxStorageBackendVMFSPoolLookupType(
+ pool->conn, pool->name, &poolDef.type) < 0) {
+ return NULL;
+ }
+
+ if (virAsprintf(&sourceDatastorePath, "[%s] %s", sourceVolume->pool,
+ sourceVolume->name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* Parse config */
+ def = virStorageVolDefParseString(&poolDef, xmldesc);
+
+ if (def == NULL) {
+ goto cleanup;
+ }
+
+ if (def->type != VIR_STORAGE_VOL_FILE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Creating non-file volumes is not supported"));
+ goto cleanup;
+ }
+
+ /* Validate config */
+ tmp = strrchr(def->name, '/');
+
+ if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Volume name '%s' doesn't have expected format "
+ "'<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) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (def->target.format == VIR_STORAGE_FILE_VMDK) {
+ /* Parse and escape datastore path */
+ if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
+ &unescapedDirectoryName,
+ &unescapedDirectoryAndFileName) < 0) {
+ goto cleanup;
+ }
+
+ directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
+
+ if (directoryName == NULL) {
+ goto cleanup;
+ }
+
+ fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
+ strlen(unescapedDirectoryName) + 1);
+
+ if (fileName == NULL) {
+ goto cleanup;
+ }
+
+ if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
+ directoryName) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
+ fileName) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* Create directory, if it doesn't exist yet */
+ if (esxVI_LookupFileInfoByDatastorePath
+ (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
+ esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ if (fileInfo == NULL) {
+ if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
+ priv->primary->datacenter->_reference,
+ esxVI_Boolean_True) < 0) {
+ goto cleanup;
+ }
+ }
+
+ /* Copy VirtualDisk */
+ if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath,
+ priv->primary->datacenter->_reference,
+ datastorePath,
+ priv->primary->datacenter->_reference,
+ NULL, esxVI_Boolean_False, &task) < 0 ||
+ esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+ esxVI_Occurrence_None,
+ priv->parsedUri->autoAnswer,
+ &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
+ goto cleanup;
+ }
+
+ if (taskInfoState != esxVI_TaskInfoState_Success) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"),
+ taskInfoErrorMessage);
+ goto cleanup;
+ }
+
+ if (priv->primary->hasQueryVirtualDiskUuid) {
+ if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
+ priv->primary->datacenter->_reference,
+ &uuid_string) < 0) {
+ goto cleanup;
+ }
+
+ if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
+ goto cleanup;
+ }
+ } else {
+ /* Fall back to the path as key */
+ if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
+ goto cleanup;
+ }
+ }
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Creation of %s volumes is not supported"),
+ virStorageFileFormatTypeToString(def->target.format));
+ goto cleanup;
+ }
+
+ volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+
+ 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 char *
+esxStorageBackendVMFSVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
+{
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ virStoragePoolDef pool;
+ char *datastorePath = NULL;
+ esxVI_FileInfo *fileInfo = NULL;
+ esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
+ esxVI_IsoImageFileInfo *isoImageFileInfo = NULL;
+ esxVI_FloppyImageFileInfo *floppyImageFileInfo = NULL;
+ virStorageVolDef def;
+ char *xml = NULL;
+
+ virCheckFlags(0, NULL);
+
+ memset(&pool, 0, sizeof(pool));
+ memset(&def, 0, sizeof(def));
+
+ if (esxStorageBackendVMFSPoolLookupType(
+ volume->conn, volume->pool, &pool.type) < 0) {
+ return NULL;
+ }
+
+ /* Lookup file info */
+ if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
+ false, &fileInfo,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
+ isoImageFileInfo = esxVI_IsoImageFileInfo_DynamicCast(fileInfo);
+ floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo);
+
+ def.name = volume->name;
+
+ if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath,
+ &def.key) < 0) {
+ goto cleanup;
+ }
+
+ def.type = VIR_STORAGE_VOL_FILE;
+ def.target.path = datastorePath;
+
+ if (vmDiskFileInfo != NULL) {
+ def.capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */
+ def.allocation = vmDiskFileInfo->fileSize->value;
+
+ def.target.format = VIR_STORAGE_FILE_VMDK;
+ } else if (isoImageFileInfo != NULL) {
+ def.capacity = fileInfo->fileSize->value;
+ def.allocation = fileInfo->fileSize->value;
+
+ def.target.format = VIR_STORAGE_FILE_ISO;
+ } else if (floppyImageFileInfo != NULL) {
+ def.capacity = fileInfo->fileSize->value;
+ def.allocation = fileInfo->fileSize->value;
+
+ def.target.format = VIR_STORAGE_FILE_RAW;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("File '%s' has unknown type"), datastorePath);
+ goto cleanup;
+ }
+
+ xml = virStorageVolDefFormat(&pool, &def);
+
+ cleanup:
+ VIR_FREE(datastorePath);
+ esxVI_FileInfo_Free(&fileInfo);
+ VIR_FREE(def.key);
+
+ return xml;
+}
+
+
+
+static int
+esxStorageBackendVMFSVolumeDelete(virStorageVolPtr volume, unsigned int flags)
+{
+ int result = -1;
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ char *datastorePath = NULL;
+ esxVI_ManagedObjectReference *task = NULL;
+ esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
+
+ virCheckFlags(0, -1);
+
+ if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (esxVI_DeleteVirtualDisk_Task(priv->primary, datastorePath,
+ priv->primary->datacenter->_reference,
+ &task) < 0 ||
+ esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+ esxVI_Occurrence_None,
+ priv->parsedUri->autoAnswer,
+ &taskInfoState, &taskInfoErrorMessage) < 0) {
+ goto cleanup;
+ }
+
+ if (taskInfoState != esxVI_TaskInfoState_Success) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not delete volume: %s"),
+ taskInfoErrorMessage);
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ VIR_FREE(datastorePath);
+ esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
+
+ return result;
+
+}
+
+
+
+static int
+esxStorageBackendVMFSVolumeWipe(virStorageVolPtr volume, unsigned int flags)
+{
+ int result = -1;
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ char *datastorePath = NULL;
+ esxVI_ManagedObjectReference *task = NULL;
+ esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
+
+ virCheckFlags(0, -1);
+
+ if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (esxVI_ZeroFillVirtualDisk_Task(priv->primary, datastorePath,
+ priv->primary->datacenter->_reference,
+ &task) < 0 ||
+ esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+ esxVI_Occurrence_None,
+ priv->parsedUri->autoAnswer,
+ &taskInfoState, &taskInfoErrorMessage) < 0) {
+ goto cleanup;
+ }
+
+ if (taskInfoState != esxVI_TaskInfoState_Success) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not wipe volume: %s"),
+ taskInfoErrorMessage);
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ VIR_FREE(datastorePath);
+ esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
+
+ return result;
+
+}
+
+
+static char*
+esxStorageBackendVMFSVolumeGetPath(virStorageVolPtr volume)
+{
+ char *path;
+
+ if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ return path;
+
+}
+
+
+
+
+virStorageDriver esxStorageBackendVMFSDrv = {
+ .name = "ESX VMFS backend",
+ .open = NULL, /* 0.7.6 */
+ .close = NULL, /* 0.7.6 */
+ .numOfPools = esxStorageBackendVMFSNumberOfStoragePools, /* 0.8.2 */
+ .listPools = esxStorageBackendVMFSListStoragePools, /* 0.8.2 */
+ .poolLookupByName = esxStorageBackendVMFSPoolLookupByName, /* 0.8.2 */
+ .poolLookupByUUID = esxStorageBackendVMFSPoolLookupByUUID, /* 0.8.2 */
+ .poolRefresh = esxStorageBackendVMFSPoolRefresh, /* 0.8.2 */
+ .poolGetInfo = esxStorageBackendVMFSPoolGetInfo, /* 0.8.2 */
+ .poolGetXMLDesc = esxStorageBackendVMFSPoolGetXMLDesc, /* 0.8.2 */
+ .poolNumOfVolumes = esxStorageBackendVMFSPoolNumberOfStorageVolumes, /* 0.8.4 */
+ .poolListVolumes = esxStorageBackendVMFSPoolListStorageVolumes, /* 0.8.4 */
+ .volLookupByName = esxStorageBackendVMFSVolumeLookupByName, /* x.x.x */
+ .volLookupByKey = esxStorageBackendVMFSVolumeLookupByKey, /* 0.8.4 */
+ .volLookupByPath = esxStorageBackendVMFSVolumeLookupByPath, /* 0.8.4 */
+ .volCreateXML = esxStorageBackendVMFSVolumeCreateXML, /* 0.8.4 */
+ .volCreateXMLFrom = esxStorageBackendVMFSVolumeCreateXMLFrom, /* 0.8.7 */
+ .volGetXMLDesc = esxStorageBackendVMFSVolumeGetXMLDesc, /* 0.8.4 */
+ .volDelete = esxStorageBackendVMFSVolumeDelete, /* 0.8.7 */
+ .volWipe = esxStorageBackendVMFSVolumeWipe, /* 0.8.7 */
+ .volGetPath = esxStorageBackendVMFSVolumeGetPath, /* 0.10.0 */
+
+};
diff --git a/src/esx/esx_storage_backend_vmfs.h b/src/esx/esx_storage_backend_vmfs.h
new file mode 100644
index 0000000..d3adf73
--- /dev/null
+++ b/src/esx/esx_storage_backend_vmfs.h
@@ -0,0 +1,31 @@
+/*
+ * esx_storage_backend_vmfs.h: ESX storage backend for VMFS datastores
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Author: Ata E Husain Bohra (ata.husain(a)hotmail.com)
+ */
+
+#ifndef __ESX_STORAGE_BACKEND_VMFS_H__
+# define __ESX_STORAGE_BACKEND_VMFS_H__
+
+#include "driver.h"
+
+extern virStorageDriver esxStorageBackendVMFSDrv;
+
+#endif /* __ESX_STORAGE_BACKEND_VMFS_H__ */
+
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 348bd62..d4e81f3 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -24,82 +24,67 @@
#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_storage_backend_iscsi.h"
+#include "esx_storage_backend_vmfs.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.
+/**
+ * ESX storage driver implements a facade pattern;
+ * the driver exposes the routines supported by Libvirt
+ * public interface to manage ESX storage devices. Internally
+ * it uses backend drivers to perform the required task.
*/
-verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
+enum {
+ ISCSI = 0,
+ VMFS,
+ LAST_DRIVER
+};
+static virStorageDriverPtr backendDrv[LAST_DRIVER] = {NULL};
static int
-esxStoragePoolLookupType(esxVI_Context *ctx, const char *poolName,
- int *poolType)
+esxStorageGetBackendDriver(virConnectPtr conn, const char *name,
+ virStorageDriverPtr *backend)
{
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;
- }
+ int i = 0;
- for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
- dynamicProperty = dynamicProperty->_next) {
- if (STREQ(dynamicProperty->name, "info")) {
- if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
- &datastoreInfo) < 0) {
- goto cleanup;
- }
+ virCheckNonNullArgGoto(backend, cleanup);
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ const virStoragePoolPtr tempPool =
+ backendDrv[i]->poolLookupByName(conn, name);
+ if (tempPool != NULL) {
+ *backend = backendDrv[i];
break;
}
}
- if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- *poolType = VIR_STORAGE_POOL_DIR;
- } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- *poolType = VIR_STORAGE_POOL_NETFS;
- } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- *poolType = VIR_STORAGE_POOL_FS;
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("DatastoreInfo has unexpected type"));
+ if (*backend == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find storage pool with name '%s'"), name);
goto cleanup;
}
result = 0;
- cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastore);
- esxVI_DatastoreInfo_Free(&datastoreInfo);
+cleanup:
return result;
-}
-
+}
static virDrvOpenStatus
esxStorageOpen(virConnectPtr conn,
@@ -114,6 +99,10 @@ esxStorageOpen(virConnectPtr conn,
conn->storagePrivateData = conn->privateData;
+ /* set backend driver pointers */
+ backendDrv[ISCSI] = &esxStorageBackendISCSIDrv;
+ backendDrv[VMFS] = &esxStorageBackendVMFSDrv;
+
return VIR_DRV_OPEN_SUCCESS;
}
@@ -122,6 +111,13 @@ esxStorageOpen(virConnectPtr conn,
static int
esxStorageClose(virConnectPtr conn)
{
+ int i = 0;
+
+ /* reset the backend driver pointers */
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ backendDrv[i] = NULL;
+ }
+
conn->storagePrivateData = NULL;
return 0;
@@ -132,27 +128,28 @@ esxStorageClose(virConnectPtr conn)
static int
esxNumberOfStoragePools(virConnectPtr conn)
{
- int count = 0;
esxPrivate *priv = conn->storagePrivateData;
- esxVI_ObjectContent *datastoreList = NULL;
- esxVI_ObjectContent *datastore = NULL;
+ int count = 0;
+ int i = 0;
+ bool success = false;
if (esxVI_EnsureSession(priv->primary) < 0) {
- return -1;
+ goto cleanup;
}
- if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0) {
- return -1;
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ int tempCount = backendDrv[i]->numOfPools(conn);
+ if (tempCount < 0) {
+ goto cleanup;
+ }
+ count += tempCount;
}
- for (datastore = datastoreList; datastore != NULL;
- datastore = datastore->_next) {
- ++count;
- }
+ success = true;
- esxVI_ObjectContent_Free(&datastoreList);
+ cleanup:
- return count;
+ return success ? count : -1;
}
@@ -162,56 +159,32 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
{
bool success = false;
esxPrivate *priv = conn->storagePrivateData;
- esxVI_String *propertyNameList = NULL;
- esxVI_DynamicProperty *dynamicProperty = NULL;
- esxVI_ObjectContent *datastoreList = NULL;
- esxVI_ObjectContent *datastore = NULL;
int count = 0;
- int i;
+ int i = 0;
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);
- }
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ int tempCount =
+ backendDrv[i]->listPools(conn, &names[count], maxnames-count);
+
+ if (tempCount < 0) {
+ goto cleanup;
}
+
+ count += tempCount;
}
success = true;
cleanup:
+
if (! success) {
for (i = 0; i < count; ++i) {
VIR_FREE(names[i]);
@@ -220,10 +193,8 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
count = -1;
}
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastoreList);
-
return count;
+
}
@@ -252,43 +223,31 @@ static virStoragePoolPtr
esxStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
esxPrivate *priv = conn->storagePrivateData;
- esxVI_ObjectContent *datastore = NULL;
- esxVI_DatastoreHostMount *hostMount = NULL;
- unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
virStoragePoolPtr pool = NULL;
+ int i = 0;
- if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
+ virCheckNonNullArgGoto(name, cleanup);
- if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore,
- esxVI_Occurrence_RequiredItem) < 0) {
+ if (esxVI_EnsureSession(priv->primary) < 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;
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ pool = backendDrv[i]->poolLookupByName(conn, name);
+ if (pool != NULL) {
+ break;
+ }
}
- md5_buffer(hostMount->mountInfo->path,
- strlen(hostMount->mountInfo->path), md5);
-
- pool = virGetStoragePool(conn, name, md5);
+ if (pool == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find storage pool with name '%s'"), name);
+ }
- cleanup:
- esxVI_ObjectContent_Free(&datastore);
- esxVI_DatastoreHostMount_Free(&hostMount);
+cleanup:
return pool;
+
}
@@ -297,65 +256,31 @@ 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;
+ int i = 0;
- if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
+ virCheckNonNullArgGoto(uuid, cleanup);
- if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
- esxVI_LookupDatastoreList(priv->primary, propertyNameList,
- &datastoreList) < 0) {
+ if (esxVI_EnsureSession(priv->primary) < 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) {
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ pool = backendDrv[i]->poolLookupByUUID(conn, uuid);
+ if (pool != NULL) {
break;
}
}
- if (datastore == NULL) {
- virUUIDFormat(uuid, uuid_string);
-
- virReportError(VIR_ERR_NO_STORAGE_POOL,
- _("Could not find datastore with UUID '%s'"),
- uuid_string);
-
- goto cleanup;
- }
-
- if (esxVI_GetStringValue(datastore, "summary.name", &name,
- esxVI_Occurrence_RequiredItem) < 0) {
- goto cleanup;
+ if (pool == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find storage pool with uuid '%s'"), uuid);
}
- pool = virGetStoragePool(conn, name, uuid);
-
- cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastoreList);
- esxVI_DatastoreHostMount_Free(&hostMount);
+cleanup:
return pool;
+
}
@@ -373,26 +298,23 @@ esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
{
int result = -1;
esxPrivate *priv = pool->conn->storagePrivateData;
- esxVI_ObjectContent *datastore = NULL;
-
- virCheckFlags(0, -1);
+ virStorageDriverPtr backend = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
- return -1;
+ goto cleanup;
}
- if (esxVI_LookupDatastoreByName(priv->primary, pool->name, NULL, &datastore,
- esxVI_Occurrence_RequiredItem) < 0 ||
- esxVI_RefreshDatastore(priv->primary, datastore->obj) < 0) {
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0 ||
+ backend->poolRefresh(pool, flags) < 0) {
goto cleanup;
}
result = 0;
cleanup:
- esxVI_ObjectContent_Free(&datastore);
return result;
+
}
@@ -402,63 +324,25 @@ esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
{
int result = -1;
esxPrivate *priv = pool->conn->storagePrivateData;
- esxVI_String *propertyNameList = NULL;
- esxVI_ObjectContent *datastore = NULL;
- esxVI_DynamicProperty *dynamicProperty = NULL;
- esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+ virStorageDriverPtr backend = NULL;
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;
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0 ||
+ backend->poolGetInfo(pool, info) < 0) {
+ goto cleanup;
}
result = 0;
cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastore);
return result;
+
}
@@ -466,123 +350,24 @@ esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
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));
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ virStorageDriverPtr backend = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
-
- if (esxVI_String_AppendValueListToList(&propertyNameList,
- "summary.accessible\0"
- "summary.capacity\0"
- "summary.freeSpace\0"
- "info\0") < 0 ||
- esxVI_LookupDatastoreByName(priv->primary, pool->name,
- propertyNameList, &datastore,
- esxVI_Occurrence_RequiredItem) < 0 ||
- esxVI_GetBoolean(datastore, "summary.accessible",
- &accessible, esxVI_Occurrence_RequiredItem) < 0 ||
- esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
- &hostMount) < 0) {
goto cleanup;
}
- def.name = pool->name;
- memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
-
- def.target.path = hostMount->mountInfo->path;
-
- if (accessible == esxVI_Boolean_True) {
- for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
- dynamicProperty = dynamicProperty->_next) {
- if (STREQ(dynamicProperty->name, "summary.capacity")) {
- if (esxVI_AnyType_ExpectType(dynamicProperty->val,
- esxVI_Type_Long) < 0) {
- goto cleanup;
- }
-
- def.capacity = dynamicProperty->val->int64;
- } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
- if (esxVI_AnyType_ExpectType(dynamicProperty->val,
- esxVI_Type_Long) < 0) {
- goto cleanup;
- }
-
- def.available = dynamicProperty->val->int64;
- }
- }
-
- def.allocation = def.capacity - def.available;
- }
-
- for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
- dynamicProperty = dynamicProperty->_next) {
- if (STREQ(dynamicProperty->name, "info")) {
- if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
- &info) < 0) {
- goto cleanup;
- }
-
- break;
- }
- }
-
- /* See vSphere API documentation about HostDatastoreSystem for details */
- if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) {
- def.type = VIR_STORAGE_POOL_DIR;
- } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
- if (VIR_ALLOC_N(def.source.hosts, 1) < 0) {
- virReportOOMError();
- goto cleanup;
- }
- def.type = VIR_STORAGE_POOL_NETFS;
- def.source.hosts[0].name = nasInfo->nas->remoteHost;
- def.source.dir = nasInfo->nas->remotePath;
-
- if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
- def.source.format = VIR_STORAGE_POOL_NETFS_NFS;
- } else if (STRCASEEQ(nasInfo->nas->type, "CIFS")) {
- def.source.format = VIR_STORAGE_POOL_NETFS_CIFS;
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Datastore has unexpected type '%s'"),
- nasInfo->nas->type);
- goto cleanup;
- }
- } else if (esxVI_VmfsDatastoreInfo_DynamicCast(info) != NULL) {
- def.type = VIR_STORAGE_POOL_FS;
- /*
- * FIXME: I'm not sure how to represent the source and target of a
- * VMFS based datastore in libvirt terms
- */
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("DatastoreInfo has unexpected type"));
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
goto cleanup;
}
- xml = virStoragePoolDefFormat(&def);
+ xml = backend->poolGetXMLDesc(pool, flags);
cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastore);
- esxVI_DatastoreHostMount_Free(&hostMount);
- esxVI_DatastoreInfo_Free(&info);
return xml;
+
}
@@ -622,33 +407,25 @@ esxStoragePoolNumberOfStorageVolumes(virStoragePoolPtr pool)
{
bool success = false;
esxPrivate *priv = pool->conn->storagePrivateData;
- esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
- esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
- esxVI_FileInfo *fileInfo = NULL;
+ virStorageDriverPtr backend = NULL;
int count = 0;
if (esxVI_EnsureSession(priv->primary) < 0) {
- return -1;
+ goto cleanup;
}
- if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
- &searchResultsList) < 0) {
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
goto cleanup;
}
- /* Interpret search result */
- for (searchResults = searchResultsList; searchResults != NULL;
- searchResults = searchResults->_next) {
- for (fileInfo = searchResults->file; fileInfo != NULL;
- fileInfo = fileInfo->_next) {
- ++count;
- }
+ count = backend->poolNumOfVolumes(pool);
+ if (count < 0) {
+ goto cleanup;
}
success = true;
cleanup:
- esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
return success ? count : -1;
}
@@ -659,87 +436,25 @@ static int
esxStoragePoolListStorageVolumes(virStoragePoolPtr pool, char **const names,
int maxnames)
{
- bool success = false;
+ int result = -1;
esxPrivate *priv = pool->conn->storagePrivateData;
- esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
- esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
- esxVI_FileInfo *fileInfo = NULL;
- char *directoryAndFileName = NULL;
- size_t length;
- int count = 0;
- int i;
-
- if (names == NULL || maxnames < 0) {
- virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
- return -1;
- }
-
- if (maxnames == 0) {
- return 0;
- }
+ virStorageDriverPtr backend = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
- return -1;
- }
-
- if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
- &searchResultsList) < 0) {
goto cleanup;
}
- /* Interpret search result */
- for (searchResults = searchResultsList; searchResults != NULL;
- searchResults = searchResults->_next) {
- VIR_FREE(directoryAndFileName);
-
- if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL, NULL,
- &directoryAndFileName) < 0) {
- goto cleanup;
- }
-
- /* Strip trailing separators */
- length = strlen(directoryAndFileName);
-
- while (length > 0 && directoryAndFileName[length - 1] == '/') {
- directoryAndFileName[length - 1] = '\0';
- --length;
- }
-
- /* Build volume names */
- for (fileInfo = searchResults->file; fileInfo != NULL;
- fileInfo = fileInfo->_next) {
- if (length < 1) {
- names[count] = strdup(fileInfo->path);
-
- if (names[count] == NULL) {
- virReportOOMError();
- goto cleanup;
- }
- } else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName,
- fileInfo->path) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- ++count;
- }
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0 ||
+ backend->poolListVolumes(pool, names, maxnames) < 0) {
+ goto cleanup;
}
- success = true;
+ result = 0;
cleanup:
- if (! success) {
- for (i = 0; i < count; ++i) {
- VIR_FREE(names[i]);
- }
- count = -1;
- }
-
- esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
- VIR_FREE(directoryAndFileName);
+ return result;
- return count;
}
@@ -749,30 +464,24 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->storagePrivateData;
- char *datastorePath = NULL;
- char *key = NULL;
+ virStorageDriverPtr backend = NULL;
- if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
+ virCheckNonNullArgGoto(name, cleanup);
- if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) {
- virReportOOMError();
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary,
- datastorePath, &key) < 0) {
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
goto cleanup;
}
- volume = virGetStorageVol(pool->conn, pool->name, name, key);
+ volume = backend->volLookupByName(pool, name);
cleanup:
- VIR_FREE(datastorePath);
- VIR_FREE(key);
return volume;
+
}
@@ -782,32 +491,33 @@ esxStorageVolumeLookupByPath(virConnectPtr conn, const char *path)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = conn->storagePrivateData;
- char *datastoreName = NULL;
- char *directoryAndFileName = NULL;
- char *key = NULL;
- if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
+ virCheckNonNullArgGoto(path, cleanup);
- if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL,
- &directoryAndFileName) < 0) {
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path,
- &key) < 0) {
- goto cleanup;
+ /* FIXME: calling backend blindly may set unwanted error codes
+ *
+ * VMFS Datastore path follows cannonical format i.e.:
+ * [<datastore_name>] <file_path>
+ * WHEREAS
+ * iSCSI LUNs device path follows normal linux path convention
+ */
+ if (STRPREFIX(path, "[")) {
+ volume = backendDrv[VMFS]->volLookupByPath(conn, path);
+ } else if (STRPREFIX(path, "/")) {
+ volume = backendDrv[ISCSI]->volLookupByPath(conn, path);
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected volume path format: %s"), path);
}
- volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key);
-
- cleanup:
- VIR_FREE(datastoreName);
- VIR_FREE(directoryAndFileName);
- VIR_FREE(key);
+cleanup:
return volume;
+
}
@@ -817,140 +527,29 @@ 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);
- }
+ int i = 0;
- if (!priv->primary->hasQueryVirtualDiskUuid) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("QueryVirtualDiskUuid not available, cannot lookup storage "
- "volume by UUID"));
- return NULL;
- }
+ virCheckNonNullArgGoto(key, cleanup);
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;
- }
- }
+ /* lookup by key operation is supported using connection
+ * pointer, so poke all supported backend drivers to perform
+ * the desired operation
+ */
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ volume = backendDrv[i]->volLookupByKey(conn, key);
+ if (volume != NULL) {
+ break;
}
}
- 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);
+cleanup:
return volume;
+
}
@@ -961,224 +560,24 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->storagePrivateData;
- virStoragePoolDef poolDef;
- virStorageVolDefPtr def = NULL;
- char *tmp;
- char *unescapedDatastorePath = NULL;
- char *unescapedDirectoryName = NULL;
- char *unescapedDirectoryAndFileName = NULL;
- char *directoryName = NULL;
- char *fileName = NULL;
- char *datastorePathWithoutFileName = NULL;
- char *datastorePath = NULL;
- esxVI_FileInfo *fileInfo = NULL;
- esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
- esxVI_ManagedObjectReference *task = NULL;
- esxVI_TaskInfoState taskInfoState;
- char *taskInfoErrorMessage = NULL;
- char *uuid_string = NULL;
- char *key = NULL;
-
- virCheckFlags(0, NULL);
-
- memset(&poolDef, 0, sizeof(poolDef));
-
- if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
-
- if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) {
- return NULL;
- }
-
- /* Parse config */
- def = virStorageVolDefParseString(&poolDef, xmldesc);
+ virStorageDriverPtr backend = NULL;
- if (def == NULL) {
- goto cleanup;
- }
-
- if (def->type != VIR_STORAGE_VOL_FILE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Creating non-file volumes is not supported"));
- goto cleanup;
- }
-
- /* Validate config */
- tmp = strrchr(def->name, '/');
-
- if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Volume name '%s' doesn't have expected format "
- "'<directory>/<file>'"), def->name);
- goto cleanup;
- }
+ virCheckNonNullArgGoto(xmldesc, cleanup);
- if (! virFileHasSuffix(def->name, ".vmdk")) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
- def->name);
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
- def->name) < 0) {
- virReportOOMError();
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 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 == NULL) {
- goto cleanup;
- }
-
- fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
- strlen(unescapedDirectoryName) + 1);
-
- if (fileName == NULL) {
- goto cleanup;
- }
-
- if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
- directoryName) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
- fileName) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- /* Create directory, if it doesn't exist yet */
- if (esxVI_LookupFileInfoByDatastorePath
- (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
- esxVI_Occurrence_OptionalItem) < 0) {
- goto cleanup;
- }
-
- if (fileInfo == NULL) {
- if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
- priv->primary->datacenter->_reference,
- esxVI_Boolean_True) < 0) {
- goto cleanup;
- }
- }
-
- /* Create VirtualDisk */
- if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 ||
- esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) {
- goto cleanup;
- }
-
- /* From the vSphere API documentation about VirtualDiskType ... */
- if (def->allocation == def->capacity) {
- /*
- * "A preallocated disk has all space allocated at creation time
- * and the space is zeroed on demand as the space is used."
- */
- virtualDiskSpec->diskType = (char *)"preallocated";
- } else if (def->allocation == 0) {
- /*
- * "Space required for thin-provisioned virtual disk is allocated
- * and zeroed on demand as the space is used."
- */
- virtualDiskSpec->diskType = (char *)"thin";
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Unsupported capacity-to-allocation relation"));
- goto cleanup;
- }
-
- /*
- * FIXME: The adapter type is a required parameter, but there is no
- * way to let the user specify it in the volume XML config. Therefore,
- * default to 'busLogic' here.
- */
- virtualDiskSpec->adapterType = (char *)"busLogic";
-
- virtualDiskSpec->capacityKb->value =
- VIR_DIV_UP(def->capacity, 1024); /* Scale from byte to kilobyte */
-
- if (esxVI_CreateVirtualDisk_Task
- (priv->primary, datastorePath, priv->primary->datacenter->_reference,
- esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 ||
- esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
- esxVI_Occurrence_None,
- priv->parsedUri->autoAnswer,
- &taskInfoState,
- &taskInfoErrorMessage) < 0) {
- goto cleanup;
- }
-
- if (taskInfoState != esxVI_TaskInfoState_Success) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create volume: %s"),
- taskInfoErrorMessage);
- goto cleanup;
- }
-
- if (priv->primary->hasQueryVirtualDiskUuid) {
- if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
- priv->primary->datacenter->_reference,
- &uuid_string) < 0) {
- goto cleanup;
- }
-
- if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
- goto cleanup;
- }
- } else {
- /* Fall back to the path as key */
- if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
- goto cleanup;
- }
- }
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Creation of %s volumes is not supported"),
- virStorageFileFormatTypeToString(def->target.format));
- goto cleanup;
- }
-
- volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+ volume = backend->volCreateXML(pool, xmldesc, flags);
cleanup:
- if (virtualDiskSpec != NULL) {
- virtualDiskSpec->diskType = NULL;
- virtualDiskSpec->adapterType = NULL;
- }
-
- virStorageVolDefFree(def);
- VIR_FREE(unescapedDatastorePath);
- VIR_FREE(unescapedDirectoryName);
- VIR_FREE(unescapedDirectoryAndFileName);
- VIR_FREE(directoryName);
- VIR_FREE(fileName);
- VIR_FREE(datastorePathWithoutFileName);
- VIR_FREE(datastorePath);
- esxVI_FileInfo_Free(&fileInfo);
- esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
- esxVI_ManagedObjectReference_Free(&task);
- VIR_FREE(taskInfoErrorMessage);
- VIR_FREE(uuid_string);
- VIR_FREE(key);
return volume;
+
}
@@ -1189,193 +588,24 @@ esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
{
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) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Creating non-file volumes is not supported"));
- goto cleanup;
- }
-
- /* Validate config */
- tmp = strrchr(def->name, '/');
+ virStorageDriverPtr backend = NULL;
- if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Volume name '%s' doesn't have expected format "
- "'<directory>/<file>'"), def->name);
- goto cleanup;
- }
+ virCheckNonNullArgGoto(xmldesc, cleanup);
- if (! virFileHasSuffix(def->name, ".vmdk")) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
- def->name);
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
- def->name) < 0) {
- virReportOOMError();
+ if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 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 == NULL) {
- goto cleanup;
- }
-
- fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
- strlen(unescapedDirectoryName) + 1);
-
- if (fileName == NULL) {
- goto cleanup;
- }
-
- if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
- directoryName) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
- fileName) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- /* Create directory, if it doesn't exist yet */
- if (esxVI_LookupFileInfoByDatastorePath
- (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
- esxVI_Occurrence_OptionalItem) < 0) {
- goto cleanup;
- }
-
- if (fileInfo == NULL) {
- if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
- priv->primary->datacenter->_reference,
- esxVI_Boolean_True) < 0) {
- goto cleanup;
- }
- }
-
- /* Copy VirtualDisk */
- if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath,
- priv->primary->datacenter->_reference,
- datastorePath,
- priv->primary->datacenter->_reference,
- NULL, esxVI_Boolean_False, &task) < 0 ||
- esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
- esxVI_Occurrence_None,
- priv->parsedUri->autoAnswer,
- &taskInfoState,
- &taskInfoErrorMessage) < 0) {
- goto cleanup;
- }
-
- if (taskInfoState != esxVI_TaskInfoState_Success) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"),
- taskInfoErrorMessage);
- goto cleanup;
- }
-
- if (priv->primary->hasQueryVirtualDiskUuid) {
- if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
- priv->primary->datacenter->_reference,
- &uuid_string) < 0) {
- goto cleanup;
- }
-
- if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
- goto cleanup;
- }
- } else {
- /* Fall back to the path as key */
- if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
- goto cleanup;
- }
- }
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Creation of %s volumes is not supported"),
- virStorageFileFormatTypeToString(def->target.format));
- goto cleanup;
- }
-
- volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+ volume = backend->volCreateXMLFrom(pool, xmldesc, sourceVolume, flags);
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;
+
}
@@ -1383,48 +613,19 @@ esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
static int
esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags)
{
- int result = -1;
esxPrivate *priv = volume->conn->storagePrivateData;
- char *datastorePath = NULL;
- esxVI_ManagedObjectReference *task = NULL;
- esxVI_TaskInfoState taskInfoState;
- char *taskInfoErrorMessage = NULL;
-
- virCheckFlags(0, -1);
+ virStorageDriverPtr backend = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
}
- if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (esxVI_DeleteVirtualDisk_Task(priv->primary, datastorePath,
- priv->primary->datacenter->_reference,
- &task) < 0 ||
- esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
- esxVI_Occurrence_None,
- priv->parsedUri->autoAnswer,
- &taskInfoState, &taskInfoErrorMessage) < 0) {
- goto cleanup;
- }
-
- if (taskInfoState != esxVI_TaskInfoState_Success) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not delete volume: %s"),
- taskInfoErrorMessage);
- goto cleanup;
+ if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0 ||
+ backend->volDelete(volume , flags) < 0) {
+ return -1;
}
- result = 0;
-
- cleanup:
- VIR_FREE(datastorePath);
- esxVI_ManagedObjectReference_Free(&task);
- VIR_FREE(taskInfoErrorMessage);
-
- return result;
+ return 0;
}
@@ -1432,97 +633,39 @@ esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags)
static int
esxStorageVolumeWipe(virStorageVolPtr volume, unsigned int flags)
{
- int result = -1;
esxPrivate *priv = volume->conn->storagePrivateData;
- char *datastorePath = NULL;
- esxVI_ManagedObjectReference *task = NULL;
- esxVI_TaskInfoState taskInfoState;
- char *taskInfoErrorMessage = NULL;
-
- virCheckFlags(0, -1);
+ virStorageDriverPtr backend = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
}
- if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (esxVI_ZeroFillVirtualDisk_Task(priv->primary, datastorePath,
- priv->primary->datacenter->_reference,
- &task) < 0 ||
- esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
- esxVI_Occurrence_None,
- priv->parsedUri->autoAnswer,
- &taskInfoState, &taskInfoErrorMessage) < 0) {
- goto cleanup;
- }
-
- if (taskInfoState != esxVI_TaskInfoState_Success) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not wipe volume: %s"),
- taskInfoErrorMessage);
- goto cleanup;
+ if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0 ||
+ backend->volDelete(volume , flags) < 0) {
+ return -1;
}
- result = 0;
-
- cleanup:
- VIR_FREE(datastorePath);
- esxVI_ManagedObjectReference_Free(&task);
- VIR_FREE(taskInfoErrorMessage);
-
- return result;
+ return 0;
}
-
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));
+ virStorageDriverPtr backend = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
}
- if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
- false, &fileInfo,
- esxVI_Occurrence_RequiredItem) < 0) {
- goto cleanup;
- }
-
- vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
-
- info->type = VIR_STORAGE_VOL_FILE;
-
- if (vmDiskFileInfo != NULL) {
- info->capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */
- info->allocation = vmDiskFileInfo->fileSize->value;
- } else {
- info->capacity = fileInfo->fileSize->value;
- info->allocation = fileInfo->fileSize->value;
+ if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0 ||
+ backend->volGetInfo(volume , info) < 0) {
+ return -1;
}
- result = 0;
-
- cleanup:
- VIR_FREE(datastorePath);
- esxVI_FileInfo_Free(&fileInfo);
+ return 0;
- return result;
}
@@ -1530,84 +673,24 @@ esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
static char *
esxStorageVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
{
- esxPrivate *priv = volume->conn->storagePrivateData;
- virStoragePoolDef pool;
- char *datastorePath = NULL;
- esxVI_FileInfo *fileInfo = NULL;
- esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
- esxVI_IsoImageFileInfo *isoImageFileInfo = NULL;
- esxVI_FloppyImageFileInfo *floppyImageFileInfo = NULL;
- virStorageVolDef def;
char *xml = NULL;
-
- virCheckFlags(0, NULL);
-
- memset(&pool, 0, sizeof(pool));
- memset(&def, 0, sizeof(def));
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ virStorageDriverPtr backend = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
-
- if (esxStoragePoolLookupType(priv->primary, volume->pool, &pool.type) < 0) {
- return NULL;
- }
-
- /* Lookup file info */
- if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
- false, &fileInfo,
- esxVI_Occurrence_RequiredItem) < 0) {
goto cleanup;
}
- vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
- isoImageFileInfo = esxVI_IsoImageFileInfo_DynamicCast(fileInfo);
- floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo);
-
- def.name = volume->name;
-
- if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath,
- &def.key) < 0) {
- goto cleanup;
- }
-
- def.type = VIR_STORAGE_VOL_FILE;
- def.target.path = datastorePath;
-
- if (vmDiskFileInfo != NULL) {
- def.capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */
- def.allocation = vmDiskFileInfo->fileSize->value;
-
- def.target.format = VIR_STORAGE_FILE_VMDK;
- } else if (isoImageFileInfo != NULL) {
- def.capacity = fileInfo->fileSize->value;
- def.allocation = fileInfo->fileSize->value;
-
- def.target.format = VIR_STORAGE_FILE_ISO;
- } else if (floppyImageFileInfo != NULL) {
- def.capacity = fileInfo->fileSize->value;
- def.allocation = fileInfo->fileSize->value;
-
- def.target.format = VIR_STORAGE_FILE_RAW;
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("File '%s' has unknown type"), datastorePath);
+ if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0) {
goto cleanup;
}
- xml = virStorageVolDefFormat(&pool, &def);
+ xml = backend->volGetXMLDesc(volume, flags);
- cleanup:
- VIR_FREE(datastorePath);
- esxVI_FileInfo_Free(&fileInfo);
- VIR_FREE(def.key);
+ cleanup:
return xml;
+
}
@@ -1615,14 +698,24 @@ esxStorageVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
static char *
esxStorageVolumeGetPath(virStorageVolPtr volume)
{
- char *path;
+ char *path = NULL;
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ virStorageDriverPtr backend = NULL;
- if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) {
- virReportOOMError();
- return NULL;
+ if (esxVI_EnsureSession(priv->primary) < 0) {
+ goto cleanup;
}
+ if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0) {
+ goto cleanup;
+ }
+
+ path = backend->volGetPath(volume);
+
+ cleanup:
+
return path;
+
}
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 65e1d9a..0e647d4 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -3011,7 +3011,7 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
if (*datastore == NULL && occurrence != esxVI_Occurrence_OptionalItem) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Could not find datastore with name '%s'"), name);
+ _("Could not find datastore with name '%s'"), name);
goto cleanup;
}
@@ -3118,7 +3118,8 @@ esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx,
int
esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
esxVI_ManagedObjectReference *datastore,
- esxVI_DatastoreHostMount **hostMount)
+ esxVI_DatastoreHostMount **hostMount,
+ esxVI_Occurrence occurrence)
{
int result = -1;
esxVI_String *propertyNameList = NULL;
@@ -3166,9 +3167,9 @@ esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
break;
}
- if (*hostMount == NULL) {
+ if (*hostMount == NULL && occurrence != esxVI_Occurrence_OptionalItem) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Could not lookup datastore host mount"));
+ _("Could not lookup datastore host mount"));
goto cleanup;
}
@@ -4883,5 +4884,337 @@ esxVI_LookupManagedObjectHelper(esxVI_Context *ctx,
}
+int
+esxVI_LookupHostInternetScsiHbaStaticTargetByName(
+ esxVI_Context *ctx,
+ const char *name,
+ esxVI_HostInternetScsiHbaStaticTarget **ret,
+ esxVI_Occurrence occurrence)
+{
+ int result = -1;
+ esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+ const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+
+ if (esxVI_LookupHostInternetScsiHba(ctx, &hostInternetScsiHba) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to obtain hostInternetScsiHba"));
+ goto cleanup;
+ }
+
+ if (hostInternetScsiHba == NULL) {
+ /* iSCSI adapter may not be enabled for this host */
+ return 0;
+ }
+
+ if (hostInternetScsiHba->configuredStaticTarget) {
+ for (target = hostInternetScsiHba->configuredStaticTarget;
+ target != NULL; target = target->_next) {
+ if (STREQ(target->iScsiName, name)) {
+ break;
+ }
+ }
+ }
+
+ if (target == NULL) {
+ if (occurrence == esxVI_Occurrence_RequiredItem) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find storage pool with name: %s"), name);
+ }
+ goto cleanup;
+ }
+
+ if (esxVI_HostInternetScsiHbaStaticTarget_DeepCopy(
+ ret, (esxVI_HostInternetScsiHbaStaticTarget *)target) < 0) {
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+
+ esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+ return result;
+}
+
+
+int
+esxVI_LookupHostInternetScsiHba(
+ esxVI_Context *ctx,
+ esxVI_HostInternetScsiHba **hostInternetScsiHba)
+{
+ int result = -1;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_ObjectContent *hostSystem = NULL;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_HostHostBusAdapter *hostHostBusAdapterList = NULL;
+ esxVI_HostHostBusAdapter *hostHostBusAdapter = NULL;
+
+ if (esxVI_String_AppendValueToList(&propertyNameList,
+ "config.storageDevice.hostBusAdapter\0") < 0 ||
+ esxVI_LookupHostSystemProperties(ctx, propertyNameList,
+ &hostSystem) < 0) {
+ goto cleanup;
+ }
+
+ for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name,
+ "config.storageDevice.hostBusAdapter")) {
+ if (esxVI_HostHostBusAdapter_CastListFromAnyType(
+ dynamicProperty->val, &hostHostBusAdapterList) < 0 ||
+ hostHostBusAdapterList == NULL) {
+ goto cleanup;
+ }
+ } else {
+ VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+ }
+ }
+
+ /* See vSphere API documentation about HostInternetScsiHba for details */
+ for (hostHostBusAdapter = hostHostBusAdapterList; hostHostBusAdapter != NULL;
+ hostHostBusAdapter = hostHostBusAdapter->_next) {
+ esxVI_HostInternetScsiHba *candidate=
+ esxVI_HostInternetScsiHba_DynamicCast(hostHostBusAdapter);
+
+ if (candidate) {
+ if (esxVI_HostInternetScsiHba_DeepCopy(hostInternetScsiHba,
+ candidate) < 0) {
+ goto cleanup;
+ }
+ break;
+ }
+ }
+
+ result = 0;
+
+cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&hostSystem);
+ esxVI_HostHostBusAdapter_Free(&hostHostBusAdapterList);
+
+ return result;
+}
+
+int
+esxVI_LookupScsiLunList(esxVI_Context *ctx,
+ esxVI_ScsiLun **ret)
+{
+ int result = -1;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_ObjectContent *hostSystem = NULL;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ScsiLun *scsiLunList = NULL;
+
+ if (esxVI_String_AppendValueToList(&propertyNameList,
+ "config.storageDevice.scsiLun\0") < 0 ||
+ esxVI_LookupHostSystemProperties(
+ ctx, propertyNameList, &hostSystem) < 0) {
+ goto cleanup;
+ }
+
+ for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name,
+ "config.storageDevice.scsiLun")) {
+ if (esxVI_ScsiLun_CastListFromAnyType(dynamicProperty->val,
+ &scsiLunList) < 0) {
+ goto cleanup;
+ }
+ } else {
+ VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+ }
+ }
+
+ if (scsiLunList == NULL) {
+ goto cleanup;
+ }
+
+ /**
+ * FIXME: deep list copy operation fails with error:
+ * " libvir: ESX Driver error :
+ * internal error Call to esxVI_HostDevice_Free for
+ * unexpected type 'HostScsiDisk' "
+ * HostScsiDisk extends ScsiLun
+ */
+ *ret = scsiLunList;
+ scsiLunList = NULL; /* prevent double free */
+
+ result = 0;
+
+cleanup:
+
+ esxVI_ScsiLun_Free(&scsiLunList);
+
+ return result;
+
+}
+
+int
+esxVI_LookupHostScsiTopologyLunListByTargetName(
+ esxVI_Context *ctx, const char *name, esxVI_HostScsiTopologyLun **ret)
+{
+ int result = -1;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_ObjectContent *hostSystem = NULL;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
+ const esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
+ const esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
+ bool found = false;
+
+ if (esxVI_String_AppendValueToList(&propertyNameList,
+ "config.storageDevice.scsiTopology.adapter\0") < 0 ||
+ esxVI_LookupHostSystemProperties(
+ ctx, propertyNameList, &hostSystem) < 0) {
+ goto cleanup;
+ }
+
+ for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name,
+ "config.storageDevice.scsiTopology.adapter")) {
+ esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+ if ((esxVI_HostScsiTopologyInterface_CastListFromAnyType
+ (dynamicProperty->val, &hostScsiInterfaceList) < 0)) {
+ goto cleanup;
+ }
+ } else {
+ VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+ }
+ }
+
+ if (hostScsiInterfaceList == NULL) {
+ /* iSCSI adapter may not be enabled */
+ return 0;
+ }
+
+ /* See vSphere API documentation about HostScsiTopologyInterface */
+ for (hostScsiInterface = hostScsiInterfaceList;
+ hostScsiInterface != NULL && !found;
+ hostScsiInterface = hostScsiInterface->_next) {
+ for (hostScsiTopologyTarget = hostScsiInterface->target;
+ hostScsiTopologyTarget != NULL;
+ hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
+ const esxVI_HostInternetScsiTargetTransport *candidate =
+ esxVI_HostInternetScsiTargetTransport_DynamicCast(
+ hostScsiTopologyTarget->transport);
+
+ if (candidate && STREQ(candidate->iScsiName, name)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found || hostScsiTopologyTarget == NULL) {
+ goto cleanup;
+ }
+
+ if (esxVI_HostScsiTopologyLun_DeepCopyList(
+ ret, hostScsiTopologyTarget->lun) < 0) {
+ goto cleanup;
+ }
+
+ if (*ret == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Target not found"));
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&hostSystem);
+ esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+ return result;
+}
+
+
+int
+esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx,
+ const char *key,
+ char **poolName)
+{
+ int result = -1;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_ObjectContent *hostSystem = NULL;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
+ const esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
+ const esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
+ bool found = false;
+
+ if (esxVI_String_AppendValueToList(&propertyNameList,
+ "config.storageDevice.scsiTopology.adapter\0") < 0 ||
+ esxVI_LookupHostSystemProperties(
+ ctx, propertyNameList, &hostSystem) < 0) {
+ goto cleanup;
+ }
+
+ for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name,
+ "config.storageDevice.scsiTopology.adapter")) {
+ esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+ if ((esxVI_HostScsiTopologyInterface_CastListFromAnyType
+ (dynamicProperty->val, &hostScsiInterfaceList) < 0)) {
+ goto cleanup;
+ }
+ } else {
+ VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+ }
+ }
+
+ if (hostScsiInterfaceList == NULL) {
+ /* iSCSI adapter may not be enabled */
+ return 0;
+ }
+
+ /* See vSphere API documentation about HostScsiTopologyInterface */
+ for (hostScsiInterface = hostScsiInterfaceList;
+ hostScsiInterface != NULL && !found;
+ hostScsiInterface = hostScsiInterface->_next) {
+ for (hostScsiTopologyTarget = hostScsiInterface->target;
+ hostScsiTopologyTarget != NULL;
+ hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
+ const esxVI_HostInternetScsiTargetTransport *candidate =
+ esxVI_HostInternetScsiTargetTransport_DynamicCast(
+ hostScsiTopologyTarget->transport);
+
+ if (candidate) {
+ /* iterate hostScsiTopologyLun list to find matching key */
+ const esxVI_HostScsiTopologyLun *hostScsiTopologyLun =
+ hostScsiTopologyTarget->lun;
+ for (; hostScsiTopologyLun != NULL;
+ hostScsiTopologyLun = hostScsiTopologyLun->_next) {
+ if (STREQ(hostScsiTopologyLun->scsiLun, key)) {
+ *poolName = strdup(candidate->iScsiName);
+
+ if (*poolName == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ result = 0;
+
+ cleanup:
+ esxVI_ObjectContent_Free(&hostSystem);
+ esxVI_String_Free(&propertyNameList);
+ esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+ return result;
+}
#include "esx_vi.generated.c"
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 12394e7..6149c2d 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -438,7 +438,8 @@ int esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx,
int esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
esxVI_ManagedObjectReference *datastore,
- esxVI_DatastoreHostMount **hostMount);
+ esxVI_DatastoreHostMount **hostMount,
+ esxVI_Occurrence occurrence);
int esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
esxVI_ManagedObjectReference *task,
@@ -524,6 +525,24 @@ int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
int esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion);
+int esxVI_LookupHostInternetScsiHbaStaticTargetByName(esxVI_Context *ctx,
+ const char *name, esxVI_HostInternetScsiHbaStaticTarget **ret,
+ esxVI_Occurrence occurrence);
+
+int esxVI_LookupHostInternetScsiHba(
+ esxVI_Context *ctx,
+ esxVI_HostInternetScsiHba **hostInternetScsiHba);
+
+int esxVI_LookupScsiLunList(esxVI_Context *ctx, esxVI_ScsiLun **ret);
+
+int esxVI_LookupHostScsiTopologyLunListByTargetName(
+ esxVI_Context *ctx, const char *name, esxVI_HostScsiTopologyLun **ret);
+
+int
+esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx,
+ const char *key,
+ char **poolName);
+
# include "esx_vi.generated.h"
#endif /* __ESX_VI_H__ */
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index c4a3e56..6e50be5 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -58,6 +58,14 @@ enum AutoStartWaitHeartbeatSetting
end
+enum FibreChannelPortType
+ fabric
+ loop
+ pointToPoint
+ unknown
+end
+
+
enum ManagedEntityStatus
gray
green
@@ -128,6 +136,11 @@ enum VirtualMachinePowerState
end
+enum vStorageSupport
+ vStorageUnknown
+end
+
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Objects
#
@@ -263,6 +276,13 @@ object HostAutoStartManagerConfig
end
+object HostBlockAdapterTargetTransport extends HostTargetTransport
+end
+
+object HostBlockHba extends HostHostBusAdapter
+end
+
+
object HostConfigManager
ManagedObjectReference cpuScheduler o
ManagedObjectReference datastoreSystem o
@@ -310,6 +330,32 @@ object HostDatastoreBrowserSearchSpec
end
+object HostDevice
+ String deviceName r
+ String deviceType r
+end
+
+
+object HostDiskDimensionsLba
+ Int blockSize r
+ Long block r
+end
+
+
+object HostFibreChannelHba extends HostHostBusAdapter
+ Long nodeWorldWideName r
+ FibreChannelPortType portType r
+ Long portWorldWideName r
+ Long speed r
+end
+
+
+object HostFibreChannelTargetTransport extends HostTargetTransport
+ Long nodeWorldWideName r
+ Long portWorldWideName r
+end
+
+
object HostFileSystemVolume
String type r
String name r
@@ -317,11 +363,171 @@ object HostFileSystemVolume
end
+object HostHostBusAdapter
+ Int bus r
+ String device r
+ String driver o
+ String key o
+ String model r
+ String pci o
+ String status r
+end
+
+
+object HostInternetScsiTargetTransport extends HostTargetTransport
+ String iScsiName r
+ String iScsiAlias r
+ String address ol
+
+end
+
+
+object HostInternetScsiHba extends HostHostBusAdapter
+ HostInternetScsiHbaAuthenticationCapabilities authenticationCapabilities r
+ HostInternetScsiHbaAuthenticationProperties authenticationProperties r
+ HostInternetScsiHbaDiscoveryCapabilities discoveryCapabilities r
+ HostInternetScsiHbaDiscoveryProperties discoveryProperties r
+ HostInternetScsiHbaIPCapabilities ipCapabilities r
+ HostInternetScsiHbaIPProperties ipProperties r
+ String iScsiName r
+ Boolean isSoftwareBased r
+ HostInternetScsiHbaParamValue advancedOptions ol
+ HostInternetScsiHbaSendTarget configuredSendTarget ol
+ HostInternetScsiHbaStaticTarget configuredStaticTarget ol
+ Int currentSpeedMb o
+ HostInternetScsiHbaDigestCapabilities digestCapabilities o
+ HostInternetScsiHbaDigestProperties digestProperties o
+ String iScsiAlias o
+ Int maxSpeedMb o
+ OptionDef supportedAdvancedOptions ol
+end
+
+
+
+object HostInternetScsiHbaAuthenticationCapabilities
+ Boolean chapAuthSettable r
+ Boolean krb5AuthSettable r
+ Boolean spkmAuthSettable r
+ Boolean srpAuthSettable r
+ Boolean mutualChapSettable o
+ Boolean targetChapSettable o
+ Boolean targetMutualChapSettable o
+end
+
+
+object HostInternetScsiHbaAuthenticationProperties
+ Boolean chapAuthEnabled r
+ String chapAuthenticationType o
+ Boolean chapInherited o
+ String chapName o
+ String chapSecret o
+ String mutualChapAuthenticationType o
+ Boolean mutualChapInherited o
+ String mutualChapName o
+ String mutualChapSecret o
+end
+
+
+object HostInternetScsiHbaDigestCapabilities
+ Boolean dataDigestSettable o
+ Boolean headerDigestSettable o
+ Boolean targetDataDigestSettable o
+ Boolean targetHeaderDigestSettable o
+end
+
+
+object HostInternetScsiHbaDigestProperties
+ Boolean dataDigestInherited o
+ String dataDigestType o
+ Boolean headerDigestInherited o
+ String headerDigestType o
+end
+
+
+object HostInternetScsiHbaDiscoveryCapabilities
+ Boolean iSnsDiscoverySettable r
+ Boolean sendTargetsDiscoverySettable r
+ Boolean slpDiscoverySettable r
+ Boolean staticTargetDiscoverySettable r
+end
+
+
+object HostInternetScsiHbaDiscoveryProperties
+ Boolean iSnsDiscoveryEnabled r
+ Boolean sendTargetsDiscoveryEnabled r
+ Boolean slpDiscoveryEnabled r
+ Boolean staticTargetDiscoveryEnabled r
+ String iSnsDiscoveryMethod o
+ String iSnsHost o
+ String slpDiscoveryMethod o
+ String slpHost o
+end
+
+
+object HostInternetScsiHbaIPCapabilities
+ Boolean addressSettable r
+ Boolean alternateDnsServerAddressSettable r
+ Boolean defaultGatewaySettable r
+ Boolean ipConfigurationMethodSettable r
+ Boolean primaryDnsServerAddressSettable r
+ Boolean subnetMaskSettable r
+ Boolean arpRedirectSettable o
+ Boolean hostNameAsTargetAddress o
+ Boolean ipv6Supported o
+ Boolean mtuSettable o
+ Boolean nameAliasSettable o
+end
+
+
+object HostInternetScsiHbaIPProperties
+ Boolean dhcpConfigurationEnabled r
+ String address o
+ String alternateDnsServerAddress o
+ Boolean arpRedirectEnabled o
+ String defaultGateway o
+ String ipv6Address o
+ String ipv6DefaultGateway o
+ Boolean jumboFramesEnabled o
+ String mac o
+ Int mtu o
+ String primaryDnsServerAddress o
+ String subnetMask o
+end
+
+
+object HostInternetScsiHbaParamValue extends OptionValue
+ Boolean isInherited o
+end
+
+
+object HostInternetScsiHbaSendTarget
+ String address r
+ HostInternetScsiHbaParamValue advancedOptions ol
+ HostInternetScsiHbaAuthenticationProperties authenticationProperties o
+ HostInternetScsiHbaDigestProperties digestProperties o
+ String parent o
+ Int port o
+ OptionDef supportedAdvancedOptions ol
+end
+
+
+object HostInternetScsiHbaStaticTarget
+ String address r
+ String iScsiName r
+ HostInternetScsiHbaParamValue advancedOptions ol
+ HostInternetScsiHbaAuthenticationProperties authenticationProperties o
+ HostInternetScsiHbaDigestProperties digestProperties o
+ String parent o
+ Int port o
+ OptionDef supportedAdvancedOptions ol
+end
+
+
+
object HostIpConfig
Boolean dhcp r
String ipAddress o
String subnetMask o
-end
object HostMountInfo
@@ -416,6 +622,19 @@ object HostPortGroupSpec
Int vlanId r
String vswitchName r
HostNetworkPolicy policy r
+
+
+object HostParallelScsiHba extends HostHostBusAdapter
+end
+
+
+object HostParallelScsiTargetTransport extends HostTargetTransport
+end
+
+
+object HostScsiDisk extends ScsiLun
+ HostDiskDimensionsLba capacity r
+ String devicePath r
end
@@ -425,6 +644,37 @@ object HostScsiDiskPartition
end
+object HostScsiTopology
+ HostScsiTopologyInterface adapater ol
+end
+
+
+object HostScsiTopologyInterface
+ String adapter r
+ String key r
+ HostScsiTopologyTarget target ol
+end
+
+
+object HostScsiTopologyLun
+ String key r
+ Int lun r
+ String scsiLun r
+end
+
+
+object HostScsiTopologyTarget
+ String key r
+ Int target r
+ HostScsiTopologyLun lun ol
+ HostTargetTransport transport o
+end
+
+
+object HostTargetTransport
+end
+
+
object HostVirtualSwitch
String name r
String key r
@@ -467,7 +717,6 @@ object HostVirtualSwitchSpec
HostVirtualSwitchBridge bridge o
HostNetworkPolicy policy o
Int mtu o
-end
object HostVmfsVolume extends HostFileSystemVolume
@@ -527,11 +776,22 @@ object ObjectUpdate
end
+object OptionDef extends ElementDescription
+ OptionType optionType r
+end
+
+
object OptionType
Boolean valueIsReadonly o
end
+object OptionValue
+ String key r
+ AnyType value r
+end
+
+
object PerfCounterInfo
Int key r
ElementDescription nameInfo r
@@ -664,6 +924,45 @@ object SelectionSpec
end
+object ScsiLun extends HostDevice
+ String lunType r
+ String operationalState rl
+ String uuid r
+ ScsiLunDurableName alternateName ol
+ String canonicalName o
+ ScsiLunCapabilities capabilities o
+ ScsiLunDescriptor descriptor ol
+ String displayName o
+ ScsiLunDurableName durableName o
+ String key o
+ String model o
+ Int queueDepth o
+ String revision o
+ Int scsiLevel o
+ String serialNumber o
+ Byte standardInquiry ol
+ String vendor o
+end
+
+
+object ScsiLunCapabilities
+ Boolean updateDisplayNameSupported r
+end
+
+
+object ScsiLunDescriptor
+ String id r
+ String quality r
+end
+
+
+object ScsiLunDurableName
+ String namespace r
+ Byte namespaceId r
+ Byte data ol
+end
+
+
object ServiceContent
ManagedObjectReference rootFolder r
ManagedObjectReference propertyCollector r
@@ -1135,6 +1434,11 @@ end
method RemoveVirtualSwitch
ManagedObjectReference _this r
String vswitchName r
+
+
+method RescanHba
+ ManagedObjectReference _this r
+ String hbaDevice r
end
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index b49db70..7c0c1f2 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -1520,6 +1520,21 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN
Object.FEATURE__ANY_TYPE,
"HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST |
Object.FEATURE__ANY_TYPE,
+ "HostHostBusAdapter" : Object.FEATURE__LIST |
+ Object.FEATURE__ANY_TYPE,
+ "HostInternetScsiHba" : Object.FEATURE__DYNAMIC_CAST |
+ Object.FEATURE__DEEP_COPY,
+ "HostInternetScsiTargetTransport" : Object.FEATURE__DYNAMIC_CAST,
+ "HostScsiDisk" : Object.FEATURE__LIST |
+ Object.FEATURE__ANY_TYPE |
+ Object.FEATURE__DYNAMIC_CAST,
+ "HostScsiTopologyInterface" : Object.FEATURE__LIST |
+ Object.FEATURE__ANY_TYPE,
+ "HostScsiTopologyLun" : Object.FEATURE__ANY_TYPE |
+ Object.FEATURE__LIST |
+ Object.FEATURE__DEEP_COPY,
+ "HostScsiTopologyTarget" : Object.FEATURE__ANY_TYPE |
+ Object.FEATURE__LIST,
"HostPortGroup" : Object.FEATURE__LIST |
Object.FEATURE__ANY_TYPE,
"HostVirtualSwitch" : Object.FEATURE__DEEP_COPY |
@@ -1531,6 +1546,10 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN
Object.FEATURE__LIST |
Object.FEATURE__ANY_TYPE,
"ResourcePoolResourceUsage" : Object.FEATURE__ANY_TYPE,
+ "ScsiLun" : Object.FEATURE__LIST |
+ Object.FEATURE__ANY_TYPE |
+ Object.FEATURE__DEEP_COPY,
+ "ScsiLunDurableName" : Object.FEATURE__LIST,
"ServiceContent" : Object.FEATURE__DESERIALIZE,
"SharesInfo" : Object.FEATURE__ANY_TYPE,
"TaskInfo" : Object.FEATURE__LIST |
--
1.7.9.5
12 years, 2 months
[libvirt] [PATCH 0/4] snapshot: work towards external system checkpoint
by Eric Blake
I've previously posted 1/4, it is now rebased to latest and some
bugs fixed that I found while testing later patches:
https://www.redhat.com/archives/libvir-list/2012-August/msg01252.html
The other three are new. My next snapshot task will be hooking up
external snapshots for an offline domain.
Eric Blake (4):
snapshot: new XML for external system checkpoint
snapshot: improve disk align checking
snapshot: populate new XML info for qemu snapshots
snapshot: merge pre-snapshot checks
docs/formatsnapshot.html.in | 11 ++
docs/schemas/domainsnapshot.rng | 23 ++++
src/conf/snapshot_conf.c | 91 ++++++++++----
src/conf/snapshot_conf.h | 4 +
src/qemu/qemu_driver.c | 133 ++++++++++-----------
tests/domainsnapshotxml2xmlin/external_vm.xml | 10 ++
tests/domainsnapshotxml2xmlin/noparent.xml | 9 ++
tests/domainsnapshotxml2xmlout/all_parameters.xml | 1 +
tests/domainsnapshotxml2xmlout/disk_snapshot.xml | 1 +
tests/domainsnapshotxml2xmlout/external_vm.xml | 43 +++++++
tests/domainsnapshotxml2xmlout/full_domain.xml | 1 +
tests/domainsnapshotxml2xmlout/metadata.xml | 1 +
tests/domainsnapshotxml2xmlout/noparent.xml | 1 +
.../noparent_nodescription.xml | 1 +
.../noparent_nodescription_noactive.xml | 1 +
tests/domainsnapshotxml2xmltest.c | 1 +
16 files changed, 241 insertions(+), 91 deletions(-)
create mode 100644 tests/domainsnapshotxml2xmlin/external_vm.xml
create mode 100644 tests/domainsnapshotxml2xmlin/noparent.xml
create mode 100644 tests/domainsnapshotxml2xmlout/external_vm.xml
--
1.7.11.4
12 years, 2 months
[libvirt] [PATCH 00/12]
by Daniel P. Berrange
An update of
https://www.redhat.com/archives/libvir-list/2012-August/msg00618.html
Mostly this is a rebase to latest GIT. Alot of the questions raised
with review last time bogged down on whether the APIs were design
in the right way. I think I clarified their intended usage, so
hopefully we can do code review this time :-)
There are still a few more patches to add on to this
- Serialize the tx/rx message queues so we don't loose
partially sent/received messages across re-exec()
- Make fcntl driver more configurable in its behaviour
- Add support for leases based on LVM UUID and SCSI
WWN
12 years, 2 months
[libvirt] [PATCH] node_memory: Add new parameter field to tune the new sysfs knob
by Osier Yang
Upstream kernel introduced new sysfs knob "merge_across_nodes" to
specify if pages from different numa nodes can be merged. When set
to 0, only pages which physically reside in the memory area of
same NUMA node can be merged. When set to 1, pages from all nodes
can be merged.
This patch supports the tuning by adding new param field
"shm-merge-across-nodes".
---
Perhaps two bool options like "--disable-shm-merge-across-nodes",
and "--enable-shm-merge-across-nodes" are good, but could the
kernel sysfs knob have other values beyond 0 and 1 in future?
---
include/libvirt/libvirt.h.in | 10 ++++++++++
src/nodeinfo.c | 26 +++++++++++++++++++++++---
tools/virsh-host.c | 20 ++++++++++++++++++++
tools/virsh.pod | 5 ++++-
4 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 81f12a4..56ee2f5 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -4489,6 +4489,16 @@ typedef virMemoryParameter *virMemoryParameterPtr;
*/
# define VIR_NODE_MEMORY_SHARED_FULL_SCANS "shm_full_scans"
+/* VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES:
+ *
+ * Macro for typed parameter that represents whether pages from
+ * different NUMA nodes can be merged, when its value is 0, only
+ * pages which physically reside in the memory area of same NUMA
+ * node are merged, otherwise pages from all nodes can be merged.
+ */
+# define VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES "shm_merge_across_nodes"
+
+
int virNodeGetMemoryParameters(virConnectPtr conn,
virTypedParameterPtr params,
int *nparams,
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 021eb05..6002789 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -1004,6 +1004,13 @@ nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED,
/* Out of memory */
if (ret == -2)
return -1;
+ } else if (STREQ(param->field,
+ VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES)) {
+ ret = nodeSetMemoryParameterValue("merge_across_nodes", param);
+
+ /* Out of memory */
+ if (ret == -2)
+ return -1;
}
}
@@ -1039,8 +1046,9 @@ nodeGetMemoryParameterValue(const char *field,
if ((tmp = strchr(buf, '\n')))
*tmp = '\0';
- if (STREQ(field, "pages_to_scan") ||
- STREQ(field, "sleep_millisecs"))
+ if (STREQ(field, "pages_to_scan") ||
+ STREQ(field, "sleep_millisecs") ||
+ STREQ(field, "merge_across_nodes"))
rc = virStrToLong_ui(buf, NULL, 10, (unsigned int *)value);
else if (STREQ(field, "pages_shared") ||
STREQ(field, "pages_sharing") ||
@@ -1063,7 +1071,7 @@ cleanup:
}
#endif
-#define NODE_MEMORY_PARAMETERS_NUM 7
+#define NODE_MEMORY_PARAMETERS_NUM 8
int
nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED,
virTypedParameterPtr params ATTRIBUTE_UNUSED,
@@ -1075,6 +1083,7 @@ nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED,
#ifdef __linux__
unsigned int pages_to_scan;
unsigned int sleep_millisecs;
+ unsigned int merge_across_nodes;
unsigned long long pages_shared;
unsigned long long pages_sharing;
unsigned long long pages_unshared;
@@ -1168,6 +1177,17 @@ nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED,
break;
+ case 7:
+ if (nodeGetMemoryParameterValue("merge_across_nodes",
+ &merge_across_nodes) < 0)
+ return -1;
+
+ if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
+ VIR_TYPED_PARAM_UINT, merge_across_nodes) < 0)
+ return -1;
+
+ break;
+
default:
break;
}
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index 2c46336..62ecafc 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -900,6 +900,8 @@ static const vshCmdOptDef opts_node_memory_tune[] = {
{"shm-sleep-millisecs", VSH_OT_INT, VSH_OFLAG_NONE,
N_("number of millisecs the shared memory service should "
"sleep before next scan")},
+ {"shm-merge-across-nodes", VSH_OT_INT, VSH_OFLAG_NONE,
+ N_("Specifies if pages from different numa nodes can be merged")},
{NULL, 0, 0, NULL}
};
@@ -911,6 +913,7 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd)
unsigned int flags = 0;
unsigned int shm_pages_to_scan = 0;
unsigned int shm_sleep_millisecs = 0;
+ unsigned int shm_merge_across_nodes = 0;
bool ret = false;
int i = 0;
@@ -926,12 +929,21 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd)
return false;
}
+ if (vshCommandOptUInt(cmd, "shm-merge-across-nodes",
+ &shm_merge_across_nodes) < 0) {
+ vshError(ctl, "%s", _("invalid shm-merge-across-nodes number"));
+ return false;
+ }
+
if (shm_pages_to_scan)
nparams++;
if (shm_sleep_millisecs)
nparams++;
+ if (shm_merge_across_nodes)
+ nparams++;
+
if (nparams == 0) {
/* Get the number of memory parameters */
if (virNodeGetMemoryParameters(ctl->conn, NULL, &nparams, flags) != 0) {
@@ -983,6 +995,14 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd)
goto error;
}
+ if (i < nparams && shm_merge_across_nodes) {
+ if (virTypedParameterAssign(¶ms[i++],
+ VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
+ VIR_TYPED_PARAM_UINT,
+ shm_merge_across_nodes) < 0)
+ goto error;
+ }
+
if (virNodeSetMemoryParameters(ctl->conn, params, nparams, flags) != 0)
goto error;
else
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 2120429..d975f06 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -299,7 +299,10 @@ Allows you to display or set the node memory parameters.
I<shm-pages-to-scan> can be used to set the number of pages to scan
before the shared memory service goes to sleep; I<shm-sleep-millisecs>
can be used to set the number of millisecs the shared memory service should
-sleep before next scan.
+sleep before next scan; I<shm-merge-across-nodes> specifies if pages from
+different numa nodes can be merged. When set to 0, only pages which physically
+reside in the memory area of same NUMA node can be merged. When set to 1,
+pages from all nodes can be merged. Default to 1.
=item B<capabilities>
--
1.7.7.3
12 years, 2 months
[libvirt] Potential race condition problem
by Benjamin Wang (gendwang)
Hi,
Currently virInitialize() method defined in libvirt.c has the following code:
int
virInitialize(void)
{
if (initialized)
return 0;
initialized = 1;
if (virThreadInitialize() < 0 ||
virErrorInitialize() < 0 ||
virRandomInitialize(time(NULL) ^ getpid()) ||
virNodeSuspendInit() < 0)
return -1;
......
}
When two threads access virInitialize method, there is no lock for the "initialized" parameter. If the first thread enters this method and set "initialized" to 1,
the second thread could see that "initialized" is 1(Because initialized is not volatiled, I say could). In some situation, before the first thread finishes all the initialization,
the second thread could use some resources which should be initialized in Initialize method.
If you have any comments, please let me know. Thanks!
B.R.
Benjamin Wang
12 years, 2 months
[libvirt] [PATCHv7 0/9] blockjob: live block migration
by Eric Blake
v6 of these patches is here:
https://www.redhat.com/archives/libvir-list/2012-April/msg01240.html
The 'drive-mirror' command not only missed qemu 1.1 (back when I
first posted these patches), but also missed qemu 1.2. Paolo
is still working on re-posting his patches to the qemu lists
(see patch 2/9 for a link to his previous posting, which has had
two months of commentary). I'm still not anxious to have these
commands committed to upstream libvirt until 'drive-mirror' is
at least in qemu.git rather than just Paolo's tree, but thought
it would be worth rebasing the series to track the things that
have changed since April.
In v7, I've adjusted the series to cater to Paolo's proposed QMP
semantics (most of the review on his last patch to the qemu list
was on the internals, and not the interface itself), as well as to
allow working out-of-the-box with the RHEL 6.3 implementation of
block copy.
Unfortunately, since Paolo's patches are still in flux, I suspect
this will need a v8 that has seen further testing with both upstream
qemu.git and RHEL 6.3 git.
Eric Blake (9):
blockjob: react to active block copy
blockjob: add qemu capabilities related to block jobs
blockjob: return appropriate event and info
blockjob: support pivot operation on cancel
blockjob: make drive-reopen safer
blockjob: implement block copy for qemu
blockjob: allow for existing files
blockjob: allow mirroring under SELinux and cgroup
blockjob: relabel entire existing chain
include/libvirt/libvirt.h.in | 1 +
src/conf/domain_conf.c | 12 ++
src/conf/domain_conf.h | 1 +
src/libvirt.c | 7 +-
src/libvirt_private.syms | 1 +
src/qemu/qemu_capabilities.c | 2 +
src/qemu/qemu_capabilities.h | 2 +
src/qemu/qemu_driver.c | 413 ++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_hotplug.c | 7 +
src/qemu/qemu_monitor.c | 52 ++++++
src/qemu/qemu_monitor.h | 14 ++
src/qemu/qemu_monitor_json.c | 101 ++++++++++-
src/qemu/qemu_monitor_json.h | 21 ++-
src/qemu/qemu_process.c | 2 +
14 files changed, 625 insertions(+), 11 deletions(-)
--
1.7.11.4
12 years, 2 months
[libvirt] 100+ misspellings
by Jim Meyering
Hello,
In case someone is interested in weeding out the inevitable false
positives, here is a slightly filtered list of misspelled words
in libvirt, as detected by the misspellings program from here:
http://github.com/lyda/misspell-check
Here's the output from this command:
misspellings $(git ls-files)|grep -vE 'gnulib/|po/|ChangeLog-old'
HACKING:456: particulary -> "particularly"
configure.ac:1359: presense -> "presence"
daemon/libvirtd.conf:254: upto -> "up to"
daemon/libvirtd.conf:270: upto -> "up to"
daemon/stream.c:692: upto -> "up to"
docs/api.html.in:67: garanteed -> "guaranteed"
docs/api.html.in:73: garanteed -> "guaranteed"
docs/apibuild.py:2476: unkown -> "unknown"
docs/apps.html.in:191: upto -> "up to"
docs/firewall.html.in:320: managable -> "manageable","manageably"
docs/formatdomain.html.in:423: ommitted -> "omitted"
docs/hacking.html.in:547: particulary -> "particularly"
docs/internals/locking.html.in:153: psuedo -> "pseudo"
docs/news.html.in:610: commited -> "committed"
docs/news.html.in:1195: dependancy -> "dependency"
docs/news.html.in:1459: doesnt -> "doesn't"
docs/news.html.in:1570: dependancy -> "dependency"
docs/news.html.in:1837: stange -> "strange"
docs/news.html.in:1838: dependancy -> "dependency"
docs/news.html.in:1892: sucessful -> "successful"
docs/news.html.in:1893: sucessful -> "successful"
docs/news.html.in:2032: sucessful -> "successful"
docs/news.html.in:2472: orginal -> "original"
docs/news.html.in:2628: statment -> "statement"
docs/news.html.in:2793: controling -> "controlling"
docs/news.html.in:3912: Seperate -> "Separate"
docs/news.html.in:5025: occurence -> "occurrence"
docs/news.html.in:5592: Explictly -> "Explicitly"
docs/news.html.in:6508: beeing -> "being"
docs/news.html.in:7158: adressing -> "addressing","dressing"
docs/news.html.in:7483: Supress -> "Suppress"
docs/news.html.in:7542: occurence -> "occurrence"
docs/news.html.in:7551: sucess -> "success"
docs/news.html.in:7825: neccessary -> "necessary"
docs/news.html.in:7902: Occurence -> "Occurrence"
docs/news.html.in:7902: occurences -> "occurrences"
docs/news.html.in:8472: wierd -> "weird"
docs/news.html.in:8535: accomodate -> "accommodate"
docs/news.html.in:8598: dependancy -> "dependency"
docs/news.html.in:9008: dependancy -> "dependency"
docs/news.html.in:9306: dependancy -> "dependency"
docs/news.html.in:9324: dependance -> "dependence"
docs/news.html.in:9520: extention -> "extension"
docs/news.html.in:9587: dependance -> "dependence"
docs/remote.html.in:359: agains -> "against"
docs/schemas/interface.rng:7: everytime -> "every time"
docs/schemas/interface.rng:175: grat -> "great"
examples/domain-events/events-python/event-test.py:129: occurr -> "occur"
examples/domain-events/events-python/event-test.py:172: upto -> "up to"
examples/python/dominfo.py:46: runing -> "running"
include/libvirt/libvirt.h.in:642: targetting -> "targeting"
include/libvirt/libvirt.h.in:2935: specfic -> "specific"
include/libvirt/libvirt.h.in:3207: upto -> "up to"
include/libvirt/libvirt.h.in:3639: occuring -> "occurring"
src/conf/domain_conf.c:4565: Unkown -> "Unknown"
src/conf/domain_conf.c:4933: Unkown -> "Unknown"
src/conf/domain_conf.c:6914: Wierd -> "Weird"
src/conf/nwfilter_conf.c:2804: definiton -> "definition"
src/internal.h:114: conciously -> "consciously"
src/libvirt.c:3083: transfered -> "transferred"
src/libvirt.c:4390: dependant -> "dependent"
src/libvirt.c:4441: dependant -> "dependent"
src/libvirt.c:11461: upto -> "up to"
src/libvirt.c:11544: upto -> "up to"
src/libvirt.c:14119: funtion -> "function"
src/libvirt.c:14542: dependant -> "dependent"
src/libvirt_internal.h:2: publically -> "publicly"
src/phyp/phyp_driver.c:2067: avaliable -> "available"
src/phyp/phyp_driver.c:2290: avaliable -> "available"
src/phyp/phyp_driver.c:2770: avaliable -> "available"
src/qemu/qemu_capabilities.c:659: existance -> "existence"
src/qemu/qemu_capabilities.c:1234: targetting -> "targeting"
src/qemu/qemu_conf.c:205: lenght -> "length"
src/qemu/qemu_driver.c:1235: calulate -> "calculate"
src/qemu/qemu_monitor_text.c:2406: everthing -> "everything"
src/qemu/qemu_process.c:2657: pased -> "passed"
src/rpc/virnetsaslcontext.c:153: Succesful -> "Successful"
src/rpc/virnettlscontext.c:377: Succesful -> "Successful"
src/storage/storage_backend_disk.c:536: boundry -> "boundary"
src/storage/storage_backend_disk.c:561: boundry -> "boundary"
src/storage/storage_backend_disk.c:571: boundry -> "boundary"
src/storage/storage_backend_disk.c:620: boundry -> "boundary"
src/storage/storage_backend_rbd.c:318: occured -> "occurred"
src/uml/uml_driver.c:260: upto -> "up to"
src/uml/uml_driver.c:1293: calulate -> "calculate"
src/util/cgroup.c:69: HIERACHY -> "Hierarchy"
src/util/cgroup.c:172: neccessarily -> "necessarily"
src/util/cgroup.c:592: HIERACHY -> "Hierarchy"
src/util/cgroup.c:1007: HIERACHY -> "Hierarchy"
src/util/cgroup.c:2029: existance -> "existence"
src/util/processinfo.c:80: upto -> "up to"
src/util/processinfo.c:145: upto -> "up to"
src/util/virpidfile.c:369: agin -> "again"
src/util/virpidfile.c:378: agin -> "again"
src/util/virsocketaddr.c:421: recieve -> "receive"
src/util/virsocketaddr.c:451: recieve -> "receive"
src/util/virtime.c:105: THRU -> "Through"
src/util/virtime.c:162: THRU -> "Through"
src/util/virtime.c:163: THRU -> "Through"
src/vbox/vbox_tmpl.c:7050: becuase -> "because"
src/vbox/vbox_tmpl.c:8748: devide -> "divide"
src/vbox/vbox_tmpl.c:9262: persistance -> "persistence"
src/xen/xend_internal.c:517: targetting -> "targeting"
src/xen/xm_internal.c:177: funtion -> "function"
src/xen/xm_internal.c:201: funtion -> "function"
src/xen/xm_internal.c:310: funtion -> "function"
src/xen/xm_internal.c:386: alot -> "a lot","allot"
src/xenxs/xen_sxpr.c:814: Subsquent -> "Subsequent"
tests/virnettlscontexttest.c:451: suceeds -> "succeeds"
tools/virsh.pod:128: specfic -> "specific"
tools/virsh.pod:597: folowing -> "following"
tools/virsh.pod:2293: occurr -> "occur"
tools/virsh.pod:2537: preceed -> "precede"
12 years, 2 months
[libvirt] [PATCH v9] support offline migration
by liguang
original migration did not aware of offline case,
so, try to support offline migration quietly
(did not disturb original migration) by pass
VIR_MIGRATE_OFFLINE flag to migration APIs if only
the domain is really inactive, and
migration process will not puzzled by domain
offline and exit unexpectedly.
these changes did not take care of disk images the
domain required, for them could be transferred by
other APIs as suggested, then VIR_MIGRATE_OFFLINE
should not combined with VIR_MIGRATE_NON_SHARED_*.
so, this migration result is just make domain
definition alive at target side.
Signed-off-by: liguang <lig.fnst(a)cn.fujitsu.com>
---
include/libvirt/libvirt.h.in | 1 +
src/qemu/qemu_driver.c | 15 ++++++++++++
src/qemu/qemu_migration.c | 53 ++++++++++++++++++++++++++++++++++++-----
src/qemu/qemu_migration.h | 3 +-
tools/virsh-domain.c | 6 ++++
5 files changed, 70 insertions(+), 8 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 79c7689..627e9d4 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -995,6 +995,7 @@ typedef enum {
* whole migration process; this will be used automatically
* when supported */
VIR_MIGRATE_UNSAFE = (1 << 9), /* force migration even if it is considered unsafe */
+ VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */
} virDomainMigrateFlags;
/* Domain migration. */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6848924..105febf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9631,6 +9631,15 @@ qemuDomainMigrateBegin3(virDomainPtr domain,
}
if (!virDomainObjIsActive(vm)) {
+ if (flags & VIR_MIGRATE_OFFLINE) {
+ if (flags & (VIR_MIGRATE_NON_SHARED_DISK|
+ VIR_MIGRATE_NON_SHARED_INC)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("migrating storage handled by volume APIs"));
+ goto endjob;
+ }
+ goto offline;
+ }
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("domain is not running"));
goto endjob;
@@ -9643,6 +9652,7 @@ qemuDomainMigrateBegin3(virDomainPtr domain,
if (qemuDomainCheckEjectableMedia(driver, vm, asyncJob) < 0)
goto endjob;
+offline:
if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
cookieout, cookieoutlen,
flags)))
@@ -9878,6 +9888,11 @@ qemuDomainMigrateConfirm3(virDomainPtr domain,
goto cleanup;
}
+ if (flags & VIR_MIGRATE_OFFLINE) {
+ ret = 0;
+ goto cleanup;
+ }
+
if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
goto cleanup;
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 8e85875..411a4c2 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -70,6 +70,7 @@ enum qemuMigrationCookieFlags {
QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS,
QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE,
QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT,
+ QEMU_MIGRATION_COOKIE_FLAG_OFFLINE,
QEMU_MIGRATION_COOKIE_FLAG_LAST
};
@@ -77,12 +78,13 @@ enum qemuMigrationCookieFlags {
VIR_ENUM_DECL(qemuMigrationCookieFlag);
VIR_ENUM_IMPL(qemuMigrationCookieFlag,
QEMU_MIGRATION_COOKIE_FLAG_LAST,
- "graphics", "lockstate", "persistent");
+ "graphics", "lockstate", "persistent", "offline");
enum qemuMigrationCookieFeatures {
QEMU_MIGRATION_COOKIE_GRAPHICS = (1 << QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS),
QEMU_MIGRATION_COOKIE_LOCKSTATE = (1 << QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE),
QEMU_MIGRATION_COOKIE_PERSISTENT = (1 << QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT),
+ QEMU_MIGRATION_COOKIE_OFFLINE = (1 << QEMU_MIGRATION_COOKIE_FLAG_OFFLINE),
};
typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics;
@@ -439,6 +441,9 @@ qemuMigrationCookieXMLFormat(struct qemud_driver *driver,
virBufferAdjustIndent(buf, -2);
}
+ if (mig->flags & QEMU_MIGRATION_COOKIE_OFFLINE)
+ virBufferAsprintf(buf, " <offline/>\n");
+
virBufferAddLit(buf, "</qemu-migration>\n");
return 0;
}
@@ -662,6 +667,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
VIR_FREE(nodes);
}
+ if ((flags & QEMU_MIGRATION_COOKIE_OFFLINE)) {
+ if (virXPathBoolean("count(./offline) > 0", ctxt))
+ mig->flags |= QEMU_MIGRATION_COOKIE_OFFLINE;
+ }
+
return 0;
error:
@@ -721,6 +731,10 @@ qemuMigrationBakeCookie(qemuMigrationCookiePtr mig,
qemuMigrationCookieAddPersistent(mig, dom) < 0)
return -1;
+ if (flags & QEMU_MIGRATION_COOKIE_OFFLINE) {
+ mig->flags |= QEMU_MIGRATION_COOKIE_OFFLINE;
+ }
+
if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig)))
return -1;
@@ -1151,6 +1165,13 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
QEMU_MIGRATION_COOKIE_LOCKSTATE) < 0)
goto cleanup;
+ if (flags & VIR_MIGRATE_OFFLINE) {
+ if (qemuMigrationBakeCookie(mig, driver, vm,
+ cookieout, cookieoutlen,
+ QEMU_MIGRATION_COOKIE_OFFLINE) < 0)
+ goto cleanup;
+ }
+
if (xmlin) {
if (!(def = virDomainDefParseString(driver->caps, xmlin,
QEMU_EXPECTED_VIRT_TYPES,
@@ -1314,6 +1335,15 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
goto endjob;
}
+ if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
+ QEMU_MIGRATION_COOKIE_OFFLINE)))
+ return ret;
+
+ if (mig->flags & QEMU_MIGRATION_COOKIE_OFFLINE) {
+ ret = 0;
+ goto cleanup;
+ }
+
/* Start the QEMU daemon, with the same command-line arguments plus
* -incoming $migrateFrom
*/
@@ -1856,7 +1886,8 @@ qemuMigrationRun(struct qemud_driver *driver,
virLockManagerPluginGetName(driver->lockManager));
return -1;
}
-
+ if (flags & VIR_MIGRATE_OFFLINE)
+ return 0;
if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
QEMU_MIGRATION_COOKIE_GRAPHICS)))
goto cleanup;
@@ -2372,6 +2403,8 @@ static int doPeer2PeerMigrate3(struct qemud_driver *driver,
qemuDomainObjExitRemoteWithDriver(driver, vm);
}
VIR_FREE(dom_xml);
+ if (flags & VIR_MIGRATE_OFFLINE)
+ goto cleanup;
if (ret == -1)
goto cleanup;
@@ -2477,7 +2510,7 @@ finish:
vm->def->name);
cleanup:
- if (ddomain) {
+ if (ddomain || (flags & VIR_MIGRATE_OFFLINE)) {
virObjectUnref(ddomain);
ret = 0;
} else {
@@ -2554,7 +2587,7 @@ static int doPeer2PeerMigrate(struct qemud_driver *driver,
}
/* domain may have been stopped while we were talking to remote daemon */
- if (!virDomainObjIsActive(vm)) {
+ if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("guest unexpectedly quit"));
goto cleanup;
@@ -2617,7 +2650,7 @@ qemuMigrationPerformJob(struct qemud_driver *driver,
if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
goto cleanup;
- if (!virDomainObjIsActive(vm)) {
+ if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("domain is not running"));
goto endjob;
@@ -2941,6 +2974,8 @@ qemuMigrationFinish(struct qemud_driver *driver,
*/
if (retcode == 0) {
if (!virDomainObjIsActive(vm)) {
+ if (flags & VIR_MIGRATE_OFFLINE)
+ goto offline;
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("guest unexpectedly quit"));
goto endjob;
@@ -3038,7 +3073,7 @@ qemuMigrationFinish(struct qemud_driver *driver,
goto endjob;
}
}
-
+ offline:
dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
event = virDomainEventNewFromObj(vm,
@@ -3074,6 +3109,7 @@ qemuMigrationFinish(struct qemud_driver *driver,
endjob:
if (qemuMigrationJobFinish(driver, vm) == 0) {
vm = NULL;
+ } else if (flags & VIR_MIGRATE_OFFLINE) {
} else if (!vm->persistent && !virDomainObjIsActive(vm)) {
qemuDomainRemoveInactive(driver, vm);
vm = NULL;
@@ -3120,7 +3156,10 @@ int qemuMigrationConfirm(struct qemud_driver *driver,
if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen, 0)))
return -1;
-
+ if (flags & VIR_MIGRATE_OFFLINE) {
+ rv = 0;
+ goto cleanup;
+ }
/* Did the migration go as planned? If yes, kill off the
* domain object, but if no, resume CPUs
*/
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 7a2269a..b4f6a77 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -36,7 +36,8 @@
VIR_MIGRATE_NON_SHARED_DISK | \
VIR_MIGRATE_NON_SHARED_INC | \
VIR_MIGRATE_CHANGE_PROTECTION | \
- VIR_MIGRATE_UNSAFE)
+ VIR_MIGRATE_UNSAFE | \
+ VIR_MIGRATE_OFFLINE)
enum qemuMigrationJobPhase {
QEMU_MIGRATION_PHASE_NONE = 0,
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 505169b..2218379 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -6647,6 +6647,7 @@ static const vshCmdOptDef opts_migrate[] = {
{"dname", VSH_OT_DATA, 0, N_("rename to new name during migration (if supported)")},
{"timeout", VSH_OT_INT, 0, N_("force guest to suspend if live migration exceeds timeout (in seconds)")},
{"xml", VSH_OT_STRING, 0, N_("filename containing updated XML for the target")},
+ {"offline", VSH_OT_BOOL, 0, N_("for offline migration")},
{NULL, 0, 0, NULL}
};
@@ -6713,6 +6714,11 @@ doMigrate(void *opaque)
if (vshCommandOptBool(cmd, "unsafe"))
flags |= VIR_MIGRATE_UNSAFE;
+ if (vshCommandOptBool(cmd, "offline")) {
+ if (!virDomainIsActive(dom))
+ flags |= VIR_MIGRATE_OFFLINE;
+ }
+
if (xmlfile &&
virFileReadAll(xmlfile, 8192, &xml) < 0) {
vshError(ctl, _("file '%s' doesn't exist"), xmlfile);
--
1.7.2.5
12 years, 2 months
[libvirt] [PATCH 00/12] Structured syslog (Lumberjack/CEE) support
by Miloslav Trmač
This patch set adds structured syslog support to libvirt.
In short, the idea is to embed JSON in a syslog record. This format
is used in a new log output type called "syslog/json".
Example "syslog/json" record (line-wrapped for readability):
Sep 20 19:59:40 kulicka libvirt: @cee: {"msg":"libvirt version: 0.10.1",
"category":"../../src/test/test_driver.c","priority":"info",
"funcname":"virLogVMessage","line":769,
"timestamp":"2012-09-20 17:59:40.853+0000"}
compared with existing "syslog" record format:
Sep 20 20:02:24 kulicka libvirt: 5896: info : libvirt version: 0.10.1
This JSON embedding format is defined by the Lumberjack project led
by the major Open Source syslog implementations
(https://fedorahosted.org/lumberjack/). The format is also a base
for a future MITRE CEE standard. Some of the fields are specified
at https://fedorahosted.org/lumberjack/wiki/FieldList , but applications
are free to use whatever fields make sense for them.
The JSON structure makes easy to process logs by programs without writing
code that understands the specific format used by each application,
or using unreliable regexps (https://fedorahosted.org/ceelog/ is a
companion project that allows processing such logs).
Current systems will store and these records unmodified and present them
to users unmodified, but tools (and probably /var/log/messages) will
be able to show only the "msg" field; this allows us to add more detailed
information without worsening the user experience (the example above
already shows added information that is currently being thrown away when
logging to syslog).
The patch set, aside from building the required infrastructure, has two
main components:
* Add the "syslog/json" output type, and use it to record all information
passed to virLogMessage. The example result is shown above. This primarily
makes it easier to parse the message.
* Allow callers of virLogMessage to add arbitrary additional JSON fields,
and use it in virRaiseErrorFull and its callers. Because the additional
fields for errors include virErrorDomain and virErrorNumber, this allows
_programs_ to _automatically_ detect the event and react to it, perhaps
alerting the user about a situation that requires immediate attention,
or automatically suggesting a solution.
This has not been possible until now because the current logs contain
only a translated error message, so the log record doesn't contain
anything stable that could be detected by a program.
It is assumed that other parts of libvirt may add more event-specific
JSON fields in the future, based on demand by applications that process
the logs; I have, however, no immediate plans to add more.
Miloslav Trmač (12):
Drop unused return value of virLogOutputFunc
Add JSON API for preallocated objects.
Split yajl_gen allocation into a separate function.
Split adding object properties from virJSONValueToStringOne
Add a JSON generator API.
Pass the "raw" log message to each virLogOutputFunc
Split priority conversion from virLogOutputToSyslog
Add "syslog/json" log output format.
Add a JSON properties parameter to virLog{,V}Message
Add a JSON properties parameter to virLogOutputFunc
Add detailed error information to JSON syslog
Add a test for the new error reporting mechanism.
docs/logging.html.in | 3 +
src/libvirt_private.syms | 4 +
src/uml/uml_conf.c | 2 +-
src/util/json.c | 232 +++++++++++++++++++++++++++++++++++++++++-----
src/util/json.h | 26 ++++++
src/util/logging.c | 233 ++++++++++++++++++++++++++++++++++-------------
src/util/logging.h | 35 +++----
src/util/viraudit.c | 4 +-
src/util/virterror.c | 32 ++++++-
tests/Makefile.am | 6 +-
tests/errorjsontest.c | 211 ++++++++++++++++++++++++++++++++++++++++++
tests/testutils.c | 7 +-
12 files changed, 684 insertions(+), 111 deletions(-)
create mode 100644 tests/errorjsontest.c
--
1.7.11.4
12 years, 2 months