[libvirt] Supporting vhost-net and macvtap in libvirt for QEMU
by Anthony Liguori
Disclaimer: I am neither an SR-IOV nor a vhost-net expert, but I've CC'd
people that are who can throw tomatoes at me for getting bits wrong :-)
I wanted to start a discussion about supporting vhost-net in libvirt.
vhost-net has not yet been merged into qemu but I expect it will be soon
so it's a good time to start this discussion.
There are two modes worth supporting for vhost-net in libvirt. The
first mode is where vhost-net backs to a tun/tap device. This is
behaves in very much the same way that -net tap behaves in qemu today.
Basically, the difference is that the virtio backend is in the kernel
instead of in qemu so there should be some performance improvement.
Current, libvirt invokes qemu with -net tap,fd=X where X is an already
open fd to a tun/tap device. I suspect that after we merge vhost-net,
libvirt could support vhost-net in this mode by just doing -net
vhost,fd=X. I think the only real question for libvirt is whether to
provide a user visible switch to use vhost or to just always use vhost
when it's available and it makes sense. Personally, I think the later
makes sense.
The more interesting invocation of vhost-net though is one where the
vhost-net device backs directly to a physical network card. In this
mode, vhost should get considerably better performance than the current
implementation. I don't know the syntax yet, but I think it's
reasonable to assume that it will look something like -net
tap,dev=eth0. The effect will be that eth0 is dedicated to the guest.
On most modern systems, there is a small number of network devices so
this model is not all that useful except when dealing with SR-IOV
adapters. In that case, each physical device can be exposed as many
virtual devices (VFs). There are a few restrictions here though. The
biggest is that currently, you can only change the number of VFs by
reloading a kernel module so it's really a parameter that must be set at
startup time.
I think there are a few ways libvirt could support vhost-net in this
second mode. The simplest would be to introduce a new tag similar to
<source network='br0'>. In fact, if you probed the device type for the
network parameter, you could probably do something like <source
network='eth0'> and have it Just Work.
Another model would be to have libvirt see an SR-IOV adapter as a
network pool whereas it handled all of the VF management. Considering
how inflexible SR-IOV is today, I'm not sure whether this is the best model.
Has anyone put any more thought into this problem or how this should be
modeled in libvirt? Michael, could you share your current thinking for
-net syntax?
--
Regards,
Anthony Liguori
1 year
[libvirt] New application
by Maciej Nabożny
Hello,
I'm developer of CC1 project in Institute of Nuclear Physics in
Cracow. We are creating cloud computing system based on Libvirt. Is it
possible to add link to our project at yours website in applications
section?
Title: CC1 Project (http://cc1.ifj.edu.pl)
Description: The Cloud Computing for Science and Economy project
At this time we are using version 0.8.3, but as soon as debian 7 will
we stable, we are going to migrate to newer version of Libvirt.
Regards,
Maciej Nabożny
11 years, 6 months
[libvirt] [PATCH 0/4] Multiple problems with saving to block devices
by Daniel P. Berrange
This patch series makes it possible to save to a block device,
instead of a plain file. There were multiple problems
- WHen save failed, we might de-reference a NULL pointer
- When save failed, we unlinked the device node !!
- The approach of using >> to append, doesn't work with block devices
- CGroups was blocking QEMU access to the block device when enabled
One remaining problem is not in libvirt, but rather QEMU. The QEMU
exec: based migration often fails to detect failure of the command
and will thus hang forever attempting a migration that'll never
succeed! Fortunately you can now work around this in libvirt using
the virsh domjobabort command
11 years, 7 months
[libvirt] [PATCHv4 00/51] another round of snapshot patches
by Eric Blake
I think I've addressed most findings from round 3 - by implementing
the ability to redefine a snapshot, it becomes possible to restore
snapshot hierarchy when recreating a transient domain by the same
name. New goodies in this round: several bug fixes, add virsh
snapshot-edit, drop undefine --snapshots-full (you can only remove
snapshot metadata on undefine). I tested as I went, but this went
through so many rebases that there may be some nasties that snuck
in; but I wanted to get this posted now. I also know that I'm
missing at least one major feature requested in the v3 review:
namely, transient domains _should_ auto-remove snapshot metadata
files when they halt, but right now aren't doing that.
v3 was at:
https://www.redhat.com/archives/libvir-list/2011-August/msg01132.html
Also available here:
git fetch git://repo.or.cz/libvirt/ericb.git snapshot
or browse online at:
http://repo.or.cz/w/libvirt/ericb.git/shortlog/refs/heads/snapshot
I'm also trying to group things by several bugzilla related to
various patches (looks like I still need to create a few):
Eric Blake (51):
https://bugzilla.redhat.com/show_bug.cgi?id=674537
snapshot: fix corner case on OOM during creation
https://bugzilla.redhat.com/show_bug.cgi?id=733762
snapshot: better events when starting paused
snapshot: fine-tune ability to start paused
snapshot: expose --running and --paused in virsh
snapshot: fine-tune qemu saved images starting paused
snapshot: improve reverting to qemu paused snapshots
snapshot: properly revert qemu to offline snapshots
snapshot: fine-tune qemu snapshot revert states
no bug filed yet... should be one about no stale metadata
snapshot: allow deletion of just snapshot metadata
snapshot: add snapshot-list --parent to virsh
https://bugzilla.redhat.com/show_bug.cgi?id=733529
snapshot: speed up snapshot location
snapshot: avoid crash when deleting qemu snapshots
snapshot: track current domain across deletion of children
snapshot: simplify acting on just children
no bug filed yet... should be one about no stale metadata
snapshot: let qemu discard only snapshot metadata
snapshot: identify which snapshots have metadata
snapshot: reflect new dumpxml and list options in virsh
snapshot: identify qemu snapshot roots
snapshot: allow recreation of metadata
snapshot: refactor virsh snapshot creation
snapshot: improve virsh snapshot-create, add snapshot-edit
snapshot: add qemu snapshot creation without metadata
no bug filed yet... should be one about snapshot migration
snapshot: add qemu snapshot redefine support
snapshot: prevent stranding snapshot data on domain destruction
snapshot: teach virsh about new undefine flags
snapshot: refactor some qemu code
snapshot: cache qemu-img location
snapshot: support new undefine flags in qemu
snapshot: prevent migration from stranding snapshot data
https://bugzilla.redhat.com/show_bug.cgi?id=638510
snapshot: refactor domain xml output
snapshot: allow full domain xml in snapshot
snapshot: correctly escape generated xml
snapshot: update rng to support full domain in xml
snapshot: store qemu domain details in xml
snapshot: additions to domain xml for disks
snapshot: reject transient disks where code is not ready
snapshot: introduce new deletion flag
snapshot: expose new delete flag in virsh
snapshot: allow halting after snapshot
snapshot: expose halt-after-creation in virsh
snapshot: wire up new qemu monitor command
snapshot: support extra state in snapshots
snapshot: add <disks> to snapshot xml
snapshot: also support disks by path
snapshot: add virsh domblklist command
snapshot: add flag for requesting disk snapshot
snapshot: wire up disk-only flag to snapshot-create
snapshot: reject unimplemented disk snapshot features
snapshot: make it possible to audit external snapshot
snapshot: wire up live qemu disk snapshots
snapshot: use SELinux and lock manager with external snapshots
docs/formatdomain.html.in | 40 +-
docs/formatsnapshot.html.in | 269 ++-
docs/schemas/Makefile.am | 1 +
docs/schemas/domain.rng | 2555 +-------------------
docs/schemas/{domain.rng => domaincommon.rng} | 32 +-
docs/schemas/domainsnapshot.rng | 84 +-
examples/domain-events/events-c/event-test.c | 37 +-
include/libvirt/libvirt.h.in | 66 +-
src/conf/domain_audit.c | 12 +-
src/conf/domain_audit.h | 4 +-
src/conf/domain_conf.c | 902 ++++++--
src/conf/domain_conf.h | 76 +-
src/esx/esx_driver.c | 38 +-
src/libvirt.c | 256 ++-
src/libvirt_private.syms | 8 +
src/libxl/libxl_conf.c | 5 +
src/libxl/libxl_driver.c | 11 +-
src/qemu/qemu_command.c | 5 +
src/qemu/qemu_conf.h | 1 +
src/qemu/qemu_driver.c | 1532 +++++++++---
src/qemu/qemu_hotplug.c | 18 +-
src/qemu/qemu_migration.c | 48 +-
src/qemu/qemu_migration.h | 2 -
src/qemu/qemu_monitor.c | 24 +
src/qemu/qemu_monitor.h | 4 +
src/qemu/qemu_monitor_json.c | 33 +
src/qemu/qemu_monitor_json.h | 4 +
src/qemu/qemu_monitor_text.c | 40 +
src/qemu/qemu_monitor_text.h | 4 +
src/qemu/qemu_process.c | 11 +-
src/uml/uml_driver.c | 56 +-
src/vbox/vbox_tmpl.c | 43 +-
src/xen/xend_internal.c | 12 +-
src/xenxs/xen_sxpr.c | 5 +
src/xenxs/xen_xm.c | 5 +
tests/domainsnapshotxml2xmlin/disk_snapshot.xml | 16 +
tests/domainsnapshotxml2xmlout/disk_snapshot.xml | 77 +
tests/domainsnapshotxml2xmlout/full_domain.xml | 35 +
.../qemuxml2argv-disk-snapshot.args | 7 +
.../qemuxml2argv-disk-snapshot.xml | 39 +
.../qemuxml2argv-disk-transient.xml | 27 +
tests/qemuxml2argvtest.c | 2 +
tests/virsh-optparse | 20 +
tools/virsh.c | 772 +++++-
tools/virsh.pod | 214 ++-
45 files changed, 3978 insertions(+), 3474 deletions(-)
copy docs/schemas/{domain.rng => domaincommon.rng} (98%)
create mode 100644 tests/domainsnapshotxml2xmlin/disk_snapshot.xml
create mode 100644 tests/domainsnapshotxml2xmlout/disk_snapshot.xml
create mode 100644 tests/domainsnapshotxml2xmlout/full_domain.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-snapshot.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-snapshot.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-transient.xml
--
1.7.4.4
12 years
[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
[libvirt] [PATCH] ARMHF: Fixed Parser for /proc/cpuinfo needs to be adapted for your architecture
by Chuck Short
Minimal CPU "parser" for armhf to avoid compile time warning.
Signed-off-by: Chuck Short <chuck.short(a)canonical.com>
---
src/nodeinfo.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 84a5d66..358fa3b 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -397,6 +397,27 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
* and parsed in next iteration, because it is not in expected
* format and thus lead to error. */
}
+# elif defined(__arm__)
+ char *buf = line;
+ if (STRPREFIX(buf, "BogoMIPS")) {
+ char *p;
+ unsigned int ui;
+
+ buf += 8;
+ while (*buf && c_isspace(*buf))
+ buf++;
+
+ if (*buf != ':' || !buf[1]) {
+ nodeReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("parsing cpu MHz from cpuinfo"));
+ goto cleanup;
+ }
+
+ if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
+ /* Accept trailing fractional part. */
+ && (*p == '\0' || *p == '.' || c_isspace(*p)))
+ nodeinfo->mhz = ui;
+ }
# elif defined(__s390__) || \
defined(__s390x__)
/* s390x has no realistic value for CPU speed,
--
1.7.10.4
12 years, 1 month
[libvirt] [PATCH] Fix dnsmasq/radvd on bridges not being able to be bound to IPv6 address on "recent" kernels
by Benjamin Cama
Hi,
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address (resp. interface), waiting 20s and then giving up with
-EADDRNOTAVAIL (resp. exiting immediately with "error parsing or
activating the config file", without libvirt noticing it, BTW). This can
be reproduced with (I think) any kernel >= 2.6.39 and the following XML
(to be used with "virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier. I see radvd
yelling quite often in the logs when the interface is NO-CARRIER, but
it's ok, it keeps running.
Still, this patch is not exactly correct, as radvd get daemonized “too
soon” most of the time (i.e. when not debugging libvirtd…) and probes
the bridge once it has been set down (even if started before setting it
down), thus failing as before (and libvirt lets it be like that: this
would need some more checking, maybe). One /may/ introduce some delay
between networkStartRadvd() and setting the dummy tap down to solve it,
but it seemed too hackish to me. But I couldn't come with a better
solution. I would welcome suggestions here.
BTW, I removed the “up” argument from virNetDevTapCreateInBridgePort()
and virNetDevTapCreate() as all TAP devices are created up now, and I
fixed a function name in the docstring.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1...
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b...
---
src/network/bridge_driver.c | 15 ++++++++++++++-
src/qemu/qemu_command.c | 2 +-
src/uml/uml_conf.c | 2 +-
src/util/virnetdevtap.c | 29 +++++++++++++++++------------
src/util/virnetdevtap.h | 7 ++++---
5 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 63338a2..a13efe6 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -62,6 +62,7 @@
#include "virnetdev.h"
#include "virnetdevbridge.h"
#include "virnetdevtap.h"
+#include "virfile.h"
#define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
#define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network"
@@ -1693,6 +1694,7 @@ networkStartNetworkVirtual(struct network_driver *driver,
virErrorPtr save_err = NULL;
virNetworkIpDefPtr ipdef;
char *macTapIfName = NULL;
+ int tapfd = -1;
/* Check to see if any network IP collides with an existing route */
if (networkCheckRouteCollision(network) < 0)
@@ -1714,8 +1716,9 @@ networkStartNetworkVirtual(struct network_driver *driver,
virReportOOMError();
goto err0;
}
+ /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
if (virNetDevTapCreateInBridgePort(network->def->bridge,
- &macTapIfName, network->def->mac, 0, false, NULL) < 0) {
+ &macTapIfName, network->def->mac, 0, &tapfd, true) < 0) {
VIR_FREE(macTapIfName);
goto err0;
}
@@ -1775,6 +1778,16 @@ networkStartNetworkVirtual(struct network_driver *driver,
if (v6present && networkStartRadvd(network) < 0)
goto err4;
+ /* DAD has happened (dnsmasq waits for it), dnsmasq is now bound to the
+ * bridge's IPv6 address, and radvd to the interface, so we can now set the
+ * dummy tun down.
+ */
+ if (tapfd >= 0) {
+ if (virNetDevSetOnline(macTapIfName, false) < 0)
+ goto err4;
+ VIR_FORCE_CLOSE(tapfd);
+ }
+
if (virNetDevBandwidthSet(network->def->bridge, network->def->bandwidth) < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot set bandwidth limits on %s"),
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 22dc871..08457e7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -247,7 +247,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
err = virNetDevTapCreateInBridgePort(brname, &net->ifname, tapmac,
- vnet_hdr, true, &tapfd);
+ vnet_hdr, &tapfd, false);
virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);
if (err < 0) {
if (template_ifname)
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index b878622..bd838a6 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -141,7 +141,7 @@ umlConnectTapDevice(virConnectPtr conn,
memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, tapmac,
- 0, true, NULL) < 0) {
+ 0, NULL, true) < 0) {
if (template_ifname)
VIR_FREE(net->ifname);
goto error;
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index 2ed53c6..3e2c2cc 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -109,18 +109,21 @@ virNetDevProbeVnetHdr(int tapfd)
* @ifname: the interface name
* @vnet_hr: whether to try enabling IFF_VNET_HDR
* @tapfd: file descriptor return value for the new tap device
+ * @persist: if the device persists after the file descriptor is closed
*
* Creates a tap interface.
* If the @tapfd parameter is supplied, the open tap device file
- * descriptor will be returned, otherwise the TAP device will be made
- * persistent and closed. The caller must use brDeleteTap to remove
- * a persistent TAP devices when it is no longer needed.
+ * descriptor will be returned, otherwise the TAP device will be closed. The
+ * TAP device will persist after closing the file descriptor if @persist is
+ * true. The caller must use virNetDevTapDelete to remove a persistent TAP
+ * devices when it is no longer needed.
*
* Returns 0 in case of success or an errno code in case of failure.
*/
int virNetDevTapCreate(char **ifname,
int vnet_hdr ATTRIBUTE_UNUSED,
- int *tapfd)
+ int *tapfd,
+ bool persist)
{
int fd;
struct ifreq ifr;
@@ -156,7 +159,7 @@ int virNetDevTapCreate(char **ifname,
goto cleanup;
}
- if (!tapfd &&
+ if (persist &&
(errno = ioctl(fd, TUNSETPERSIST, 1))) {
virReportSystemError(errno,
_("Unable to set tap device %s to persistent"),
@@ -249,14 +252,16 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)
* @macaddr: desired MAC address (VIR_MAC_BUFLEN long)
* @vnet_hdr: whether to try enabling IFF_VNET_HDR
* @tapfd: file descriptor return value for the new tap device
+ * @persist: if the device persists after the file descriptor is closed
*
* This function creates a new tap device on a bridge. @ifname can be either
* a fixed name or a name template with '%d' for dynamic name allocation.
* in either case the final name for the bridge will be stored in @ifname.
* If the @tapfd parameter is supplied, the open tap device file
- * descriptor will be returned, otherwise the TAP device will be made
- * persistent and closed. The caller must use brDeleteTap to remove
- * a persistent TAP devices when it is no longer needed.
+ * descriptor will be returned, otherwise the TAP device will be closed. The
+ * TAP device will persist after closing the file descriptor if @persist is
+ * true. The caller must use virNetDevTapDelete to remove a persistent TAP
+ * devices when it is no longer needed.
*
* Returns 0 in case of success or -1 on failure
*/
@@ -264,10 +269,10 @@ int virNetDevTapCreateInBridgePort(const char *brname,
char **ifname,
const unsigned char *macaddr,
int vnet_hdr,
- bool up,
- int *tapfd)
+ int *tapfd,
+ bool persist)
{
- if (virNetDevTapCreate(ifname, vnet_hdr, tapfd) < 0)
+ if (virNetDevTapCreate(ifname, vnet_hdr, tapfd, persist) < 0)
return -1;
/* We need to set the interface MAC before adding it
@@ -289,7 +294,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
if (virNetDevBridgeAddPort(brname, *ifname) < 0)
goto error;
- if (virNetDevSetOnline(*ifname, up) < 0)
+ if (virNetDevSetOnline(*ifname, true) < 0)
goto error;
return 0;
diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h
index fb35ac5..6aff641 100644
--- a/src/util/virnetdevtap.h
+++ b/src/util/virnetdevtap.h
@@ -27,7 +27,8 @@
int virNetDevTapCreate(char **ifname,
int vnet_hdr,
- int *tapfd)
+ int *tapfd,
+ bool persist)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
int virNetDevTapDelete(const char *ifname)
@@ -37,8 +38,8 @@ int virNetDevTapCreateInBridgePort(const char *brname,
char **ifname,
const unsigned char *macaddr,
int vnet_hdr,
- bool up,
- int *tapfd)
+ int *tapfd,
+ bool persist)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_RETURN_CHECK;
--
Benjamin Cama <benjamin.cama(a)telecom-bretagne.eu>
12 years, 1 month
[libvirt] [libvirt-glib PATCHv3] Fix *_new_from_xml
by Christophe Fergeau
For objects with a subtype 'type' attribute, when the _new_from_xml
function was called, the 'type' attribute was forcefully set to the
right value rather than checking that the passed-in value matches
the type of the subclass we are trying to instantiate. This commit
changes this, and returns NULL when the value of the 'type' attribute
of the passed-in XML document does not match the expected type.
---
libvirt-gconfig/libvirt-gconfig-domain-address-pci.c | 5 ++++-
libvirt-gconfig/libvirt-gconfig-domain-address-usb.c | 5 ++++-
libvirt-gconfig/libvirt-gconfig-domain-chardev-source-pty.c | 5 ++++-
libvirt-gconfig/libvirt-gconfig-domain-chardev-source-spicevmc.c | 5 ++++-
libvirt-gconfig/libvirt-gconfig-domain-controller-usb.c | 5 ++++-
libvirt-gconfig/libvirt-gconfig-domain-graphics-sdl.c | 5 +++--
libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c | 5 +++--
libvirt-gconfig/libvirt-gconfig-domain-graphics-vnc.c | 5 +++--
libvirt-gconfig/libvirt-gconfig-domain-interface-bridge.c | 5 +++--
libvirt-gconfig/libvirt-gconfig-domain-interface-network.c | 5 +++--
libvirt-gconfig/libvirt-gconfig-domain-interface-user.c | 5 +++--
libvirt-gconfig/libvirt-gconfig-domain-timer-pit.c | 5 ++++-
libvirt-gconfig/libvirt-gconfig-domain-timer-rtc.c | 5 ++++-
13 files changed, 46 insertions(+), 19 deletions(-)
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-address-pci.c b/libvirt-gconfig/libvirt-gconfig-domain-address-pci.c
index 48e3872..9ad7765 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-address-pci.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-address-pci.c
@@ -67,7 +67,10 @@ GVirConfigDomainAddressPci *gvir_config_domain_address_pci_new_from_xml(const gc
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_ADDRESS_PCI,
"address", NULL, xml, error);
- gvir_config_object_set_attribute(object, "type", "pci", NULL);
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "pci") != 0) {
+ g_object_unref(G_OBJECT(object));
+ g_return_val_if_reached(NULL);
+ }
return GVIR_CONFIG_DOMAIN_ADDRESS_PCI(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-address-usb.c b/libvirt-gconfig/libvirt-gconfig-domain-address-usb.c
index 3da5811..cb7a986 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-address-usb.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-address-usb.c
@@ -67,7 +67,10 @@ GVirConfigDomainAddressUsb *gvir_config_domain_address_usb_new_from_xml(const gc
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_ADDRESS_USB,
"address", NULL, xml, error);
- gvir_config_object_set_attribute(object, "type", "usb", NULL);
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "usb") != 0) {
+ g_object_unref(G_OBJECT(object));
+ g_return_val_if_reached(NULL);
+ }
return GVIR_CONFIG_DOMAIN_ADDRESS_USB(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-pty.c b/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-pty.c
index 201e123..8b14330 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-pty.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-pty.c
@@ -75,7 +75,10 @@ GVirConfigDomainChardevSourcePty *gvir_config_domain_chardev_source_pty_new_from
*/
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_CHARDEV_SOURCE_PTY,
"dummy", NULL, xml, error);
- gvir_config_object_set_attribute(object, "type", "pty", NULL);
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "pty") != 0) {
+ g_object_unref(G_OBJECT(object));
+ g_return_val_if_reached(NULL);
+ }
return GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE_PTY(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-spicevmc.c b/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-spicevmc.c
index 22eabf5..10c0ab8 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-spicevmc.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-chardev-source-spicevmc.c
@@ -75,6 +75,9 @@ GVirConfigDomainChardevSourceSpiceVmc *gvir_config_domain_chardev_source_spicevm
*/
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_CHARDEV_SOURCE_SPICE_VMC,
"dummy", NULL, xml, error);
- gvir_config_object_set_attribute(object, "type", "spicevmc", NULL);
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "spicevmc") != 0) {
+ g_object_unref(G_OBJECT(object));
+ g_return_val_if_reached(NULL);
+ }
return GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE_SPICE_VMC(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-controller-usb.c b/libvirt-gconfig/libvirt-gconfig-domain-controller-usb.c
index 1fd248c..d7d7f65 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-controller-usb.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-controller-usb.c
@@ -167,7 +167,10 @@ GVirConfigDomainControllerUsb *gvir_config_domain_controller_usb_new_from_xml(co
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_CONTROLLER_USB,
"controller", NULL, xml, error);
- gvir_config_object_set_attribute(object, "type", "usb", NULL);
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "usb") != 0) {
+ g_object_unref(G_OBJECT(object));
+ g_return_val_if_reached(NULL);
+ }
return GVIR_CONFIG_DOMAIN_CONTROLLER_USB(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-graphics-sdl.c b/libvirt-gconfig/libvirt-gconfig-domain-graphics-sdl.c
index 7871ae5..8b22ad0 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-graphics-sdl.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-graphics-sdl.c
@@ -68,9 +68,10 @@ gvir_config_domain_graphics_sdl_new_from_xml(const gchar *xml,
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_GRAPHICS_SDL,
"graphics", NULL, xml, error);
- if (object == NULL)
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "sdl") != 0) {
+ g_object_unref(G_OBJECT(object));
return NULL;
- gvir_config_object_set_attribute(object, "type", "sdl", NULL);
+ }
return GVIR_CONFIG_DOMAIN_GRAPHICS_SDL(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c b/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c
index e60a778..61d3f5b 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c
@@ -68,9 +68,10 @@ gvir_config_domain_graphics_spice_new_from_xml(const gchar *xml,
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_GRAPHICS_SPICE,
"graphics", NULL, xml, error);
- if (object == NULL)
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "spice") != 0) {
+ g_object_unref(G_OBJECT(object));
return NULL;
- gvir_config_object_set_attribute(object, "type", "spice", NULL);
+ }
return GVIR_CONFIG_DOMAIN_GRAPHICS_SPICE(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-graphics-vnc.c b/libvirt-gconfig/libvirt-gconfig-domain-graphics-vnc.c
index d9d1303..f2fc9d5 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-graphics-vnc.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-graphics-vnc.c
@@ -68,9 +68,10 @@ gvir_config_domain_graphics_vnc_new_from_xml(const gchar *xml,
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_GRAPHICS_VNC,
"graphics", NULL, xml, error);
- if (object == NULL)
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "vnc") != 0) {
+ g_object_unref(G_OBJECT(object));
return NULL;
- gvir_config_object_set_attribute(object, "type", "vnc", NULL);
+ }
return GVIR_CONFIG_DOMAIN_GRAPHICS_VNC(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-interface-bridge.c b/libvirt-gconfig/libvirt-gconfig-domain-interface-bridge.c
index ea5eafa..09a7efc 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-interface-bridge.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-interface-bridge.c
@@ -70,9 +70,10 @@ GVirConfigDomainInterfaceBridge *gvir_config_domain_interface_bridge_new_from_xm
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_INTERFACE_BRIDGE,
"interface", NULL, xml, error);
- if (object == NULL)
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "bridge") != 0) {
+ g_object_unref(G_OBJECT(object));
return NULL;
- gvir_config_object_set_attribute(object, "type", "bridge", NULL);
+ }
return GVIR_CONFIG_DOMAIN_INTERFACE_BRIDGE(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-interface-network.c b/libvirt-gconfig/libvirt-gconfig-domain-interface-network.c
index 1a7bfad..ce39234 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-interface-network.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-interface-network.c
@@ -69,9 +69,10 @@ GVirConfigDomainInterfaceNetwork *gvir_config_domain_interface_network_new_from_
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_INTERFACE_NETWORK,
"interface", NULL, xml, error);
- if (object == NULL)
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "network") != 0) {
+ g_object_unref(G_OBJECT(object));
return NULL;
- gvir_config_object_set_attribute(object, "type", "network", NULL);
+ }
return GVIR_CONFIG_DOMAIN_INTERFACE_NETWORK(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-interface-user.c b/libvirt-gconfig/libvirt-gconfig-domain-interface-user.c
index a455a73..4ede31f 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-interface-user.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-interface-user.c
@@ -69,8 +69,9 @@ GVirConfigDomainInterfaceUser *gvir_config_domain_interface_user_new_from_xml(co
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_INTERFACE_USER,
"interface", NULL, xml, error);
- if (object == NULL)
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "user") != 0) {
+ g_object_unref(G_OBJECT(object));
return NULL;
- gvir_config_object_set_attribute(object, "type", "user", NULL);
+ }
return GVIR_CONFIG_DOMAIN_INTERFACE_USER(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-timer-pit.c b/libvirt-gconfig/libvirt-gconfig-domain-timer-pit.c
index d75cd30..d5e57f1 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-timer-pit.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-timer-pit.c
@@ -67,6 +67,9 @@ GVirConfigDomainTimerPit *gvir_config_domain_timer_pit_new_from_xml(const gchar
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_TIMER_PIT,
"timer", NULL, xml, error);
- gvir_config_object_set_attribute(object, "name", "pit", NULL);
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "pit") != 0) {
+ g_object_unref(G_OBJECT(object));
+ g_return_val_if_reached(NULL);
+ }
return GVIR_CONFIG_DOMAIN_TIMER_PIT(object);
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-timer-rtc.c b/libvirt-gconfig/libvirt-gconfig-domain-timer-rtc.c
index b99c1e3..64b7f80 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-timer-rtc.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-timer-rtc.c
@@ -67,6 +67,9 @@ GVirConfigDomainTimerRtc *gvir_config_domain_timer_rtc_new_from_xml(const gchar
object = gvir_config_object_new_from_xml(GVIR_CONFIG_TYPE_DOMAIN_TIMER_RTC,
"timer", NULL, xml, error);
- gvir_config_object_set_attribute(object, "name", "rtc", NULL);
+ if (g_strcmp0(gvir_config_object_get_attribute(object, NULL, "type"), "rtc") != 0) {
+ g_object_unref(G_OBJECT(object));
+ g_return_val_if_reached(NULL);
+ }
return GVIR_CONFIG_DOMAIN_TIMER_RTC(object);
}
--
1.7.10.4
12 years, 1 month