Re: [libvirt] [PATCH v2 00/13] parallels: implement operations with hard disks
by Dmitry Guryanov
On 121114 14:32:41, Dmitry Guryanov wrote:
> This patch series adds ability to list existing disk images,
> create a new ones and add or remove hard disk devices to the VM.
>
> Changes in v2:
> rebased to current sources
Sorry, forgot to run make syntax-check, it fails in some places :(
>
> Dmitry Guryanov (13):
> parallels: add info about hard disk devices
> parallels: handle disk devices in parallelsDomainDefineXML
> parallels: split parallelsStorageOpen function
> parallels: remove unused code from storage driver
> parallels: create storage pools by VM list
> parallels: fix leaks in parallelsFindVolumes
> parallels: add info about volumes
> parallels: fill volumes capacity parameter
> parallels: split parallelsStorageVolumeDelete function
> parallels: add function parallelsGetDiskBusName
> parallels: add support of disks creation
> parallels: apply config after VM creation
> parallels: add support of removing disks
>
> src/parallels/parallels_driver.c | 346 +++++++++++++++++++++++++--
> src/parallels/parallels_storage.c | 479 +++++++++++++++++++++++++++++++------
> src/parallels/parallels_utils.h | 3 +
> 3 files changed, 731 insertions(+), 97 deletions(-)
>
> --
> 1.7.7.6
>
11 years, 12 months
[libvirt] [PATCH v5 0/4] Qemu/Gluster support in Libvirt
by Harsh Prateek Bora
Changelog:
v5:
- Separated initialization of new host members for nbd, rbd, sheepdog
in a separate patch [Patch 3/4]
- Fixed tests for appropriate args to DO_TEST
- Code cleanups for squashing pointer incrememnts into single line.
v4:
- Addressed review comment by Jiri on v3 updated series.
v3 updated:
- Fix other network backends (nbd, rbd, sheepdog) to initialize new members
(transport, socket) of _virDomainDiskHostDef appropriately so that garbage
values doesnt break the argv2xml tests.
v3:
- RNG schema updated as required for unix transport [Paolo]
- introduced another new attribute 'socket' for unix transport [Paolo]
- Uses virURIFormat and virURIParse for URI parsing. [danpb]
- updated documentation as required. [Jirka]
v2:
- Addressed review comments by Jiri
- Updated patcheset as per new URI spec
Ref: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg05199.html
v1:
- Initial prototype
Harsh Prateek Bora (4):
Add Gluster protocol as supported network disk backend
qemu: Add support for gluster protocol based network storage backend.
qemu: Fix nbd, rbd, sheepdog to initialize defaults for new host
members.
tests: Add tests for gluster protocol based network disks support
docs/formatdomain.html.in | 24 ++-
docs/schemas/domaincommon.rng | 33 +++-
src/conf/domain_conf.c | 77 ++++++--
src/conf/domain_conf.h | 12 ++
src/libvirt_private.syms | 2 +
src/qemu/qemu_command.c | 195 ++++++++++++++++++++-
tests/qemuargv2xmltest.c | 1 +
.../qemuxml2argv-disk-drive-network-gluster.args | 1 +
.../qemuxml2argv-disk-drive-network-gluster.xml | 34 ++++
tests/qemuxml2argvtest.c | 2 +
10 files changed, 352 insertions(+), 29 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.xml
--
1.7.11.7
11 years, 12 months
[libvirt] [PATCH v1 2/2][RFC] help to create disk images of non-shared migration
by liguang
try to do non-shared migration without bothering to
create disk images at target by hand.
consider this situation:
1. non-shared migration
virsh migrate --copy-storage-all ...
2. migration fails
3. create disk images required
qemu-img create ...
4 migration run smoothly
so, try do remove step 2, 3, 4
this kind of usage had been discussed before,
http://www.redhat.com/archives/libvir-list/2011-December/msg00451.html
this patch depends on my support offline migration patch:
https://www.redhat.com/archives/libvir-list/2012-November/msg00512.html
Signed-off-by: liguang <lig.fnst(a)cn.fujitsu.com>
---
src/qemu/qemu_conf.h | 2 +
src/qemu/qemu_driver.c | 1 +
src/qemu/qemu_migration.c | 275 ++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 277 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 47f349c..ad789e9 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -102,6 +102,8 @@ struct qemud_driver {
char *hugetlbfs_mount;
char *hugepage_path;
+ void *private;
+
unsigned int macFilter : 1;
ebtablesContext *ebtables;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b23056b..db11629 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1133,6 +1133,7 @@ static virDrvOpenStatus qemudOpen(virConnectPtr conn,
}
}
}
+ qemu_driver->private = conn;
conn->privateData = qemu_driver;
return VIR_DRV_OPEN_SUCCESS;
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 53171df..8b4e563 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -50,6 +50,7 @@
#include "storage_file.h"
#include "viruri.h"
#include "hooks.h"
+#include "dirname.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -72,6 +73,7 @@ enum qemuMigrationCookieFlags {
QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE,
QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT,
QEMU_MIGRATION_COOKIE_FLAG_NETWORK,
+ QEMU_MIGRATION_COOKIE_FLAG_COPYSTORAGE,
QEMU_MIGRATION_COOKIE_FLAG_LAST
};
@@ -79,13 +81,14 @@ enum qemuMigrationCookieFlags {
VIR_ENUM_DECL(qemuMigrationCookieFlag);
VIR_ENUM_IMPL(qemuMigrationCookieFlag,
QEMU_MIGRATION_COOKIE_FLAG_LAST,
- "graphics", "lockstate", "persistent", "network");
+ "graphics", "lockstate", "persistent", "network", "storage");
enum qemuMigrationCookieFeatures {
QEMU_MIGRATION_COOKIE_GRAPHICS = (1 << QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS),
QEMU_MIGRATION_COOKIE_LOCKSTATE = (1 << QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE),
QEMU_MIGRATION_COOKIE_PERSISTENT = (1 << QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT),
QEMU_MIGRATION_COOKIE_NETWORK = (1 << QEMU_MIGRATION_COOKIE_FLAG_NETWORK),
+ QEMU_MIGRATION_COOKIE_COPYSTORAGE = (1 << QEMU_MIGRATION_COOKIE_FLAG_COPYSTORAGE),
};
typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics;
@@ -119,6 +122,19 @@ struct _qemuMigrationCookieNetwork {
qemuMigrationCookieNetDataPtr net;
};
+typedef struct _qemuMigrationCookieStorageData qemuMigrationCookieStorageData;
+typedef qemuMigrationCookieStorageData *qemuMigrationCookieStorageDataPtr;
+struct _qemuMigrationCookieStorageData {
+ char *dsize;
+};
+
+typedef struct _qemuMigrationCookieStorage qemuMigrationCookieStorage;
+typedef qemuMigrationCookieStorage *qemuMigrationCookieStoragePtr;
+struct _qemuMigrationCookieStorage {
+ int ndisks;
+ qemuMigrationCookieStorageDataPtr disk;
+};
+
typedef struct _qemuMigrationCookie qemuMigrationCookie;
typedef qemuMigrationCookie *qemuMigrationCookiePtr;
struct _qemuMigrationCookie {
@@ -147,6 +163,9 @@ struct _qemuMigrationCookie {
/* If (flags & QEMU_MIGRATION_COOKIE_NETWORK) */
qemuMigrationCookieNetworkPtr network;
+
+ /* If (flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) */
+ qemuMigrationCookieStoragePtr storage;
};
static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap)
@@ -175,6 +194,21 @@ qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr network)
VIR_FREE(network);
}
+static void
+qemuMigrationCookieStorageFree(qemuMigrationCookieStoragePtr storage)
+{
+ int i;
+
+ if (!storage)
+ return;
+
+ if (storage->disk) {
+ for (i = 0; i < storage->ndisks; i++)
+ VIR_FREE(storage->disk[i].dsize);
+ }
+ VIR_FREE(storage->disk);
+ VIR_FREE(storage);
+}
static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
{
@@ -187,6 +221,9 @@ static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
if (mig->flags & QEMU_MIGRATION_COOKIE_NETWORK)
qemuMigrationCookieNetworkFree(mig->network);
+ if (mig->flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE)
+ qemuMigrationCookieStorageFree(mig->storage);
+
VIR_FREE(mig->localHostname);
VIR_FREE(mig->remoteHostname);
VIR_FREE(mig->name);
@@ -356,6 +393,45 @@ error:
return NULL;
}
+static qemuMigrationCookieStoragePtr
+qemuMigrationCookieStorageAlloc(struct qemud_driver *driver,
+ virDomainDefPtr def)
+{
+ int i;
+ qemuMigrationCookieStoragePtr mig;
+ virDomainBlockInfo info;
+ virDomainPtr dom;
+ virConnectPtr conn = driver->private;
+
+ dom = virGetDomain(conn, def->name, def->uuid);
+ if (!dom)
+ goto error;
+ dom->id = def->id;
+
+ if (VIR_ALLOC(mig) < 0)
+ goto no_memory;
+ if (VIR_ALLOC_N(mig->disk, def->ndisks) < 0)
+ goto no_memory;
+
+ mig->ndisks = def->ndisks;
+
+ for (i = 0; i < mig->ndisks; i++) {
+ if (virDomainGetBlockInfo(dom, def->disks[i]->src,
+ &info, 0) < 0)
+ goto error;
+ if (virAsprintf(&(mig->disk[i].dsize), "%llu", info.capacity) < 0)
+ goto no_memory;
+ }
+
+ return mig;
+
+no_memory:
+ virReportOOMError();
+error:
+ qemuMigrationCookieStorageFree(mig);
+ return NULL;
+}
+
static qemuMigrationCookiePtr
qemuMigrationCookieNew(virDomainObjPtr dom)
{
@@ -491,6 +567,31 @@ qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig,
return 0;
}
+static int qemuMigrationCookieAddStorage(qemuMigrationCookiePtr mig,
+ struct qemud_driver *driver,
+ virDomainObjPtr dom)
+{
+ if (mig->flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("migration storage data already present"));
+ return -1;
+ }
+
+ virDomainObjUnlock(dom);
+ qemuDriverUnlock(driver);
+
+ if (dom->def->ndisks > 0) {
+ mig->storage = qemuMigrationCookieStorageAlloc(driver, dom->def);
+ if (!mig->storage)
+ return -1;
+ mig->flags |= QEMU_MIGRATION_COOKIE_COPYSTORAGE;
+ }
+
+ qemuDriverLock(driver);
+ virDomainObjLock(dom);
+
+ return 0;
+}
static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf,
qemuMigrationCookieGraphicsPtr grap)
@@ -540,6 +641,19 @@ qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf,
virBufferAddLit(buf, " </network>\n");
}
+static void
+qemuMigrationCookieStorageXMLFormat(virBufferPtr buf,
+ qemuMigrationCookieStoragePtr dsz)
+{
+ int i = 0;
+
+ for (i = 0; i < dsz->ndisks; i++) {
+ char *dsize = dsz->disk[i].dsize;
+ virBufferAsprintf(buf, " <copystorage>\n");
+ virBufferAsprintf(buf, " <disksize>%s</disksize>\n", dsize);
+ virBufferAddLit(buf, " </copystorage>\n");
+ }
+}
static int
qemuMigrationCookieXMLFormat(struct qemud_driver *driver,
@@ -594,6 +708,9 @@ qemuMigrationCookieXMLFormat(struct qemud_driver *driver,
if ((mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) && mig->network)
qemuMigrationCookieNetworkXMLFormat(buf, mig->network);
+ if ((mig->flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) && mig->storage)
+ qemuMigrationCookieStorageXMLFormat(buf, mig->storage);
+
virBufferAddLit(buf, "</qemu-migration>\n");
return 0;
}
@@ -721,6 +838,44 @@ error:
goto cleanup;
}
+static qemuMigrationCookieStoragePtr
+qemuMigrationCookieStorageXMLParse(xmlXPathContextPtr ctxt)
+{
+ qemuMigrationCookieStoragePtr dsz;
+ int i, n;
+ xmlNodePtr *storage = NULL;
+
+ if (VIR_ALLOC(dsz) < 0)
+ goto no_memory;
+
+ if ((n = virXPathNodeSet("./copystorage", ctxt, &storage)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing storage information"));
+ goto error;
+ }
+
+ dsz->ndisks = n;
+ if (VIR_ALLOC_N(dsz->disk, dsz->ndisks) < 0)
+ goto no_memory;
+
+ for (i = 0; i < dsz->ndisks; i++) {
+ ctxt->node = storage[i];
+ if (!(dsz->disk[i].dsize = virXPathString("string(./disksize[1])", ctxt)))
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing tlsPort attribute in migration data"));
+ }
+
+cleanup:
+ VIR_FREE(storage);
+ return dsz;
+
+no_memory:
+ virReportOOMError();
+error:
+ qemuMigrationCookieStorageFree(dsz);
+ dsz = NULL;
+ goto cleanup;
+}
static int
qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
@@ -873,6 +1028,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
(!(mig->network = qemuMigrationCookieNetworkXMLParse(ctxt))))
goto error;
+ if ((flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) &&
+ virXPathBoolean("count(./copystorage) > 0", ctxt) &&
+ (!(mig->storage = qemuMigrationCookieStorageXMLParse(ctxt))))
+ goto error;
+
return 0;
error:
@@ -937,6 +1097,11 @@ qemuMigrationBakeCookie(qemuMigrationCookiePtr mig,
return -1;
}
+ if (flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE &&
+ qemuMigrationCookieAddStorage(mig, driver, dom) < 0) {
+ return -1;
+ }
+
if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig)))
return -1;
@@ -1442,6 +1607,14 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
QEMU_MIGRATION_COOKIE_LOCKSTATE) < 0)
goto cleanup;
+ if (flags & (VIR_MIGRATE_NON_SHARED_DISK |
+ VIR_MIGRATE_NON_SHARED_INC)) {
+ if (qemuMigrationBakeCookie(mig, driver, vm,
+ cookieout, cookieoutlen,
+ QEMU_MIGRATION_COOKIE_COPYSTORAGE) < 0)
+ goto cleanup;
+ }
+
if (flags & VIR_MIGRATE_OFFLINE) {
if (flags & (VIR_MIGRATE_NON_SHARED_DISK |
VIR_MIGRATE_NON_SHARED_INC)) {
@@ -1487,6 +1660,91 @@ cleanup:
}
+/*
+ if gen is true, find out disk images migration required,
+ so try to generate them at target,
+ if gen is false, delete disk images generated before.
+*/
+static int qemuMigrationHandleDiskFiles(struct qemud_driver *driver,
+ virDomainDefPtr def, bool gen,
+ qemuMigrationCookiePtr mig)
+{
+ char *tmp_dir = NULL, *outbuf = NULL;
+ const char *img_tool = driver->qemuImgTool;
+ const char *disk_format[] = {"none", "raw", "none", "none", "none",
+ "cow", "none", "none", "qcow", "qcow2",
+ "qed", "vmdk", "vpc","none", "none"
+ };
+ virCommandPtr cmd = NULL;
+ int i, ret = -1;
+
+ if (!def->ndisks)
+ return 0;
+
+ if (img_tool == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unable to find kvm-img or qemu-img"));
+ goto error;
+ }
+
+ for (i = 0; i < def->ndisks; i++) {
+ if (STRNEQ(def->disks[i]->driverName, "qemu"))
+ continue;
+ if (def->disks[i]->src == NULL)
+ continue;
+ if (virFileExists(def->disks[i]->src) && gen)
+ continue;
+ if (!gen && !virFileExists(def->disks[i]->src))
+ continue;
+ if ((tmp_dir = mdir_name(def->disks[i]->src)) == NULL)
+ continue;
+ if (!virFileExists(tmp_dir))
+ if (virFileMakePath(tmp_dir) < 0)
+ continue;
+ if (STREQ(disk_format[def->disks[i]->format], "none"))
+ continue;
+ if (def->disks[i]->format < VIR_STORAGE_FILE_RAW)
+ goto error;
+ if (def->disks[i]->format >= VIR_STORAGE_FILE_LAST)
+ goto error;
+
+ if (gen) {
+ char *dsize = mig->storage->disk[i].dsize;
+ cmd = virCommandNewArgList(img_tool, "create", "-f",
+ disk_format[def->disks[i]->format],
+ def->disks[i]->src, NULL);
+ virCommandAddArgFormat(cmd, "%s", dsize);
+ if (def->disks[i]->encryption)
+ virCommandAddArgList(cmd, "-o", "encryption=on", NULL);
+ virCommandSetOutputBuffer(cmd, &outbuf);
+ if (virCommandRun(cmd, NULL) < 0) {
+ virReportSystemError(errno, "%s", outbuf);
+ goto cleanup;
+ }
+ } else {
+ if (unlink(def->disks[i]->src) < 0) {
+ virReportError(errno, "%s", _("fail to unlink disk image file"));
+ goto cleanup;
+ }
+ }
+ virCommandFree(cmd);
+ VIR_FREE(tmp_dir);
+ VIR_FREE(outbuf);
+ }
+
+ ret = 0;
+
+cleanup:
+ if (ret < 0) {
+ virCommandFree(cmd);
+ VIR_FREE(tmp_dir);
+ VIR_FREE(outbuf);
+ }
+error:
+ return ret;
+}
+
+
/* Prepare is the first step, and it runs on the destination host.
*/
@@ -1602,6 +1860,15 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
/* virDomainAssignDef already set the error */
goto cleanup;
}
+
+ if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
+ QEMU_MIGRATION_COOKIE_COPYSTORAGE)))
+ goto cleanup;
+
+ if (flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC))
+ if (qemuMigrationHandleDiskFiles(driver, def, true, mig) < 0)
+ goto endjob;
+
def = NULL;
priv = vm->privateData;
priv->origname = origname;
@@ -3247,6 +3514,7 @@ qemuMigrationFinish(struct qemud_driver *driver,
virErrorPtr orig_err = NULL;
int cookie_flags = 0;
qemuDomainObjPrivatePtr priv = vm->privateData;
+ bool migration_status = false;
VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
"cookieout=%p, cookieoutlen=%p, flags=%lx, retcode=%d",
@@ -3416,7 +3684,12 @@ qemuMigrationFinish(struct qemud_driver *driver,
if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, 0) < 0)
VIR_WARN("Unable to encode migration cookie");
+ migration_status = true;
+
endjob:
+ if (!migration_status && flags &
+ (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC))
+ qemuMigrationHandleDiskFiles(driver, vm->def, false, NULL);
if (qemuMigrationJobFinish(driver, vm) == 0) {
vm = NULL;
} else if (!vm->persistent && !virDomainObjIsActive(vm)) {
--
1.7.2.5
11 years, 12 months
[libvirt] [PATCH 0/6] Unprivileged SG_IO support
by Osier Yang
Hi,
As a result of RFC [1], this implements the unprivleged SG_IO
support. Though this is a bit rushed, and I still have no chance
to test it yet, but I'd like see an earlier reviewing.
@Paolo, please let me known once you have a kernel build with
the new sysfs knob support. Thanks!
Osier Yang (6):
unpriv_sgio: Add docs and rng schema for new XML unpriv_sgio
unpriv_sgio: Parse and format the new XML
unpriv_sgio: Prepare helpers for unpriv_sgio setting
unpriv_sgio: Manage unpriv_sgio in domain's lifecyle
unpriv_sgio: Do not restore unpriv_sgio if the disk is being used
unpriv_sgio: Error out if the unpriv_sgio setting conflicts with
others
docs/formatdomain.html.in | 10 +-
docs/schemas/domaincommon.rng | 52 ++++--
src/conf/domain_conf.c | 168 ++++++++++++++++++--
src/conf/domain_conf.h | 18 ++
src/libvirt_private.syms | 6 +
src/qemu/qemu_process.c | 54 +++++++
src/util/util.c | 154 ++++++++++++++++++
src/util/util.h | 7 +
...l2argv-disk-scsi-lun-passthrough-upriv-sgio.xml | 32 ++++
tests/qemuxml2xmltest.c | 1 +
10 files changed, 472 insertions(+), 30 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough-upriv-sgio.xml
[1] https://www.redhat.com/archives/libvir-list/2012-November/msg00988.html
Regards,
Osier
11 years, 12 months
[libvirt] [test-API][PATCH V2] Add managedsave test cases
by hongming
The patch V2 inclues fixing all spots commented by Gren
The managedsave test cases and test suite cover test include
verifying virsh commands managedsave(include all flags and their
combination)/managedsave-remove and managedSaveRemove/ManagedSave/
hasManagedSaveImage python APIs.
The following new files be created.
new file: cases/managedsave.conf
- Test all test cases
new file: repos/managedsave/__init__.py
new file: repos/managedsave/managedsave.py
- Test mangaedsave command/API and all flags
new file: repos/managedsave/managedsave_remove.py
- Test managedsave-remove command/API
new file: repos/managedsave/managedsave_start.py
- Verfiy managedsave'flags and start from managedsave image
---
cases/managedsave.conf | 63 ++++++++++++
repos/managedsave/managedsave.py | 159 +++++++++++++++++++++++++++++++
repos/managedsave/managedsave_remove.py | 60 ++++++++++++
repos/managedsave/managedsave_start.py | 150 +++++++++++++++++++++++++++++
4 files changed, 432 insertions(+), 0 deletions(-)
create mode 100644 cases/managedsave.conf
create mode 100644 repos/managedsave/__init__.py
create mode 100644 repos/managedsave/managedsave.py
create mode 100644 repos/managedsave/managedsave_remove.py
create mode 100644 repos/managedsave/managedsave_start.py
diff --git a/cases/managedsave.conf b/cases/managedsave.conf
new file mode 100644
index 0000000..8dcafe2
--- /dev/null
+++ b/cases/managedsave.conf
@@ -0,0 +1,63 @@
+domain:install_linux_cdrom
+ guestname
+ $defaultname
+ guestos
+ $defaultos
+ guestarch
+ $defaultarch
+ vcpu
+ $defaultvcpu
+ memory
+ $defaultmem
+ hddriver
+ $defaulthd
+ nicdriver
+ $defaultnic
+ imageformat
+ qcow2
+ macaddr
+ 54:52:00:4a:16:30
+
+#VIR_DOMAIN_SAVE_BYPASS_CACHE = 1
+#VIR_DOMAIN_SAVE_RUNNING = 2
+#VIR_DOMAIN_SAVE_PAUSED = 4
+#No_FLAGS = 0
+managedsave:managedsave
+ guestname
+ $defaultname
+ flags
+ 1|2
+
+managedsave:managedsave_start
+ guestname
+ $defaultname
+ flags
+ noping
+
+managedsave:managedsave
+ guestname
+ $defaultname
+ flags
+ 1|4
+
+managedsave:managedsave_start
+ guestname
+ $defaultname
+ flags
+ noping
+
+managedsave:managedsave
+ guestname
+ $defaultname
+ flags
+ 0
+
+managedsave:managedsave_remove
+ guestname
+ $defaultname
+
+managedsave:managedsave_start
+ guestname
+ $defaultname
+ flags
+ noping
diff --git a/repos/managedsave/__init__.py b/repos/managedsave/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/repos/managedsave/managedsave.py b/repos/managedsave/managedsave.py
new file mode 100644
index 0000000..a126cd8
--- /dev/null
+++ b/repos/managedsave/managedsave.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+
+import os
+import math
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('guestname', 'flags',)
+optional_params = {}
+
+def check_guest_status(*args):
+ """Check guest current status"""
+ (domobj, logger) = args
+ state = domobj.info()[0]
+ logger.debug("current guest status: %s" % state)
+
+ if state == libvirt.VIR_DOMAIN_SHUTOFF or \
+ state == libvirt.VIR_DOMAIN_SHUTDOWN or \
+ state == libvirt.VIR_DOMAIN_BLOCKED:
+ return False
+ else:
+ return True
+
+def check_savefile_create(*args):
+ """Check guest's managed save file be created"""
+
+ (guestname) = args
+ cmds = "ls /var/lib/libvirt/qemu/save/%s" % guestname + ".save -lh"
+ logger.info("Execute cmd %s" % cmds)
+ (status, output) = utils.exec_cmd(cmds, shell=True)
+ if status != 0:
+ logger.error("No managed save file")
+ return False
+ else :
+ logger.info("managed save file exists")
+ return True
+
+def compare_cachedfile(cachebefore, cacheafter):
+ """Compare cached value before managed save and its value after
+ managed save """
+
+ diff = cacheafter - cachebefore
+ logger.info("diff is %s " % diff)
+ percent = math.fabs(diff)/cachebefore
+ logger.info("diff percent is %s " % percent)
+ if percent < 0.05:
+ return True
+ else:
+ return False
+
+def get_cachevalue():
+ """Get the file system cached value """
+
+ cmds = "head -n4 /proc/meminfo|grep Cached|awk '{print $2}'"
+ (status, output) = utils.exec_cmd(cmds, shell=True)
+ if status != 0:
+ logger.error("Fail to run cmd line to get cache")
+ return 1
+ else:
+ logger.debug(output[0])
+ cachevalue= int(output[0])
+ return cachevalue
+
+def managedsave(params):
+ """Managed save a running domain"""
+
+ global logger
+ logger = params['logger']
+ guestname = params['guestname']
+ flags = params ['flags']
+ #Save given flags to sharedmod.data
+ sharedmod.data['flagsave'] = flags
+
+ logger.info("The given flags are %s " % flags)
+ if not '|' in flags:
+ flagn = int(flags)
+ else:
+ # bitwise-OR of flags of managedsave
+ flaglist = flags.split('|')
+ flagn = 0
+ for flag in flaglist:
+ flagn |= int(flag)
+
+ conn = sharedmod.libvirtobj['conn']
+ domobj = conn.lookupByName(guestname)
+
+ if not check_guest_status(domobj, logger):
+ logger.error("Current guest status is shutoff")
+ return 1
+
+ try:
+
+ logger.info("bitwise OR value of flags is %s" % flagn)
+
+ if flagn == 0:
+ logger.info("managedsave %s domain with no flag" % guestname)
+ elif flagn == 1:
+ logger.info("managedsave %s domain --bypass-cache" % guestname)
+ elif flagn == 2:
+ logger.info("managedsave %s domain --running" % guestname)
+ elif flagn == 3:
+ logger.info("managedsave %s domain --running --bypass-cache"\
+ % guestname)
+ elif flagn == 4:
+ logger.info("managedsave %s domain --paused" % guestname)
+ elif flagn == 5:
+ logger.info("managedsave %s domain --paused --bypass-cache"\
+ % guestname)
+ elif flagn == 6:
+ logger.error("--running and --paused are mutually exclusive")
+ return 1
+ elif flagn == 7:
+ logger.error("--running and --paused are mutually exclusive")
+ return 1
+ else:
+ logger.error("Wrong flags be given and fail to managedsave domain")
+ return 1
+
+ #If given flags include bypass-cache,check if bypass file system cache
+ if flagn % 2 == 1:
+ logger.info("Given flags include --bypass-cache")
+ os.system('echo 3 > /proc/sys/vm/drop_caches')
+ cache_before = get_cachevalue()
+ logger.info("Cached value before managedsave is %s" % cache_before)
+
+ domobj.managedSave(flagn)
+
+ cache_after = get_cachevalue()
+ logger.info("Cached value after managedsave is %s" % cache_after)
+
+ if compare_cachedfile(cache_before, cache_after):
+ logger.info("Bypass file system cache successfully")
+ else:
+ logger.error("Bypass file system cache failed")
+ return 1
+ else:
+ domobj.managedSave(flagn)
+
+ #Check if domain has managedsave image
+ if domobj.hasManagedSaveImage(0) and \
+ domobj.info()[0]==libvirt.VIR_DOMAIN_SHUTOFF and \
+ check_savefile_create(guestname):
+ logger.info("Domain %s managedsave successfully " % guestname)
+ else:
+ logger.error("Fail to managedsave domain")
+ return 1
+
+ except libvirtError, e:
+ logger.error("API error message: %s, error code is %s" \
+ % e.message)
+ logger.error("Fail to managedsave %s domain" % guestname)
+ return 1
+
+ return 0
+
diff --git a/repos/managedsave/managedsave_remove.py b/repos/managedsave/managedsave_remove.py
new file mode 100644
index 0000000..a0eec1f
--- /dev/null
+++ b/repos/managedsave/managedsave_remove.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# Save domain as a statefile
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('guestname',)
+optional_params = {}
+
+def check_savefile_remove(*args):
+ """Check if guest's managedsave file be removed """
+
+ (guestname) = args
+ cmds = "ls /var/lib/libvirt/qemu/save/%s" % guestname + ".save -lh"
+ logger.info("Execute cmd %s" % cmds)
+ (status, output) = utils.exec_cmd(cmds, shell=True)
+ if status != 0:
+ logger.info("No managed save file")
+ return True
+ else :
+ logger.error("managed save file exits")
+ return False
+
+def managedsave_remove(params):
+ """Remove an existing managed save state file from a domain"""
+
+ global logger
+ logger = params['logger']
+ guestname = params['guestname']
+
+ conn = sharedmod.libvirtobj['conn']
+ domobj = conn.lookupByName(guestname)
+
+ if not domobj.hasManagedSaveImage(0) and check_savefile_remove(guestname):
+ logger.error("Domain %s hasn't managedsave image" % guestname)
+ return 1
+ else:
+ logger.info("Domain %s has managedsave image" % guestname)
+
+ try:
+ domobj.managedSaveRemove(0)
+ #Check if domain has managedsave image
+ if not domobj.hasManagedSaveImage(0) and \
+ check_savefile_remove(guestname):
+ logger.info("Domain %s's managedsave image has been removed"\
+ % guestname)
+ else:
+ logger.error("Fail to remove managedsave domain")
+ return 1
+
+ except libvirtError, e:
+ logger.error("API error message: %s, error code is %s" % e.message)
+ logger.error("Fail to managedsave %s domain" % guestname)
+ return 1
+
+ return 0
+
diff --git a/repos/managedsave/managedsave_start.py b/repos/managedsave/managedsave_start.py
new file mode 100644
index 0000000..70539ae
--- /dev/null
+++ b/repos/managedsave/managedsave_start.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+
+import time
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('guestname',)
+optional_params = {'flags' : ''}
+
+NONE = 0
+START_PAUSED = 1
+
+def check_savefile_remove(*args):
+ """Check guest managed save file"""
+ (guestname) = args
+ cmds = "ls /var/lib/libvirt/qemu/save/%s" % guestname + ".save -lh"
+ logger.info("Execute cmd %s" % cmds)
+ (status, output) = utils.exec_cmd(cmds, shell=True)
+ if status != 0:
+ logger.info("No managed save file")
+ return True
+ else :
+ logger.error("managed save file exists")
+ return False
+
+def managedsave_start(params):
+ """ Start domain with managedsave image and check if its status is right
+ according to given flags of running managedsave command.If it is
+ correctly paused , resume it.
+
+ Argument is a dictionary with two keys:
+ {'logger': logger, 'guestname': guestname}
+
+ logger -- an object of utils/log.py
+ mandatory arguments : guestname -- same as the domain name
+ optional arguments : flags -- domain create flags <none|start_paused
+ |noping>.It allows only one flag be given.
+
+ Return 0 on SUCCESS or 1 on FAILURE
+ """
+ domname = params['guestname']
+ global logger
+ logger = params['logger']
+ flags = params.get('flags', '')
+ # Get given flags of managedsave
+ if sharedmod.data.has_key('flagsave'):
+ flagsave = sharedmod.data.get('flagsave')
+ else:
+ logger.error("Failed to get flags from managedsave")
+ # Clean sharedmod.data
+ sharedmod.data = {}
+
+ conn = sharedmod.libvirtobj['conn']
+ domobj = conn.lookupByName(domname)
+
+ timeout = 600
+ logger.info('start domain')
+ # Check if guest has managedsave image before start
+ if domobj.hasManagedSaveImage(0) :
+ logger.info("Domain has managedsave image")
+ else:
+ logger.info("Domain hasn't managedsave image")
+
+ try:
+ if "none" in flags:
+ domobj.createWithFlags(NONE)
+ elif "start_paused" in flags:
+ domobj.createWithFlags(START_PAUSED)
+ else:
+ # this covers flags = None as well as flags = 'noping'
+ domobj.create()
+ except libvirtError, e:
+ logger.error("API error message: %s, error code is %s" \
+ % e.message)
+ logger.error("start failed")
+ return 1
+
+ while timeout:
+ state = domobj.info()[0]
+ expect_states = [libvirt.VIR_DOMAIN_RUNNING,libvirt.VIR_DOMAIN_PAUSED,\
+ libvirt.VIR_DOMAIN_NOSTATE,libvirt.VIR_DOMAIN_BLOCKED]
+
+ if state in expect_states:
+ break
+
+ time.sleep(10)
+ timeout -= 10
+ logger.info(str(timeout) + "s left")
+
+ if timeout <= 0:
+ logger.error('The domain state is not as expected, state: ' + state)
+ return 1
+
+ logger.info("Guest started")
+
+ """If domain's current state is paused. Check if start command has
+ --paused flag or managedsave has --paused flag (given flags in managedsave
+ include '4'). If yes, it means domain successfully paused , then resume it.
+ If not, throw error -guest state error."""
+
+ if state == libvirt.VIR_DOMAIN_PAUSED:
+ if "start_paused" in flags or "4" in flagsave:
+ logger.info("Guest paused successfully ")
+
+ try:
+ domobj.resume()
+
+ except libvirtError, e:
+ logger.error("API error message: %s, error code is %s" \
+ % e.message)
+ logger.error("resume failed")
+ return 1
+ stateresume = domobj.info()[0]
+ expect_states = [libvirt.VIR_DOMAIN_RUNNING, \
+ libvirt.VIR_DOMAIN_NOSTATE, \
+ libvirt.VIR_DOMAIN_BLOCKED]
+ if stateresume not in expect_states:
+ logger.error('The domain state is not equal to "paused"')
+ return 1
+ else:
+ logger.info('Domain resume successfully')
+ return 0
+ else:
+ logger.error("guest state error")
+ return 1
+
+ # Get domain ip and ping ip to check domain's status
+ if not "noping" in flags:
+ mac = utils.get_dom_mac_addr(domname)
+ logger.info("get ip by mac address")
+ ip = utils.mac_to_ip(mac, 180)
+
+ logger.info('ping guest')
+ if not utils.do_ping(ip, 300):
+ logger.error('Failed on ping guest, IP: ' + str(ip))
+ return 1
+
+ # Check if domain' managedsave image exists,if not, return 0.
+ if not domobj.hasManagedSaveImage(0) and check_savefile_remove(domname):
+ logger.info("Domain %s with managedsave image successfully start" \
+ % domname)
+ return 0
+ else:
+ logger.error("Fail to start domain s% with managedsave image" \
+ % domname)
+ return 1
--
1.7.7.6
11 years, 12 months
[libvirt] libvirt [PATCHv2 1/2] Refactor ESX storage driver to implement facade pattern
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)
One of the task base storage driver need to do is to decide which backend
driver needs to be invoked for a given request. This approach extends
virStoragePool and virStorageVol to store extra parameters:
1. privateData: stores pointer to respective backend storage driver.
2. privateDataFreeFunc: stores cleanup function pointer.
virGetStoragePool and virGetStorageVol are modfiied to accept these extra
parameters as user params. virStoragePoolDispose and virStorageVolDispose
checks for cleanup operation if available.
---
daemon/remote.c | 6 +-
src/Makefile.am | 1 +
src/conf/storage_conf.c | 3 +-
src/datatypes.c | 25 +-
src/datatypes.h | 24 +-
src/esx/esx_driver.c | 6 +-
src/esx/esx_storage_backend_vmfs.c | 1491 ++++++++++++++++++++++++++++++++++++
src/esx/esx_storage_backend_vmfs.h | 30 +
src/esx/esx_storage_driver.c | 1319 +++++--------------------------
src/esx/esx_vi.c | 5 +-
src/esx/esx_vi.h | 3 +-
src/parallels/parallels_storage.c | 24 +-
src/remote/remote_driver.c | 6 +-
src/storage/storage_driver.c | 28 +-
src/test/test_driver.c | 30 +-
src/vbox/vbox_tmpl.c | 14 +-
16 files changed, 1843 insertions(+), 1172 deletions(-)
create mode 100644 src/esx/esx_storage_backend_vmfs.c
create mode 100644 src/esx/esx_storage_backend_vmfs.h
diff --git a/daemon/remote.c b/daemon/remote.c
index 340d07d..41b8ea8 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -4651,14 +4651,16 @@ get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface)
static virStoragePoolPtr
get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool)
{
- return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid);
+ return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid,
+ NULL, NULL);
}
static virStorageVolPtr
get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol)
{
virStorageVolPtr ret;
- ret = virGetStorageVol(conn, vol.pool, vol.name, vol.key);
+ ret = virGetStorageVol(conn, vol.pool, vol.name, vol.key,
+ NULL, NULL);
return ret;
}
diff --git a/src/Makefile.am b/src/Makefile.am
index 1f32263..4026a15 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -493,6 +493,7 @@ ESX_DRIVER_SOURCES = \
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_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 \
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 9a765d8..1c9934c 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -1981,7 +1981,8 @@ virStoragePoolList(virConnectPtr conn,
if (pools) {
if (!(pool = virGetStoragePool(conn,
poolobj->def->name,
- poolobj->def->uuid))) {
+ poolobj->def->uuid,
+ NULL, NULL))) {
virStoragePoolObjUnlock(poolobj);
goto cleanup;
}
diff --git a/src/datatypes.c b/src/datatypes.c
index ff7c524..eab7500 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -379,6 +379,8 @@ virInterfaceDispose(void *obj)
* @conn: the hypervisor connection
* @name: pointer to the storage pool name
* @uuid: pointer to the uuid
+ * @void*: pointer to driver specific privateData
+ * @virFreeCallback: cleanup function pointer specfic to driver
*
* Lookup if the storage pool is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
@@ -389,7 +391,8 @@ virInterfaceDispose(void *obj)
*/
virStoragePoolPtr
virGetStoragePool(virConnectPtr conn, const char *name,
- const unsigned char *uuid)
+ const unsigned char *uuid,
+ void *privateData, virFreeCallback func)
{
virStoragePoolPtr ret = NULL;
@@ -412,6 +415,10 @@ virGetStoragePool(virConnectPtr conn, const char *name,
ret->conn = virObjectRef(conn);
memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
+ /* set the driver specific data */
+ ret->privateData = privateData;
+ ret->privateDataFreeFunc = func;
+
return ret;
no_memory:
@@ -444,6 +451,10 @@ virStoragePoolDispose(void *obj)
VIR_FREE(pool->name);
virObjectUnref(pool->conn);
+
+ if (pool->privateDataFreeFunc) {
+ pool->privateDataFreeFunc(pool->privateData);
+ }
}
@@ -453,6 +464,8 @@ virStoragePoolDispose(void *obj)
* @pool: pool owning the volume
* @name: pointer to the storage vol name
* @key: pointer to unique key of the volume
+ * @void*: pointer to driver specific privateData
+ * @virFreeCallback: cleanup function pointer specfic to driver
*
* Lookup if the storage vol is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
@@ -463,7 +476,7 @@ virStoragePoolDispose(void *obj)
*/
virStorageVolPtr
virGetStorageVol(virConnectPtr conn, const char *pool, const char *name,
- const char *key)
+ const char *key, void *privateData, virFreeCallback func)
{
virStorageVolPtr ret = NULL;
@@ -489,6 +502,10 @@ virGetStorageVol(virConnectPtr conn, const char *pool, const char *name,
ret->conn = virObjectRef(conn);
+ /* set driver specific data */
+ ret->privateData = privateData;
+ ret->privateDataFreeFunc = func;
+
return ret;
no_memory:
@@ -520,6 +537,10 @@ virStorageVolDispose(void *obj)
VIR_FREE(vol->name);
VIR_FREE(vol->pool);
virObjectUnref(vol->conn);
+
+ if (vol->privateDataFreeFunc) {
+ vol->privateDataFreeFunc(vol->privateData);
+ }
}
diff --git a/src/datatypes.h b/src/datatypes.h
index e4c8262..264d9f6 100644
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -196,6 +196,13 @@ struct _virStoragePool {
virConnectPtr conn; /* pointer back to the connection */
char *name; /* the storage pool external name */
unsigned char uuid[VIR_UUID_BUFLEN]; /* the storage pool unique identifier */
+
+ /* Private data pointer which can be used by driver as they wish
+ * Cleanup function pointer can be hooked to provide custom cleanup
+ * operation.
+ */
+ void *privateData;
+ virFreeCallback privateDataFreeFunc;
};
/**
@@ -209,6 +216,13 @@ struct _virStorageVol {
char *pool; /* Pool name of owner */
char *name; /* the storage vol external name */
char *key; /* unique key for storage vol */
+
+ /* Private data pointer which can be used by driver as they wish
+ * Cleanup function pointer can be hooked to provide custom cleanup
+ * operation.
+ */
+ void *privateData;
+ virFreeCallback privateDataFreeFunc;
};
/**
@@ -293,12 +307,16 @@ virInterfacePtr virGetInterface(virConnectPtr conn,
const char *name,
const char *mac);
virStoragePoolPtr virGetStoragePool(virConnectPtr conn,
- const char *name,
- const unsigned char *uuid);
+ const char *name,
+ const unsigned char *uuid,
+ void *privateData,
+ virFreeCallback func);
virStorageVolPtr virGetStorageVol(virConnectPtr conn,
const char *pool,
const char *name,
- const char *key);
+ const char *key,
+ void *privateData,
+ virFreeCallback func);
virNodeDevicePtr virGetNodeDevice(virConnectPtr conn,
const char *name);
virSecretPtr virGetSecret(virConnectPtr conn,
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 56f31bb..0374a98 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -163,7 +163,8 @@ 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;
@@ -307,7 +308,8 @@ 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_vmfs.c b/src/esx/esx_storage_backend_vmfs.c
new file mode 100644
index 0000000..d934e57
--- /dev/null
+++ b/src/esx/esx_storage_backend_vmfs.c
@@ -0,0 +1,1491 @@
+
+/*
+ * esx_storage_backend_vmfs.c: ESX backend storage driver for
+ * managing VMFS datastores
+ *
+ * Copyright (C) 2012 Ata E Husain Bohra <ata.husain(a)hotmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "internal.h"
+#include "md5.h"
+#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, let the base driver handle the error reporting */
+ 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, let the base driver handle the error reporting */
+ goto cleanup;
+ }
+
+ /*
+ * Datastores don't have a UUID, but we can use the 'host.mountInfo.path'
+ * property as source for a UUID. The mount path is unique per host and
+ * cannot change during the lifetime of the datastore.
+ *
+ * The MD5 sum of the mount path can be used as UUID, assuming MD5 is
+ * considered to be collision-free enough for this use case.
+ */
+ if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
+ &hostMount, esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ if (hostMount == NULL) {
+ /* routine called by base storage driver to determine correct backend
+ * driver, leave error reporting to the base driver
+ */
+ goto cleanup;
+ }
+
+ md5_buffer(hostMount->mountInfo->path,
+ strlen(hostMount->mountInfo->path), md5);
+
+ pool = virGetStoragePool(conn, name, md5,
+ &esxStorageBackendVMFSDrv, NULL);
+
+ 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) {
+ /* it may happen that the storage pool belong to non VMFS type,
+ * leave error reporting to the base storage driver.
+ */
+ goto cleanup;
+ }
+
+ md5_buffer(hostMount->mountInfo->path,
+ strlen(hostMount->mountInfo->path), md5);
+
+ if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) {
+ break;
+ }
+ }
+
+ if (datastore == NULL) {
+ goto cleanup;
+ }
+
+ if (esxVI_GetStringValue(datastore, "summary.name", &name,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ pool = virGetStoragePool(conn, name, uuid,
+ &esxStorageBackendVMFSDrv, NULL);
+
+ 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,
+ &esxStorageBackendVMFSDrv, NULL);
+
+ 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,
+ &esxStorageBackendVMFSDrv, NULL);
+
+ 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,
+ &esxStorageBackendVMFSDrv,
+ NULL);
+ goto cleanup;
+ }
+ }
+ }
+ }
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastoreList);
+ esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+ VIR_FREE(directoryAndFileName);
+ VIR_FREE(datastorePath);
+ VIR_FREE(volumeName);
+ VIR_FREE(uuid_string);
+
+ return volume;
+}
+
+static virStorageVolPtr
+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,
+ &esxStorageBackendVMFSDrv, NULL);
+
+ 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,
+ &esxStorageBackendVMFSDrv, NULL);
+
+ cleanup:
+ VIR_FREE(sourceDatastorePath);
+ virStorageVolDefFree(def);
+ VIR_FREE(unescapedDatastorePath);
+ VIR_FREE(unescapedDirectoryName);
+ VIR_FREE(unescapedDirectoryAndFileName);
+ VIR_FREE(directoryName);
+ VIR_FREE(fileName);
+ VIR_FREE(datastorePathWithoutFileName);
+ VIR_FREE(datastorePath);
+ esxVI_FileInfo_Free(&fileInfo);
+ esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
+ VIR_FREE(uuid_string);
+ VIR_FREE(key);
+
+ return volume;
+}
+
+
+
+static 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) {
+ /* Scale from kilobyte to byte */
+ def.capacity = vmDiskFileInfo->capacityKb->value * 1024;
+ 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, /* 1.0.0 */
+ .close = NULL, /* 1.0.0 */
+ .numOfPools = esxStorageBackendVMFSNumberOfStoragePools, /* 1.0.0 */
+ .listPools = esxStorageBackendVMFSListStoragePools, /* 1.0.0 */
+ .poolLookupByName = esxStorageBackendVMFSPoolLookupByName, /* 1.0.0 */
+ .poolLookupByUUID = esxStorageBackendVMFSPoolLookupByUUID, /* 1.0.0 */
+ .poolRefresh = esxStorageBackendVMFSPoolRefresh, /* 1.0.0 */
+ .poolGetInfo = esxStorageBackendVMFSPoolGetInfo, /* 1.0.0 */
+ .poolGetXMLDesc = esxStorageBackendVMFSPoolGetXMLDesc, /* 1.0.0 */
+ .poolNumOfVolumes = esxStorageBackendVMFSPoolNumberOfStorageVolumes, /* 1.0.0 */
+ .poolListVolumes = esxStorageBackendVMFSPoolListStorageVolumes, /* 1.0.0 */
+ .volLookupByName = esxStorageBackendVMFSVolumeLookupByName, /* 1.0.0 */
+ .volLookupByKey = esxStorageBackendVMFSVolumeLookupByKey, /* 1.0.0 */
+ .volLookupByPath = esxStorageBackendVMFSVolumeLookupByPath, /* 1.0.0 */
+ .volCreateXML = esxStorageBackendVMFSVolumeCreateXML, /* 1.0.0 */
+ .volCreateXMLFrom = esxStorageBackendVMFSVolumeCreateXMLFrom, /* 1.0.0 */
+ .volGetXMLDesc = esxStorageBackendVMFSVolumeGetXMLDesc, /* 1.0.0 */
+ .volDelete = esxStorageBackendVMFSVolumeDelete, /* 1.0.0 */
+ .volWipe = esxStorageBackendVMFSVolumeWipe, /* 1.0.0 */
+ .volGetPath = esxStorageBackendVMFSVolumeGetPath, /* 1.0.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..d48a519
--- /dev/null
+++ b/src/esx/esx_storage_backend_vmfs.h
@@ -0,0 +1,30 @@
+/*
+ * esx_storage_backend_vmfs.h: ESX storage backend for VMFS datastores
+ *
+ * Copyright (C) 2012 Ata E Husain Bohra <ata.husain(a)hotmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 08d5ab1..5530ea7 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 2010-2011 Red Hat, Inc.
* Copyright (C) 2010 Matthias Bolte <matthias.bolte(a)googlemail.com>
+ * Copyright (C) 2012 Ata E Husain Bohra <ata.husain(a)hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,82 +25,29 @@
#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 "memory.h"
#include "storage_conf.h"
-#include "storage_file.h"
#include "esx_private.h"
#include "esx_storage_driver.h"
-#include "esx_vi.h"
-#include "esx_vi_methods.h"
-#include "esx_util.h"
+#include "esx_storage_backend_vmfs.h"
#define VIR_FROM_THIS VIR_FROM_ESX
-/*
- * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore,
- * verify that UUID and MD5 sum match in size, because we rely on that.
- */
-verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
-
-
-
-static int
-esxStoragePoolLookupType(esxVI_Context *ctx, const char *poolName,
- int *poolType)
-{
- int result = -1;
- esxVI_String *propertyNameList = NULL;
- esxVI_ObjectContent *datastore = NULL;
- esxVI_DynamicProperty *dynamicProperty = NULL;
- esxVI_DatastoreInfo *datastoreInfo = NULL;
-
- if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
- esxVI_LookupDatastoreByName(ctx, poolName, propertyNameList, &datastore,
- esxVI_Occurrence_RequiredItem) < 0) {
- goto cleanup;
- }
-
- for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
- dynamicProperty = dynamicProperty->_next) {
- if (STREQ(dynamicProperty->name, "info")) {
- if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
- &datastoreInfo) < 0) {
- goto cleanup;
- }
-
- break;
- }
- }
-
- if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- *poolType = VIR_STORAGE_POOL_DIR;
- } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- *poolType = VIR_STORAGE_POOL_NETFS;
- } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- *poolType = VIR_STORAGE_POOL_FS;
- } else {
- 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;
-}
-
+/**
+* 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.
+*/
+enum {
+ VMFS = 0,
+ LAST_DRIVER
+};
+static virStorageDriverPtr backendDrv[] = {
+ &esxStorageBackendVMFSDrv
+};
static virDrvOpenStatus
esxStorageOpen(virConnectPtr conn,
@@ -132,27 +80,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 +111,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 +145,8 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
count = -1;
}
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastoreList);
-
return count;
+
}
@@ -252,43 +175,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 +208,36 @@ 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;
+ char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+ 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) {
+ /* invoke backend drive method to search all known pools */
+ for (i = 0; i < LAST_DRIVER; ++i) {
+ pool = backendDrv[i]->poolLookupByUUID(conn, uuid);
+ if (pool != NULL) {
break;
}
}
- if (datastore == NULL) {
+ if (pool == 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;
+ _("Could not find storage pool with uuid '%s'"),
+ uuid_string);
}
- pool = virGetStoragePool(conn, name, uuid);
-
- cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastoreList);
- esxVI_DatastoreHostMount_Free(&hostMount);
+cleanup:
return pool;
+
}
@@ -373,26 +255,26 @@ esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
{
int result = -1;
esxPrivate *priv = pool->conn->storagePrivateData;
- esxVI_ObjectContent *datastore = NULL;
+ virStorageDriverPtr backendDrvPtr = NULL;
- virCheckFlags(0, -1);
+ virCheckNonNullArgGoto(pool->privateData, cleanup);
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) {
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
+
+ if (backendDrvPtr->poolRefresh(pool, flags) < 0) {
goto cleanup;
}
result = 0;
cleanup:
- esxVI_ObjectContent_Free(&datastore);
return result;
+
}
@@ -402,63 +284,28 @@ 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 backendDrvPtr = NULL;
+
+ virCheckNonNullArgGoto(pool->privateData, cleanup);
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;
- }
- }
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
- info->allocation = info->capacity - info->available;
- } else {
- info->state = VIR_STORAGE_POOL_INACCESSIBLE;
+ if (backendDrvPtr->poolGetInfo(pool, info) < 0) {
+ goto cleanup;
}
result = 0;
cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastore);
return result;
+
}
@@ -466,123 +313,23 @@ 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;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ virStorageDriverPtr backendDrvPtr = NULL;
- virCheckFlags(0, NULL);
-
- memset(&def, 0, sizeof(def));
+ virCheckNonNullArgGoto(pool->privateData, cleanup);
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"));
goto cleanup;
}
- xml = virStoragePoolDefFormat(&def);
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
+ xml = backendDrvPtr->poolGetXMLDesc(pool, flags);
cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastore);
- esxVI_DatastoreHostMount_Free(&hostMount);
- esxVI_DatastoreInfo_Free(&info);
return xml;
+
}
@@ -622,33 +369,24 @@ esxStoragePoolNumberOfStorageVolumes(virStoragePoolPtr pool)
{
bool success = false;
esxPrivate *priv = pool->conn->storagePrivateData;
- esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
- esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
- esxVI_FileInfo *fileInfo = NULL;
+ virStorageDriverPtr backendDrvPtr = NULL;
int count = 0;
- if (esxVI_EnsureSession(priv->primary) < 0) {
- return -1;
- }
+ virCheckNonNullArgGoto(pool->privateData, cleanup);
- if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
- &searchResultsList) < 0) {
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- /* Interpret search result */
- for (searchResults = searchResultsList; searchResults != NULL;
- searchResults = searchResults->_next) {
- for (fileInfo = searchResults->file; fileInfo != NULL;
- fileInfo = fileInfo->_next) {
- ++count;
- }
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
+ count = backendDrvPtr->poolNumOfVolumes(pool);
+ if (count < 0) {
+ goto cleanup;
}
success = true;
cleanup:
- esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
return success ? count : -1;
}
@@ -659,87 +397,28 @@ 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;
- }
+ virStorageDriverPtr backendDrvPtr = NULL;
- if (maxnames == 0) {
- return 0;
- }
+ virCheckNonNullArgGoto(pool->privateData, cleanup);
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;
- }
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
- /* 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 (backendDrvPtr->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 +428,22 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name)
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->storagePrivateData;
- char *datastorePath = NULL;
- char *key = NULL;
-
- if (esxVI_EnsureSession(priv->primary) < 0) {
- return NULL;
- }
+ virStorageDriverPtr backendDrvPtr = NULL;
- if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) {
- virReportOOMError();
- goto cleanup;
- }
+ virCheckNonNullArgGoto(name, cleanup);
+ virCheckNonNullArgGoto(pool->privateData, cleanup);
- if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary,
- datastorePath, &key) < 0) {
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- volume = virGetStorageVol(pool->conn, pool->name, name, key);
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
+ volume = backendDrvPtr->volLookupByName(pool, name);
cleanup:
- VIR_FREE(datastorePath);
- VIR_FREE(key);
return volume;
+
}
@@ -782,32 +453,30 @@ 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
+ */
+ if (STRPREFIX(path, "[")) {
+ volume = backendDrv[VMFS]->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 +486,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 +519,22 @@ 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);
-
- 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;
- }
- }
+ virStorageDriverPtr backendDrvPtr = NULL;
- /* 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;
- }
+ virCheckNonNullArgGoto(xmldesc, cleanup);
+ virCheckNonNullArgGoto(pool->privateData, 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));
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
+ volume = backendDrvPtr->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 +545,22 @@ 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, '/');
-
- 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;
- }
+ virStorageDriverPtr backendDrvPtr = NULL;
- if (def->target.format == VIR_STORAGE_FILE_VMDK) {
- /* Parse and escape datastore path */
- if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
- &unescapedDirectoryName,
- &unescapedDirectoryAndFileName) < 0) {
- goto cleanup;
- }
+ virCheckNonNullArgGoto(xmldesc, cleanup);
+ virCheckNonNullArgGoto(pool->privateData, 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));
+ if (esxVI_EnsureSession(priv->primary) < 0) {
goto cleanup;
}
- volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+ backendDrvPtr = (virStorageDriverPtr) pool->privateData;
+ volume = backendDrvPtr->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 +568,27 @@ esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
static int
esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags)
{
- int result = -1;
+ int err = -1;
esxPrivate *priv = volume->conn->storagePrivateData;
- char *datastorePath = NULL;
- esxVI_ManagedObjectReference *task = NULL;
- esxVI_TaskInfoState taskInfoState;
- char *taskInfoErrorMessage = NULL;
+ virStorageDriverPtr backendDrvPtr = NULL;
- virCheckFlags(0, -1);
+ virCheckNonNullArgGoto(volume->privateData, cleanup);
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) {
+ backendDrvPtr = (virStorageDriverPtr) volume->privateData;
+ if (backendDrvPtr->volDelete(volume , flags) < 0) {
goto cleanup;
}
- if (taskInfoState != esxVI_TaskInfoState_Success) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not delete volume: %s"),
- taskInfoErrorMessage);
- goto cleanup;
- }
+ err = 0;
- result = 0;
+cleanup:
- cleanup:
- VIR_FREE(datastorePath);
- esxVI_ManagedObjectReference_Free(&task);
- VIR_FREE(taskInfoErrorMessage);
+ return err;
- return result;
}
@@ -1432,97 +596,54 @@ esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags)
static int
esxStorageVolumeWipe(virStorageVolPtr volume, unsigned int flags)
{
- int result = -1;
+ int err = -1;
esxPrivate *priv = volume->conn->storagePrivateData;
- char *datastorePath = NULL;
- esxVI_ManagedObjectReference *task = NULL;
- esxVI_TaskInfoState taskInfoState;
- char *taskInfoErrorMessage = NULL;
+ virStorageDriverPtr backendDrvPtr = NULL;
- virCheckFlags(0, -1);
+ virCheckNonNullArgGoto(volume->privateData, cleanup);
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) {
+ backendDrvPtr = (virStorageDriverPtr) volume->privateData;
+ if (backendDrvPtr->volWipe(volume , flags) < 0) {
goto cleanup;
}
- if (taskInfoState != esxVI_TaskInfoState_Success) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not wipe volume: %s"),
- taskInfoErrorMessage);
- goto cleanup;
- }
+ err = 0;
- result = 0;
+ cleanup:
- cleanup:
- VIR_FREE(datastorePath);
- esxVI_ManagedObjectReference_Free(&task);
- VIR_FREE(taskInfoErrorMessage);
+ return err;
- return result;
}
-
static int
esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
{
- int result = -1;
+ int err = -1;
esxPrivate *priv = volume->conn->storagePrivateData;
- char *datastorePath = NULL;
- esxVI_FileInfo *fileInfo = NULL;
- esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
+ virStorageDriverPtr backendDrvPtr = NULL;
- memset(info, 0, sizeof(*info));
+ virCheckNonNullArgGoto(volume->privateData, cleanup);
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) {
+ backendDrvPtr = (virStorageDriverPtr) volume->privateData;
+ if (backendDrvPtr->volGetInfo(volume , info) < 0) {
goto cleanup;
}
- vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
+ err = 0;
- info->type = VIR_STORAGE_VOL_FILE;
+ cleanup:
- if (vmDiskFileInfo != NULL) {
- info->capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */
- info->allocation = vmDiskFileInfo->fileSize->value;
- } else {
- info->capacity = fileInfo->fileSize->value;
- info->allocation = fileInfo->fileSize->value;
- }
-
- result = 0;
-
- cleanup:
- VIR_FREE(datastorePath);
- esxVI_FileInfo_Free(&fileInfo);
+ return err;
- return result;
}
@@ -1530,84 +651,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;
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ virStorageDriverPtr backendDrvPtr = NULL;
- virCheckFlags(0, NULL);
-
- memset(&pool, 0, sizeof(pool));
- memset(&def, 0, sizeof(def));
+ virCheckNonNullArgGoto(volume->privateData, cleanup);
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;
- }
+ backendDrvPtr = (virStorageDriverPtr) volume->privateData;
- vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
- isoImageFileInfo = esxVI_IsoImageFileInfo_DynamicCast(fileInfo);
- floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo);
+ xml = backendDrvPtr->volGetXMLDesc(volume, flags);
- 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);
+ cleanup:
return xml;
+
}
@@ -1615,14 +676,24 @@ esxStorageVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
static char *
esxStorageVolumeGetPath(virStorageVolPtr volume)
{
- char *path;
+ char *path = NULL;
+ esxPrivate *priv = volume->conn->storagePrivateData;
+ virStorageDriverPtr backendDrvPtr = NULL;
- if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) {
- virReportOOMError();
- return NULL;
+ virCheckNonNullArgGoto(volume->privateData, cleanup);
+
+ if (esxVI_EnsureSession(priv->primary) < 0) {
+ goto cleanup;
}
+ backendDrvPtr = (virStorageDriverPtr) volume->privateData;
+
+ path = backendDrvPtr->volGetPath(volume);
+
+ cleanup:
+
return path;
+
}
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index f3224f8..9fb2c11 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -3107,7 +3107,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;
@@ -3155,7 +3156,7 @@ esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
break;
}
- if (*hostMount == NULL) {
+ if (*hostMount == NULL && occurrence == esxVI_Occurrence_RequiredItem) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not lookup datastore host mount"));
goto cleanup;
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index a9c12c8..d7895a0 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -441,7 +441,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,
diff --git a/src/parallels/parallels_storage.c b/src/parallels/parallels_storage.c
index 71f3f89..8d4e2c6 100644
--- a/src/parallels/parallels_storage.c
+++ b/src/parallels/parallels_storage.c
@@ -350,7 +350,8 @@ parallelsStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
if (pool)
@@ -374,7 +375,8 @@ parallelsStoragePoolLookupByName(virConnectPtr conn, const char *name)
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
if (pool)
@@ -459,7 +461,8 @@ parallelsStoragePoolDefine(virConnectPtr conn,
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
virStoragePoolDefFree(def);
@@ -831,7 +834,8 @@ parallelsStorageVolumeLookupByName(virStoragePoolPtr pool,
}
ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
cleanup:
if (privpool)
@@ -857,7 +861,8 @@ parallelsStorageVolumeLookupByKey(virConnectPtr conn, const char *key)
if (privvol) {
ret = virGetStorageVol(conn,
privconn->pools.objs[i]->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
virStoragePoolObjUnlock(privconn->pools.objs[i]);
break;
}
@@ -889,7 +894,8 @@ parallelsStorageVolumeLookupByPathLocked(virConnectPtr conn, const char *path)
if (privvol) {
ret = virGetStorageVol(conn,
privconn->pools.objs[i]->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
virStoragePoolObjUnlock(privconn->pools.objs[i]);
break;
}
@@ -1026,7 +1032,8 @@ parallelsStorageVolumeCreateXML(virStoragePoolPtr pool,
goto cleanup;
ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
cleanup:
if (privpool)
virStoragePoolObjUnlock(privpool);
@@ -1115,7 +1122,8 @@ parallelsStorageVolumeCreateXMLFrom(virStoragePoolPtr pool,
privpool->volumes.objs[privpool->volumes.count++] = privvol;
ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
privvol = NULL;
cleanup:
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 62b7729..ec33698 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -5863,13 +5863,15 @@ get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface)
static virStoragePoolPtr
get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool)
{
- return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid);
+ return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid,
+ NULL, NULL);
}
static virStorageVolPtr
get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol)
{
- return virGetStorageVol(conn, vol.pool, vol.name, vol.key);
+ return virGetStorageVol(conn, vol.pool, vol.name, vol.key,
+ NULL, NULL);
}
static virNodeDevicePtr
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index faca2a2..2e33b80 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -273,7 +273,8 @@ storagePoolLookupByUUID(virConnectPtr conn,
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
if (pool)
@@ -298,7 +299,8 @@ storagePoolLookupByName(virConnectPtr conn,
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
if (pool)
@@ -555,7 +557,8 @@ storagePoolCreate(virConnectPtr conn,
VIR_INFO("Creating storage pool '%s'", pool->def->name);
pool->active = 1;
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
virStoragePoolDefFree(def);
@@ -601,7 +604,8 @@ storagePoolDefine(virConnectPtr conn,
def = NULL;
VIR_INFO("Defining storage pool '%s'", pool->def->name);
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
virStoragePoolDefFree(def);
@@ -1202,7 +1206,8 @@ storagePoolListAllVolumes(virStoragePoolPtr pool,
for (i = 0 ; i < obj->volumes.count; i++) {
if (!(vol = virGetStorageVol(pool->conn, obj->def->name,
obj->volumes.objs[i]->name,
- obj->volumes.objs[i]->key)))
+ obj->volumes.objs[i]->key,
+ NULL, NULL)))
goto cleanup;
tmp_vols[nvols++] = vol;
}
@@ -1258,7 +1263,8 @@ storageVolumeLookupByName(virStoragePoolPtr obj,
goto cleanup;
}
- ret = virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key);
+ ret = virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key,
+ NULL, NULL);
cleanup:
if (pool)
@@ -1285,7 +1291,8 @@ storageVolumeLookupByKey(virConnectPtr conn,
ret = virGetStorageVol(conn,
driver->pools.objs[i]->def->name,
vol->name,
- vol->key);
+ vol->key,
+ NULL, NULL);
}
virStoragePoolObjUnlock(driver->pools.objs[i]);
}
@@ -1338,7 +1345,8 @@ storageVolumeLookupByPath(virConnectPtr conn,
ret = virGetStorageVol(conn,
driver->pools.objs[i]->def->name,
vol->name,
- vol->key);
+ vol->key,
+ NULL, NULL);
}
virStoragePoolObjUnlock(driver->pools.objs[i]);
}
@@ -1415,7 +1423,7 @@ storageVolumeCreateXML(virStoragePoolPtr obj,
pool->volumes.objs[pool->volumes.count++] = voldef;
volobj = virGetStorageVol(obj->conn, pool->def->name, voldef->name,
- voldef->key);
+ voldef->key, NULL, NULL);
if (!volobj) {
pool->volumes.count--;
goto cleanup;
@@ -1587,7 +1595,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
pool->volumes.objs[pool->volumes.count++] = newvol;
volobj = virGetStorageVol(obj->conn, pool->def->name, newvol->name,
- newvol->key);
+ newvol->key, NULL, NULL);
/* Drop the pool lock during volume allocation */
pool->asyncjobs++;
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 9e4d9f2..6ca59e2 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -3885,7 +3885,8 @@ testStoragePoolLookupByUUID(virConnectPtr conn,
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
if (pool)
@@ -3909,7 +3910,8 @@ testStoragePoolLookupByName(virConnectPtr conn,
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
if (pool)
@@ -4201,7 +4203,8 @@ testStoragePoolCreate(virConnectPtr conn,
}
pool->active = 1;
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
virStoragePoolDefFree(def);
@@ -4241,7 +4244,8 @@ testStoragePoolDefine(virConnectPtr conn,
goto cleanup;
}
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
cleanup:
virStoragePoolDefFree(def);
@@ -4668,7 +4672,8 @@ testStoragePoolListAllVolumes(virStoragePoolPtr obj,
for (i = 0 ; i < pool->volumes.count; i++) {
if (!(vol = virGetStorageVol(obj->conn, pool->def->name,
pool->volumes.objs[i]->name,
- pool->volumes.objs[i]->key)))
+ pool->volumes.objs[i]->key,
+ NULL, NULL)))
goto cleanup;
tmp_vols[nvols++] = vol;
}
@@ -4725,7 +4730,8 @@ testStorageVolumeLookupByName(virStoragePoolPtr pool,
}
ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
cleanup:
if (privpool)
@@ -4752,7 +4758,8 @@ testStorageVolumeLookupByKey(virConnectPtr conn,
ret = virGetStorageVol(conn,
privconn->pools.objs[i]->def->name,
privvol->name,
- privvol->key);
+ privvol->key,
+ NULL, NULL);
virStoragePoolObjUnlock(privconn->pools.objs[i]);
break;
}
@@ -4786,7 +4793,8 @@ testStorageVolumeLookupByPath(virConnectPtr conn,
ret = virGetStorageVol(conn,
privconn->pools.objs[i]->def->name,
privvol->name,
- privvol->key);
+ privvol->key,
+ NULL, NULL);
virStoragePoolObjUnlock(privconn->pools.objs[i]);
break;
}
@@ -4875,7 +4883,8 @@ testStorageVolumeCreateXML(virStoragePoolPtr pool,
privpool->volumes.objs[privpool->volumes.count++] = privvol;
ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
privvol = NULL;
cleanup:
@@ -4969,7 +4978,8 @@ testStorageVolumeCreateXMLFrom(virStoragePoolPtr pool,
privpool->volumes.objs[privpool->volumes.count++] = privvol;
ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key);
+ privvol->name, privvol->key,
+ NULL, NULL);
privvol = NULL;
cleanup:
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index bcffb2f..f9fa442 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -8321,7 +8321,7 @@ static virStoragePoolPtr vboxStoragePoolLookupByName(virConnectPtr conn, const c
ignore_value(virUUIDParse(uuidstr, uuid));
- ret = virGetStoragePool(conn, name, uuid);
+ ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
}
return ret;
@@ -8450,7 +8450,8 @@ static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const
vboxIIDToUUID(&hddIID, uuid);
virUUIDFormat(uuid, key);
- ret = virGetStorageVol(pool->conn, pool->name, name, key);
+ ret = virGetStorageVol(pool->conn, pool->name, name, key,
+ NULL, NULL);
VIR_DEBUG("virStorageVolPtr: %p", ret);
VIR_DEBUG("Storage Volume Name: %s", name);
@@ -8511,7 +8512,8 @@ static virStorageVolPtr vboxStorageVolLookupByKey(virConnectPtr conn, const char
if (hddNameUtf8) {
if (vboxStorageNumOfPools(conn) == 1) {
- ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key);
+ ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
+ NULL, NULL);
VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
} else {
/* TODO: currently only one default pool and thus
@@ -8583,7 +8585,8 @@ static virStorageVolPtr vboxStorageVolLookupByPath(virConnectPtr conn, const cha
* the check below, change it when pools are supported
*/
if (vboxStorageNumOfPools(conn) == 1)
- ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key);
+ ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
+ NULL, NULL);
VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
@@ -8683,7 +8686,8 @@ static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
vboxIIDToUUID(&hddIID, uuid);
virUUIDFormat(uuid, key);
- ret = virGetStorageVol(pool->conn, pool->name, def->name, key);
+ ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
+ NULL, NULL);
}
vboxIIDUnalloc(&hddIID);
--
1.7.9.5
11 years, 12 months
[libvirt] Proposal: no dnsmasq (no dhcp and no dns) and no radvd option
by Gene Czarcinski
Laine mentioned something yesterday that got me to thinking: being able
to specify that dnsmasq is not to be started for an interface.
Let me expand that by saying that libvirt would not start dnsmasq for
either dns or dhcp and also would not start radvd. However, the IPv4
and IPv6 gateway addresses would be defined on the virtual network
interface and the "usual" iptables and ip6tables rules would be in force.
This would allow a user to configure dnsmasq to meet any user desires or
use something completely different instead of dnsmasq.
Questions: Useful? Worth the time and effort? And then there is how
should this be specified in the network xml file? ... some new
parameter? ... A subperameter of <dns> such as <dns disable='yes' /> ?
... a subparameter of <bridge> such as <bridge name="virbr0"
dns="disable" /> ?
Comments? Suggestions?
Gene
11 years, 12 months
[libvirt] Is DBus a hard dependency
by Guido Günther
Hi,
currently running libvirtd without DBus fails due to:
error : nwfilterDriverStartup:208 : DBus matches could not be installed. Disabling nwfilter driver
error : virDBusGetSystemBus:77 : internal error Unable to get DBus system bus connection: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory
error : virStateInitialize:810 : Initialization of NWFilter state driver failed
error : daemonRunStateInit:784 : Driver state initialization failed
because we fail driver initialization hard in nwfilter_driver.c:
if (nwfilterDriverInstallDBusMatches(sysbus) < 0) {
VIR_ERROR(_("DBus matches could not be installed. Disabling nwfilter "
"driver"));
/*
* unfortunately this is fatal since virNWFilterTechDriversInit
* may have caused the ebiptables driver to use the firewall tool
* but now that the watches don't work, we just disable the nwfilter
* driver
*/
goto error;
}
I wonder if this on prupose or if we can just make this a soft error and
go on without DBus? At least in the !HAVE_FIREWALLD case it should be
o.k. to continue. Shouldn't it? See attached patch.
Cheers,
-- Guido
11 years, 12 months
[libvirt] [PATCH] Add detailed error information to journal
by Miloslav Trmač
When logging an error, don't throw away the detailed information.
Example record when using the journald output:
MESSAGE=Domain not found
PRIORITY=4
LIBVIRT_SOURCE=error
CODE_FILE=../../src/test/test_driver.c
CODE_LINE=1406
CODE_FUNC=testLookupDomainByName
DOMAIN=12
CODE=42
The format used in other output destinations (e.g. "syslog", "file") is
still unchanged.
The "domain" and "code" numbers are part of the libvirt ABI in
<libvirt/virterror.h>; therefore log processing tools can rely on them,
unlike the text log string (which is translated depending on locale,
and may be modified for other reasons as well).
Alternatively, the "domain" and "code" fields could contain strings
instead of numbers, but it's not clear that it's worth it:
Advantages of numbers:
* the numbers are shorter
* the ABI guarantees that the numbers won't change
Disadvantages of strings:
* adding a ABI-stable string mapping for virErrorNumber would result
in additional work each time a new error number is added
(note that virErrorMsg cannot be used for this because it is
translated)
* a change in the string mapping would be less likely to be noticed
The advantage of using strings is more readability, but note that the
"msg" field above already contains a readable description of the
error.
The inability to allocate memory imposes a fixed limit on the number
of metadata fields that can be supported by the journal; fields beyond
this limit are silently dropped (but the initial part of the message
sent). This was implemented in the previous patch, here we just
increase the limit to 32 fields total.
Signed-off-by: Miloslav Trmač <mitr(a)redhat.com>
---
This version drops logging the str[123] and int[12] fields.
The META_ADD_STRING macro is unused; it was left there just to
demonstrate the use of the API in case someone wanted to add more
error-specific information.
---
src/util/logging.c | 13 +++++++++++--
src/util/virterror.c | 23 ++++++++++++++++++++++-
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/src/util/logging.c b/src/util/logging.c
index e8fed55..dbffaa1 100644
--- a/src/util/logging.c
+++ b/src/util/logging.c
@@ -1125,7 +1125,7 @@ virLogOutputToJournald(virLogSource source,
int linenr,
const char *funcname,
const char *timestamp ATTRIBUTE_UNUSED,
- virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
+ virLogMetadataPtr metadata,
unsigned int flags,
const char *rawstr,
const char *str ATTRIBUTE_UNUSED,
@@ -1145,7 +1145,7 @@ virLogOutputToJournald(virLogSource source,
* and where unprivileged users can create files. */
char path[] = "/dev/shm/journal.XXXXXX";
-# define NUM_FIELDS 6
+# define NUM_FIELDS 32
struct iovec iov[NUM_FIELDS * 5];
char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
struct journalState state;
@@ -1162,6 +1162,15 @@ virLogOutputToJournald(virLogSource source,
journalAddString(&state, "CODE_FILE", filename);
journalAddInt(&state, "CODE_LINE", linenr);
journalAddString(&state, "CODE_FUNC", funcname);
+ if (metadata != NULL) {
+ while (metadata->key != NULL) {
+ if (metadata->s != NULL)
+ journalAddString(&state, metadata->key, metadata->s);
+ else
+ journalAddInt(&state, metadata->key, metadata->i);
+ metadata++;
+ }
+ }
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 213188e..10b627f 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -619,6 +619,8 @@ virRaiseErrorFull(const char *filename ATTRIBUTE_UNUSED,
virErrorPtr to;
char *str;
int priority;
+ virLogMetadata meta[3];
+ size_t i;
/*
* All errors are recorded in thread local storage
@@ -676,10 +678,29 @@ virRaiseErrorFull(const char *filename ATTRIBUTE_UNUSED,
priority = virErrorLevelPriority(level);
if (virErrorLogPriorityFilter)
priority = virErrorLogPriorityFilter(to, priority);
+
+ i = 0;
+#define META_ADD_STRING(KEY, VALUE) \
+ do { \
+ meta[i].key = (KEY); \
+ meta[i].s = (VALUE); \
+ i++; \
+ } while (0)
+#define META_ADD_INT(KEY, VALUE) \
+ do { \
+ meta[i].key = (KEY); \
+ meta[i].s = NULL; \
+ meta[i].i = (VALUE); \
+ i++; \
+ } while (0)
+
+ META_ADD_INT("DOMAIN", domain);
+ META_ADD_INT("CODE", code);
+ meta[i].key = NULL;
virLogMessage(virErrorLogPriorityFilter ? VIR_LOG_FROM_FILE : VIR_LOG_FROM_ERROR,
priority,
filename, linenr, funcname,
- NULL, "%s", str);
+ meta, "%s", str);
errno = save_errno;
}
--
1.7.11.7
12 years