[libvirt] [PATCH] test driver: File test_driver.c was splitted into smaller files.
by Tomáš Ryšavý
Because the file had over 7000 lines. Now its splitted into 5
smaller files. It looks clearer and it's better for reading the code.
Signed-off-by: Tomáš Ryšavý <tom.rysavy.0(a)gmail.com>
---
po/POTFILES.in | 6 +-
src/Makefile.am | 8 +-
src/test/test_device_driver.c | 462 +++
src/test/test_device_driver.h | 1 +
src/test/test_driver.c | 6924 +------------------------------------
src/test/test_hypervisor_driver.c | 4152 ++++++++++++++++++++++
src/test/test_hypervisor_driver.h | 1 +
src/test/test_interface_driver.c | 487 +++
src/test/test_interface_driver.h | 1 +
src/test/test_network_driver.c | 540 +++
src/test/test_network_driver.h | 1 +
src/test/test_private_driver.h | 70 +
src/test/test_storage_driver.c | 1517 ++++++++
src/test/test_storage_driver.h | 1 +
14 files changed, 7259 insertions(+), 6912 deletions(-)
create mode 100644 src/test/test_device_driver.c
create mode 100644 src/test/test_device_driver.h
create mode 100644 src/test/test_hypervisor_driver.c
create mode 100644 src/test/test_hypervisor_driver.h
create mode 100644 src/test/test_interface_driver.c
create mode 100644 src/test/test_interface_driver.h
create mode 100644 src/test/test_network_driver.c
create mode 100644 src/test/test_network_driver.h
create mode 100644 src/test/test_private_driver.h
create mode 100644 src/test/test_storage_driver.c
create mode 100644 src/test/test_storage_driver.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 25dbc84..5738c4e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -173,7 +173,11 @@ src/storage/storage_backend_scsi.c
src/storage/storage_backend_sheepdog.c
src/storage/storage_backend_zfs.c
src/storage/storage_driver.c
-src/test/test_driver.c
+src/test/test_device_driver.c
+src/test/test_hypervisor_driver.c
+src/test/test_interface_driver.c
+src/test/test_network_driver.c
+src/test/test_storage_driver.c
src/uml/uml_conf.c
src/uml/uml_driver.c
src/util/iohelper.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8ee5567..4cf01fd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -689,7 +689,13 @@ check-local: check-protocol check-symfile check-symsorting \
# Mock driver, covering domains, storage, networks, etc
TEST_DRIVER_SOURCES = \
- test/test_driver.c test/test_driver.h
+ test/test_driver.c test/test_driver.h \
+ test/test_device_driver.c test/test_device_driver.h \
+ test/test_hypervisor_driver.c test/test_hypervisor_driver.h \
+ test/test_interface_driver.c test/test_interface_driver.h \
+ test/test_network_driver.c test/test_network_driver.h \
+ test/test_storage_driver.c test/test_storage_driver.h
+
# Now the Hypervisor specific drivers
XEN_DRIVER_SOURCES = \
diff --git a/src/test/test_device_driver.c b/src/test/test_device_driver.c
new file mode 100644
index 0000000..1172bc5
--- /dev/null
+++ b/src/test/test_device_driver.c
@@ -0,0 +1,462 @@
+/*
+ * test_device_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_device_driver.h"
+
+#include "test_private_driver.h"
+
+/* Node device implementations */
+
+static int
+testConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
+ virNodeDevicePtr dev,
+ int eventID,
+ virConnectNodeDeviceEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virNodeDeviceEventStateRegisterID(conn, driver->eventState,
+ dev, eventID, callback,
+ opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testNodeNumOfDevices(virConnectPtr conn,
+ const char *cap,
+ unsigned int flags)
+{
+ testDriverPtr driver = conn->privateData;
+ int ndevs = 0;
+ size_t i;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(driver);
+ for (i = 0; i < driver->devs.count; i++)
+ if ((cap == NULL) ||
+ virNodeDeviceHasCap(driver->devs.objs[i], cap))
+ ++ndevs;
+ testDriverUnlock(driver);
+
+ return ndevs;
+}
+
+static int
+testNodeListDevices(virConnectPtr conn,
+ const char *cap,
+ char **const names,
+ int maxnames,
+ unsigned int flags)
+{
+ testDriverPtr driver = conn->privateData;
+ int ndevs = 0;
+ size_t i;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(driver);
+ for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) {
+ virNodeDeviceObjLock(driver->devs.objs[i]);
+ if (cap == NULL ||
+ virNodeDeviceHasCap(driver->devs.objs[i], cap)) {
+ if (VIR_STRDUP(names[ndevs++], driver->devs.objs[i]->def->name) < 0) {
+ virNodeDeviceObjUnlock(driver->devs.objs[i]);
+ goto failure;
+ }
+ }
+ virNodeDeviceObjUnlock(driver->devs.objs[i]);
+ }
+ testDriverUnlock(driver);
+
+ return ndevs;
+
+ failure:
+ testDriverUnlock(driver);
+ --ndevs;
+ while (--ndevs >= 0)
+ VIR_FREE(names[ndevs]);
+ return -1;
+}
+
+static virNodeDevicePtr
+testNodeDeviceLookupByName(virConnectPtr conn, const char *name)
+{
+ testDriverPtr driver = conn->privateData;
+ virNodeDeviceObjPtr obj;
+ virNodeDevicePtr ret = NULL;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ name);
+ goto cleanup;
+ }
+
+ ret = virGetNodeDevice(conn, name);
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+static char *
+testNodeDeviceGetXMLDesc(virNodeDevicePtr dev,
+ unsigned int flags)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ ret = virNodeDeviceDefFormat(obj->def);
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+static char *
+testNodeDeviceGetParent(virNodeDevicePtr dev)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ char *ret = NULL;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ if (obj->def->parent) {
+ ignore_value(VIR_STRDUP(ret, obj->def->parent));
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no parent for this device"));
+ }
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+
+static int
+testNodeDeviceNumOfCaps(virNodeDevicePtr dev)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ virNodeDevCapsDefPtr caps;
+ int ncaps = 0;
+ int ret = -1;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ for (caps = obj->def->caps; caps; caps = caps->next)
+ ++ncaps;
+ ret = ncaps;
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+
+static int
+testNodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ virNodeDevCapsDefPtr caps;
+ int ncaps = 0;
+ int ret = -1;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) {
+ if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps->data.type)) < 0)
+ goto cleanup;
+ }
+ ret = ncaps;
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ if (ret == -1) {
+ --ncaps;
+ while (--ncaps >= 0)
+ VIR_FREE(names[ncaps]);
+ }
+ return ret;
+}
+
+static virNodeDevicePtr
+testNodeDeviceCreateXML(virConnectPtr conn,
+ const char *xmlDesc,
+ unsigned int flags)
+{
+ testDriverPtr driver = conn->privateData;
+ virNodeDeviceDefPtr def = NULL;
+ virNodeDeviceObjPtr obj = NULL;
+ char *wwnn = NULL, *wwpn = NULL;
+ int parent_host = -1;
+ virNodeDevicePtr dev = NULL;
+ virNodeDevCapsDefPtr caps;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(driver);
+
+ def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, NULL);
+ if (def == NULL)
+ goto cleanup;
+
+ /* We run these next two simply for validation */
+ if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1)
+ goto cleanup;
+
+ if (virNodeDeviceGetParentHost(&driver->devs,
+ def->name,
+ def->parent,
+ &parent_host) == -1) {
+ goto cleanup;
+ }
+
+ /* 'name' is supposed to be filled in by the node device backend, which
+ * we don't have. Use WWPN instead. */
+ VIR_FREE(def->name);
+ if (VIR_STRDUP(def->name, wwpn) < 0)
+ goto cleanup;
+
+ /* Fill in a random 'host' and 'unique_id' value,
+ * since this would also come from the backend */
+ caps = def->caps;
+ while (caps) {
+ if (caps->data.type != VIR_NODE_DEV_CAP_SCSI_HOST)
+ continue;
+
+ caps->data.scsi_host.host = virRandomBits(10);
+ caps->data.scsi_host.unique_id = 2;
+ caps = caps->next;
+ }
+
+
+ if (!(obj = virNodeDeviceAssignDef(&driver->devs, def)))
+ goto cleanup;
+ virNodeDeviceObjUnlock(obj);
+
+ event = virNodeDeviceEventLifecycleNew(def->name,
+ VIR_NODE_DEVICE_EVENT_CREATED,
+ 0);
+
+ dev = virGetNodeDevice(conn, def->name);
+ def = NULL;
+ cleanup:
+ testDriverUnlock(driver);
+ virNodeDeviceDefFree(def);
+ testObjectEventQueue(driver, event);
+ VIR_FREE(wwnn);
+ VIR_FREE(wwpn);
+ return dev;
+}
+
+static int
+testNodeDeviceDestroy(virNodeDevicePtr dev)
+{
+ int ret = 0;
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj = NULL;
+ char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
+ int parent_host = -1;
+ virObjectEventPtr event = NULL;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto out;
+ }
+
+ if (virNodeDeviceGetWWNs(obj->def, &wwnn, &wwpn) == -1)
+ goto out;
+
+ if (VIR_STRDUP(parent_name, obj->def->parent) < 0)
+ goto out;
+
+ /* virNodeDeviceGetParentHost will cause the device object's lock to be
+ * taken, so we have to dup the parent's name and drop the lock
+ * before calling it. We don't need the reference to the object
+ * any more once we have the parent's name. */
+ virNodeDeviceObjUnlock(obj);
+
+ /* We do this just for basic validation */
+ if (virNodeDeviceGetParentHost(&driver->devs,
+ dev->name,
+ parent_name,
+ &parent_host) == -1) {
+ obj = NULL;
+ goto out;
+ }
+
+ event = virNodeDeviceEventLifecycleNew(dev->name,
+ VIR_NODE_DEVICE_EVENT_DELETED,
+ 0);
+
+ virNodeDeviceObjLock(obj);
+ virNodeDeviceObjRemove(&driver->devs, &obj);
+
+ out:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ testObjectEventQueue(driver, event);
+ VIR_FREE(parent_name);
+ VIR_FREE(wwnn);
+ VIR_FREE(wwpn);
+ return ret;
+}
+
+virNodeDeviceDriver testNodeDeviceDriver = {
+ .connectNodeDeviceEventRegisterAny = testConnectNodeDeviceEventRegisterAny, /* 2.2.0 */
+ .connectNodeDeviceEventDeregisterAny = testConnectNodeDeviceEventDeregisterAny, /* 2.2.0 */
+ .nodeNumOfDevices = testNodeNumOfDevices, /* 0.7.2 */
+ .nodeListDevices = testNodeListDevices, /* 0.7.2 */
+ .nodeDeviceLookupByName = testNodeDeviceLookupByName, /* 0.7.2 */
+ .nodeDeviceGetXMLDesc = testNodeDeviceGetXMLDesc, /* 0.7.2 */
+ .nodeDeviceGetParent = testNodeDeviceGetParent, /* 0.7.2 */
+ .nodeDeviceNumOfCaps = testNodeDeviceNumOfCaps, /* 0.7.2 */
+ .nodeDeviceListCaps = testNodeDeviceListCaps, /* 0.7.2 */
+ .nodeDeviceCreateXML = testNodeDeviceCreateXML, /* 0.7.3 */
+ .nodeDeviceDestroy = testNodeDeviceDestroy, /* 0.7.3 */
+};
diff --git a/src/test/test_device_driver.h b/src/test/test_device_driver.h
new file mode 100644
index 0000000..b5bd2bd
--- /dev/null
+++ b/src/test/test_device_driver.h
@@ -0,0 +1 @@
+extern virNodeDeviceDriver testNodeDeviceDriver;
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 87799e1..c30ae29 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -65,113 +65,28 @@
#include "virdomainobjlist.h"
#include "virhostcpu.h"
-#define VIR_FROM_THIS VIR_FROM_TEST
+#include "test_hypervisor_driver.h"
+#include "test_storage_driver.h"
+#include "test_network_driver.h"
+#include "test_interface_driver.h"
+#include "test_device_driver.h"
-VIR_LOG_INIT("test.test_driver");
-
-
-#define MAX_CPUS 128
-
-struct _testCell {
- unsigned long mem;
- unsigned long freeMem;
- int numCpus;
- virCapsHostNUMACellCPU cpus[MAX_CPUS];
-};
-typedef struct _testCell testCell;
-typedef struct _testCell *testCellPtr;
-
-#define MAX_CELLS 128
-
-struct _testAuth {
- char *username;
- char *password;
-};
-typedef struct _testAuth testAuth;
-typedef struct _testAuth *testAuthPtr;
-
-struct _testDriver {
- virMutex lock;
-
- virNodeInfo nodeInfo;
- virInterfaceObjList ifaces;
- bool transaction_running;
- virInterfaceObjList backupIfaces;
- virStoragePoolObjList pools;
- virNodeDeviceObjList devs;
- int numCells;
- testCell cells[MAX_CELLS];
- size_t numAuths;
- testAuthPtr auths;
-
- /* virAtomic access only */
- volatile int nextDomID;
-
- /* immutable pointer, immutable object after being initialized with
- * testBuildCapabilities */
- virCapsPtr caps;
-
- /* immutable pointer, immutable object */
- virDomainXMLOptionPtr xmlopt;
-
- /* immutable pointer, self-locking APIs */
- virDomainObjListPtr domains;
- virNetworkObjListPtr networks;
- virObjectEventStatePtr eventState;
-};
-typedef struct _testDriver testDriver;
-typedef testDriver *testDriverPtr;
-
-static testDriverPtr defaultConn;
-static int defaultConnections;
-static virMutex defaultLock = VIR_MUTEX_INITIALIZER;
+#include "test_private_driver.h"
-#define TEST_MODEL "i686"
-#define TEST_EMULATOR "/usr/bin/test-hv"
-
-static const virNodeInfo defaultNodeInfo = {
- TEST_MODEL,
- 1024*1024*3, /* 3 GB */
- 16,
- 1400,
- 2,
- 2,
- 2,
- 2,
-};
-
-static void
-testDriverFree(testDriverPtr driver)
-{
- if (!driver)
- return;
-
- virObjectUnref(driver->caps);
- virObjectUnref(driver->xmlopt);
- virObjectUnref(driver->domains);
- virNodeDeviceObjListFree(&driver->devs);
- virObjectUnref(driver->networks);
- virInterfaceObjListFree(&driver->ifaces);
- virStoragePoolObjListFree(&driver->pools);
- virObjectEventStateFree(driver->eventState);
- virMutexUnlock(&driver->lock);
- virMutexDestroy(&driver->lock);
-
- VIR_FREE(driver);
-}
+VIR_LOG_INIT("test.test_driver");
-static void testDriverLock(testDriverPtr driver)
+void testDriverLock(testDriverPtr driver)
{
virMutexLock(&driver->lock);
}
-static void testDriverUnlock(testDriverPtr driver)
+void testDriverUnlock(testDriverPtr driver)
{
virMutexUnlock(&driver->lock);
}
-static void testObjectEventQueue(testDriverPtr driver,
+void testObjectEventQueue(testDriverPtr driver,
virObjectEventPtr event)
{
if (!event)
@@ -180,6825 +95,14 @@ static void testObjectEventQueue(testDriverPtr driver,
virObjectEventStateQueue(driver->eventState, event);
}
-#define TEST_NAMESPACE_HREF "http://libvirt.org/schemas/domain/test/1.0"
-
-typedef struct _testDomainNamespaceDef testDomainNamespaceDef;
-typedef testDomainNamespaceDef *testDomainNamespaceDefPtr;
-struct _testDomainNamespaceDef {
- int runstate;
- bool transient;
- bool hasManagedSave;
-
- unsigned int num_snap_nodes;
- xmlNodePtr *snap_nodes;
-};
-
-static void
-testDomainDefNamespaceFree(void *data)
-{
- testDomainNamespaceDefPtr nsdata = data;
- size_t i;
-
- if (!nsdata)
- return;
-
- for (i = 0; i < nsdata->num_snap_nodes; i++)
- xmlFreeNode(nsdata->snap_nodes[i]);
-
- VIR_FREE(nsdata->snap_nodes);
- VIR_FREE(nsdata);
-}
-
-static int
-testDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
- xmlNodePtr root ATTRIBUTE_UNUSED,
- xmlXPathContextPtr ctxt,
- void **data)
-{
- testDomainNamespaceDefPtr nsdata = NULL;
- xmlNodePtr *nodes = NULL;
- int tmp, n;
- size_t i;
- unsigned int tmpuint;
-
- if (xmlXPathRegisterNs(ctxt, BAD_CAST "test",
- BAD_CAST TEST_NAMESPACE_HREF) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Failed to register xml namespace '%s'"),
- TEST_NAMESPACE_HREF);
- return -1;
- }
-
- if (VIR_ALLOC(nsdata) < 0)
- return -1;
-
- n = virXPathNodeSet("./test:domainsnapshot", ctxt, &nodes);
- if (n < 0)
- goto error;
-
- if (n && VIR_ALLOC_N(nsdata->snap_nodes, n) < 0)
- goto error;
-
- for (i = 0; i < n; i++) {
- xmlNodePtr newnode = xmlCopyNode(nodes[i], 1);
- if (!newnode) {
- virReportOOMError();
- goto error;
- }
-
- nsdata->snap_nodes[nsdata->num_snap_nodes] = newnode;
- nsdata->num_snap_nodes++;
- }
- VIR_FREE(nodes);
-
- tmp = virXPathBoolean("boolean(./test:transient)", ctxt);
- if (tmp == -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid transient"));
- goto error;
- }
- nsdata->transient = tmp;
-
- tmp = virXPathBoolean("boolean(./test:hasmanagedsave)", ctxt);
- if (tmp == -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid hasmanagedsave"));
- goto error;
- }
- nsdata->hasManagedSave = tmp;
-
- tmp = virXPathUInt("string(./test:runstate)", ctxt, &tmpuint);
- if (tmp == 0) {
- if (tmpuint >= VIR_DOMAIN_LAST) {
- virReportError(VIR_ERR_XML_ERROR,
- _("runstate '%d' out of range'"), tmpuint);
- goto error;
- }
- nsdata->runstate = tmpuint;
- } else if (tmp == -1) {
- nsdata->runstate = VIR_DOMAIN_RUNNING;
- } else if (tmp == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid runstate"));
- goto error;
- }
-
- if (nsdata->transient && nsdata->runstate == VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("transient domain cannot have runstate 'shutoff'"));
- goto error;
- }
- if (nsdata->hasManagedSave && nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("domain with managedsave data can only have runstate 'shutoff'"));
- goto error;
- }
-
- *data = nsdata;
- return 0;
-
- error:
- VIR_FREE(nodes);
- testDomainDefNamespaceFree(nsdata);
- return -1;
-}
-
-static virCapsPtr
-testBuildCapabilities(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- virCapsPtr caps;
- virCapsGuestPtr guest;
- int guest_types[] = { VIR_DOMAIN_OSTYPE_HVM,
- VIR_DOMAIN_OSTYPE_XEN };
- size_t i, j;
-
- if ((caps = virCapabilitiesNew(VIR_ARCH_I686, false, false)) == NULL)
- goto error;
-
- if (virCapabilitiesAddHostFeature(caps, "pae") < 0)
- goto error;
- if (virCapabilitiesAddHostFeature(caps, "nonpae") < 0)
- goto error;
-
- if (VIR_ALLOC_N(caps->host.pagesSize, 2) < 0)
- goto error;
-
- caps->host.pagesSize[caps->host.nPagesSize++] = 4;
- caps->host.pagesSize[caps->host.nPagesSize++] = 2048;
-
- for (i = 0; i < privconn->numCells; i++) {
- virCapsHostNUMACellCPUPtr cpu_cells;
- virCapsHostNUMACellPageInfoPtr pages;
- size_t nPages;
-
- if (VIR_ALLOC_N(cpu_cells, privconn->cells[i].numCpus) < 0 ||
- VIR_ALLOC_N(pages, caps->host.nPagesSize) < 0) {
- VIR_FREE(cpu_cells);
- goto error;
- }
-
- nPages = caps->host.nPagesSize;
-
- memcpy(cpu_cells, privconn->cells[i].cpus,
- sizeof(*cpu_cells) * privconn->cells[i].numCpus);
-
- for (j = 0; j < nPages; j++)
- pages[j].size = caps->host.pagesSize[j];
-
- pages[0].avail = privconn->cells[i].mem / pages[0].size;
-
- if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].mem,
- privconn->cells[i].numCpus,
- cpu_cells, 0, NULL, nPages, pages) < 0)
- goto error;
- }
-
- for (i = 0; i < ARRAY_CARDINALITY(guest_types); i++) {
- if ((guest = virCapabilitiesAddGuest(caps,
- guest_types[i],
- VIR_ARCH_I686,
- TEST_EMULATOR,
- NULL,
- 0,
- NULL)) == NULL)
- goto error;
-
- if (virCapabilitiesAddGuestDomain(guest,
- VIR_DOMAIN_VIRT_TEST,
- NULL,
- NULL,
- 0,
- NULL) == NULL)
- goto error;
-
- if (virCapabilitiesAddGuestFeature(guest, "pae", true, true) == NULL)
- goto error;
- if (virCapabilitiesAddGuestFeature(guest, "nonpae", true, true) == NULL)
- goto error;
- }
-
- caps->host.nsecModels = 1;
- if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
- goto error;
- if (VIR_STRDUP(caps->host.secModels[0].model, "testSecurity") < 0)
- goto error;
-
- if (VIR_STRDUP(caps->host.secModels[0].doi, "") < 0)
- goto error;
-
- return caps;
-
- error:
- virObjectUnref(caps);
- return NULL;
-}
-
-
-static testDriverPtr
-testDriverNew(void)
-{
- virDomainXMLNamespace ns = {
- .parse = testDomainDefNamespaceParse,
- .free = testDomainDefNamespaceFree,
- };
- testDriverPtr ret;
-
- if (VIR_ALLOC(ret) < 0)
- return NULL;
-
- if (virMutexInit(&ret->lock) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot initialize mutex"));
- goto error;
- }
-
- if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns)) ||
- !(ret->eventState = virObjectEventStateNew()) ||
- !(ret->domains = virDomainObjListNew()) ||
- !(ret->networks = virNetworkObjListNew()))
- goto error;
-
- virAtomicIntSet(&ret->nextDomID, 1);
-
- return ret;
-
- error:
- testDriverFree(ret);
- return NULL;
-}
-
-
-static const char *defaultConnXML =
-"<node>"
-"<domain type='test'>"
-" <name>test</name>"
-" <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>"
-" <memory>8388608</memory>"
-" <currentMemory>2097152</currentMemory>"
-" <vcpu>2</vcpu>"
-" <os>"
-" <type>hvm</type>"
-" </os>"
-"</domain>"
-""
-"<network>"
-" <name>default</name>"
-" <uuid>dd8fe884-6c02-601e-7551-cca97df1c5df</uuid>"
-" <bridge name='virbr0'/>"
-" <forward/>"
-" <ip address='192.168.122.1' netmask='255.255.255.0'>"
-" <dhcp>"
-" <range start='192.168.122.2' end='192.168.122.254'/>"
-" </dhcp>"
-" </ip>"
-"</network>"
-""
-"<interface type=\"ethernet\" name=\"eth1\">"
-" <start mode=\"onboot\"/>"
-" <mac address=\"aa:bb:cc:dd:ee:ff\"/>"
-" <mtu size=\"1492\"/>"
-" <protocol family=\"ipv4\">"
-" <ip address=\"192.168.0.5\" prefix=\"24\"/>"
-" <route gateway=\"192.168.0.1\"/>"
-" </protocol>"
-"</interface>"
-""
-"<pool type='dir'>"
-" <name>default-pool</name>"
-" <uuid>dfe224cb-28fb-8dd0-c4b2-64eb3f0f4566</uuid>"
-" <target>"
-" <path>/default-pool</path>"
-" </target>"
-"</pool>"
-""
-"<device>"
-" <name>computer</name>"
-" <capability type='system'>"
-" <hardware>"
-" <vendor>Libvirt</vendor>"
-" <version>Test driver</version>"
-" <serial>123456</serial>"
-" <uuid>11111111-2222-3333-4444-555555555555</uuid>"
-" </hardware>"
-" <firmware>"
-" <vendor>Libvirt</vendor>"
-" <version>Test Driver</version>"
-" <release_date>01/22/2007</release_date>"
-" </firmware>"
-" </capability>"
-"</device>"
-"<device>"
-" <name>test-scsi-host-vport</name>"
-" <parent>computer</parent>"
-" <capability type='scsi_host'>"
-" <host>1</host>"
-" <capability type='fc_host'>"
-" <wwnn>2000000012341234</wwnn>"
-" <wwpn>1000000012341234</wwpn>"
-" </capability>"
-" <capability type='vport_ops'/>"
-" </capability>"
-"</device>"
-"</node>";
-
-
-static const char *defaultPoolSourcesLogicalXML =
-"<sources>\n"
-" <source>\n"
-" <device path='/dev/sda20'/>\n"
-" <name>testvg1</name>\n"
-" <format type='lvm2'/>\n"
-" </source>\n"
-" <source>\n"
-" <device path='/dev/sda21'/>\n"
-" <name>testvg2</name>\n"
-" <format type='lvm2'/>\n"
-" </source>\n"
-"</sources>\n";
-
-static const char *defaultPoolSourcesNetFSXML =
-"<sources>\n"
-" <source>\n"
-" <host name='%s'/>\n"
-" <dir path='/testshare'/>\n"
-" <format type='nfs'/>\n"
-" </source>\n"
-"</sources>\n";
-
-static const unsigned long long defaultPoolCap = (100 * 1024 * 1024 * 1024ull);
-static const unsigned long long defaultPoolAlloc;
-
-static int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
-static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
-
-static virDomainObjPtr
-testDomObjFromDomain(virDomainPtr domain)
-{
- virDomainObjPtr vm;
- testDriverPtr driver = domain->conn->privateData;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
-
- vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
- if (!vm) {
- virUUIDFormat(domain->uuid, uuidstr);
- virReportError(VIR_ERR_NO_DOMAIN,
- _("no domain with matching uuid '%s' (%s)"),
- uuidstr, domain->name);
- }
-
- return vm;
-}
-
-static char *
-testDomainGenerateIfname(virDomainDefPtr domdef)
-{
- int maxif = 1024;
- int ifctr;
- size_t i;
-
- for (ifctr = 0; ifctr < maxif; ++ifctr) {
- char *ifname;
- int found = 0;
-
- if (virAsprintf(&ifname, "testnet%d", ifctr) < 0)
- return NULL;
-
- /* Generate network interface names */
- for (i = 0; i < domdef->nnets; i++) {
- if (domdef->nets[i]->ifname &&
- STREQ(domdef->nets[i]->ifname, ifname)) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- return ifname;
- VIR_FREE(ifname);
- }
-
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Exceeded max iface limit %d"), maxif);
- return NULL;
-}
-
-static int
-testDomainGenerateIfnames(virDomainDefPtr domdef)
-{
- size_t i = 0;
-
- for (i = 0; i < domdef->nnets; i++) {
- char *ifname;
- if (domdef->nets[i]->ifname)
- continue;
-
- ifname = testDomainGenerateIfname(domdef);
- if (!ifname)
- return -1;
-
- domdef->nets[i]->ifname = ifname;
- }
-
- return 0;
-}
-
-
-static void
-testDomainShutdownState(virDomainPtr domain,
- virDomainObjPtr privdom,
- virDomainShutoffReason reason)
-{
- virDomainObjRemoveTransientDef(privdom);
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason);
-
- if (domain)
- domain->id = -1;
-}
-
-/* Set up domain runtime state */
-static int
-testDomainStartState(testDriverPtr privconn,
- virDomainObjPtr dom,
- virDomainRunningReason reason)
-{
- int ret = -1;
-
- virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason);
- dom->def->id = virAtomicIntAdd(&privconn->nextDomID, 1);
-
- if (virDomainObjSetDefTransient(privconn->caps,
- privconn->xmlopt,
- dom) < 0) {
- goto cleanup;
- }
-
- dom->hasManagedSave = false;
- ret = 0;
- cleanup:
- if (ret < 0)
- testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED);
- return ret;
-}
-
-
-static char *testBuildFilename(const char *relativeTo,
- const char *filename)
-{
- char *offset;
- int baseLen;
- char *ret;
-
- if (!filename || filename[0] == '\0')
- return NULL;
- if (filename[0] == '/') {
- ignore_value(VIR_STRDUP(ret, filename));
- return ret;
- }
-
- offset = strrchr(relativeTo, '/');
- if ((baseLen = (offset-relativeTo+1))) {
- char *absFile;
- int totalLen = baseLen + strlen(filename) + 1;
- if (VIR_ALLOC_N(absFile, totalLen) < 0)
- return NULL;
- if (virStrncpy(absFile, relativeTo, baseLen, totalLen) == NULL) {
- VIR_FREE(absFile);
- return NULL;
- }
- strcat(absFile, filename);
- return absFile;
- } else {
- ignore_value(VIR_STRDUP(ret, filename));
- return ret;
- }
-}
-
-static xmlNodePtr
-testParseXMLDocFromFile(xmlNodePtr node, const char *file, const char *type)
-{
- xmlNodePtr ret = NULL;
- xmlDocPtr doc = NULL;
- char *absFile = NULL;
- char *relFile = virXMLPropString(node, "file");
-
- if (relFile != NULL) {
- absFile = testBuildFilename(file, relFile);
- VIR_FREE(relFile);
- if (!absFile) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("resolving %s filename"), type);
- return NULL;
- }
-
- if (!(doc = virXMLParse(absFile, NULL, type)))
- goto error;
-
- ret = xmlCopyNode(xmlDocGetRootElement(doc), 1);
- if (!ret) {
- virReportOOMError();
- goto error;
- }
- xmlReplaceNode(node, ret);
- xmlFreeNode(node);
- } else {
- ret = node;
- }
-
- error:
- xmlFreeDoc(doc);
- VIR_FREE(absFile);
- return ret;
-}
-
-static int
-testParseNodeInfo(virNodeInfoPtr nodeInfo, xmlXPathContextPtr ctxt)
-{
- char *str;
- long l;
- int ret;
-
- ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->nodes = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu nodes value"));
- goto error;
- }
-
- ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->sockets = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu sockets value"));
- goto error;
- }
-
- ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->cores = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu cores value"));
- goto error;
- }
-
- ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->threads = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu threads value"));
- goto error;
- }
-
- nodeInfo->cpus = (nodeInfo->cores * nodeInfo->threads *
- nodeInfo->sockets * nodeInfo->nodes);
- ret = virXPathLong("string(/node/cpu/active[1])", ctxt, &l);
- if (ret == 0) {
- if (l < nodeInfo->cpus)
- nodeInfo->cpus = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu active value"));
- goto error;
- }
- ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->mhz = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu mhz value"));
- goto error;
- }
-
- str = virXPathString("string(/node/cpu/model[1])", ctxt);
- if (str != NULL) {
- if (virStrcpyStatic(nodeInfo->model, str) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Model %s too big for destination"), str);
- VIR_FREE(str);
- goto error;
- }
- VIR_FREE(str);
- }
-
- ret = virXPathLong("string(/node/memory[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->memory = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node memory value"));
- goto error;
- }
-
- return 0;
- error:
- return -1;
-}
-
-static int
-testParseDomainSnapshots(testDriverPtr privconn,
- virDomainObjPtr domobj,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- size_t i;
- int ret = -1;
- testDomainNamespaceDefPtr nsdata = domobj->def->namespaceData;
- xmlNodePtr *nodes = nsdata->snap_nodes;
-
- for (i = 0; i < nsdata->num_snap_nodes; i++) {
- virDomainSnapshotObjPtr snap;
- virDomainSnapshotDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "domainsnapshot");
- if (!node)
- goto error;
-
- def = virDomainSnapshotDefParseNode(ctxt->doc, node,
- privconn->caps,
- privconn->xmlopt,
- VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
- VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL |
- VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
- if (!def)
- goto error;
-
- if (!(snap = virDomainSnapshotAssignDef(domobj->snapshots, def))) {
- virDomainSnapshotDefFree(def);
- goto error;
- }
-
- if (def->current) {
- if (domobj->current_snapshot) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("more than one snapshot claims to be active"));
- goto error;
- }
-
- domobj->current_snapshot = snap;
- }
- }
-
- if (virDomainSnapshotUpdateRelations(domobj->snapshots) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Snapshots have inconsistent relations for "
- "domain %s"), domobj->def->name);
- goto error;
- }
-
- ret = 0;
- error:
- return ret;
-}
-
-static int
-testParseDomains(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virDomainObjPtr obj;
-
- num = virXPathNodeSet("/node/domain", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virDomainDefPtr def;
- testDomainNamespaceDefPtr nsdata;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "domain");
- if (!node)
- goto error;
-
- def = virDomainDefParseNode(ctxt->doc, node,
- privconn->caps, privconn->xmlopt,
- VIR_DOMAIN_DEF_PARSE_INACTIVE);
- if (!def)
- goto error;
-
- if (testDomainGenerateIfnames(def) < 0 ||
- !(obj = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- 0, NULL))) {
- virDomainDefFree(def);
- goto error;
- }
-
- if (testParseDomainSnapshots(privconn, obj, file, ctxt) < 0) {
- virObjectUnlock(obj);
- goto error;
- }
-
- nsdata = def->namespaceData;
- obj->persistent = !nsdata->transient;
- obj->hasManagedSave = nsdata->hasManagedSave;
-
- if (nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
- if (testDomainStartState(privconn, obj,
- VIR_DOMAIN_RUNNING_BOOTED) < 0) {
- virObjectUnlock(obj);
- goto error;
- }
- } else {
- testDomainShutdownState(NULL, obj, 0);
- }
- virDomainObjSetState(obj, nsdata->runstate, 0);
-
- virObjectUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseNetworks(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virNetworkObjPtr obj;
-
- num = virXPathNodeSet("/node/network", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virNetworkDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "network");
- if (!node)
- goto error;
-
- def = virNetworkDefParseNode(ctxt->doc, node);
- if (!def)
- goto error;
-
- if (!(obj = virNetworkAssignDef(privconn->networks, def, 0))) {
- virNetworkDefFree(def);
- goto error;
- }
-
- obj->active = 1;
- virNetworkObjEndAPI(&obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseInterfaces(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virInterfaceObjPtr obj;
-
- num = virXPathNodeSet("/node/interface", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virInterfaceDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "interface");
- if (!node)
- goto error;
-
- def = virInterfaceDefParseNode(ctxt->doc, node);
- if (!def)
- goto error;
-
- if (!(obj = virInterfaceAssignDef(&privconn->ifaces, def))) {
- virInterfaceDefFree(def);
- goto error;
- }
-
- obj->active = 1;
- virInterfaceObjUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testOpenVolumesForPool(const char *file,
- xmlXPathContextPtr ctxt,
- virStoragePoolObjPtr pool,
- int poolidx)
-{
- char *vol_xpath;
- size_t i;
- int num, ret = -1;
- xmlNodePtr *nodes = NULL;
- virStorageVolDefPtr def = NULL;
-
- /* Find storage volumes */
- if (virAsprintf(&vol_xpath, "/node/pool[%d]/volume", poolidx) < 0)
- goto error;
-
- num = virXPathNodeSet(vol_xpath, ctxt, &nodes);
- VIR_FREE(vol_xpath);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "volume");
- if (!node)
- goto error;
-
- def = virStorageVolDefParseNode(pool->def, ctxt->doc, node, 0);
- if (!def)
- goto error;
-
- if (def->target.path == NULL) {
- if (virAsprintf(&def->target.path, "%s/%s",
- pool->def->target.path,
- def->name) == -1)
- goto error;
- }
-
- if (!def->key && VIR_STRDUP(def->key, def->target.path) < 0)
- goto error;
- if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, def) < 0)
- goto error;
-
- pool->def->allocation += def->target.allocation;
- pool->def->available = (pool->def->capacity -
- pool->def->allocation);
- def = NULL;
- }
-
- ret = 0;
- error:
- virStorageVolDefFree(def);
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseStorage(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virStoragePoolObjPtr obj;
-
- num = virXPathNodeSet("/node/pool", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virStoragePoolDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "pool");
- if (!node)
- goto error;
-
- def = virStoragePoolDefParseNode(ctxt->doc, node);
- if (!def)
- goto error;
-
- if (!(obj = virStoragePoolObjAssignDef(&privconn->pools,
- def))) {
- virStoragePoolDefFree(def);
- goto error;
- }
-
- if (testStoragePoolObjSetDefaults(obj) == -1) {
- virStoragePoolObjUnlock(obj);
- goto error;
- }
- obj->active = 1;
-
- /* Find storage volumes */
- if (testOpenVolumesForPool(file, ctxt, obj, i+1) < 0) {
- virStoragePoolObjUnlock(obj);
- goto error;
- }
-
- virStoragePoolObjUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseNodedevs(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virNodeDeviceObjPtr obj;
-
- num = virXPathNodeSet("/node/device", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virNodeDeviceDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "nodedev");
- if (!node)
- goto error;
-
- def = virNodeDeviceDefParseNode(ctxt->doc, node, 0, NULL);
- if (!def)
- goto error;
-
- if (!(obj = virNodeDeviceAssignDef(&privconn->devs, def))) {
- virNodeDeviceDefFree(def);
- goto error;
- }
-
- virNodeDeviceObjUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseAuthUsers(testDriverPtr privconn,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
-
- num = virXPathNodeSet("/node/auth/user", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- privconn->numAuths = num;
- if (num && VIR_ALLOC_N(privconn->auths, num) < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- char *username, *password;
-
- ctxt->node = nodes[i];
- username = virXPathString("string(.)", ctxt);
- if (!username || STREQ(username, "")) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("missing username in /node/auth/user field"));
- VIR_FREE(username);
- goto error;
- }
- /* This field is optional. */
- password = virXMLPropString(nodes[i], "password");
-
- privconn->auths[i].username = username;
- privconn->auths[i].password = password;
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testOpenParse(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- if (!xmlStrEqual(ctxt->node->name, BAD_CAST "node")) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Root element is not 'node'"));
- goto error;
- }
-
- if (testParseNodeInfo(&privconn->nodeInfo, ctxt) < 0)
- goto error;
- if (testParseDomains(privconn, file, ctxt) < 0)
- goto error;
- if (testParseNetworks(privconn, file, ctxt) < 0)
- goto error;
- if (testParseInterfaces(privconn, file, ctxt) < 0)
- goto error;
- if (testParseStorage(privconn, file, ctxt) < 0)
- goto error;
- if (testParseNodedevs(privconn, file, ctxt) < 0)
- goto error;
- if (testParseAuthUsers(privconn, ctxt) < 0)
- goto error;
+unsigned long long defaultPoolCap = (100 * 1024 * 1024 * 1024ull);
+unsigned long long defaultPoolAlloc;
- return 0;
- error:
- return -1;
-}
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
+int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
/* No shared state between simultaneous test connections initialized
* from a file. */
-static int
-testOpenFromFile(virConnectPtr conn, const char *file)
-{
- xmlDocPtr doc = NULL;
- xmlXPathContextPtr ctxt = NULL;
- testDriverPtr privconn;
-
- if (!(privconn = testDriverNew()))
- return VIR_DRV_OPEN_ERROR;
-
- testDriverLock(privconn);
- conn->privateData = privconn;
-
- if (!(privconn->caps = testBuildCapabilities(conn)))
- goto error;
-
- if (!(doc = virXMLParseFileCtxt(file, &ctxt)))
- goto error;
-
- privconn->numCells = 0;
- memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
-
- if (testOpenParse(privconn, file, ctxt) < 0)
- goto error;
-
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- testDriverUnlock(privconn);
-
- return 0;
-
- error:
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- testDriverFree(privconn);
- conn->privateData = NULL;
- return VIR_DRV_OPEN_ERROR;
-}
-
-/* Simultaneous test:///default connections should share the same
- * common state (among other things, this allows testing event
- * detection in one connection for an action caused in another). */
-static int
-testOpenDefault(virConnectPtr conn)
-{
- int u;
- testDriverPtr privconn = NULL;
- xmlDocPtr doc = NULL;
- xmlXPathContextPtr ctxt = NULL;
-
- virMutexLock(&defaultLock);
- if (defaultConnections++) {
- conn->privateData = defaultConn;
- virMutexUnlock(&defaultLock);
- return VIR_DRV_OPEN_SUCCESS;
- }
-
- if (!(privconn = testDriverNew()))
- goto error;
-
- conn->privateData = privconn;
-
- memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
-
- /* Numa setup */
- privconn->numCells = 2;
- for (u = 0; u < privconn->numCells; ++u) {
- privconn->cells[u].numCpus = 8;
- privconn->cells[u].mem = (u + 1) * 2048 * 1024;
- privconn->cells[u].freeMem = (u + 1) * 1024 * 1024;
- }
- for (u = 0; u < 16; u++) {
- virBitmapPtr siblings = virBitmapNew(16);
- if (!siblings)
- goto error;
- ignore_value(virBitmapSetBit(siblings, u));
- privconn->cells[u / 8].cpus[(u % 8)].id = u;
- privconn->cells[u / 8].cpus[(u % 8)].socket_id = u / 8;
- privconn->cells[u / 8].cpus[(u % 8)].core_id = u % 8;
- privconn->cells[u / 8].cpus[(u % 8)].siblings = siblings;
- }
-
- if (!(privconn->caps = testBuildCapabilities(conn)))
- goto error;
-
- if (!(doc = virXMLParseStringCtxt(defaultConnXML,
- _("(test driver)"), &ctxt)))
- goto error;
-
- if (testOpenParse(privconn, NULL, ctxt) < 0)
- goto error;
-
- defaultConn = privconn;
-
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- virMutexUnlock(&defaultLock);
-
- return VIR_DRV_OPEN_SUCCESS;
-
- error:
- testDriverFree(privconn);
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- conn->privateData = NULL;
- defaultConnections--;
- virMutexUnlock(&defaultLock);
- return VIR_DRV_OPEN_ERROR;
-}
-
-static int
-testConnectAuthenticate(virConnectPtr conn,
- virConnectAuthPtr auth)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
- ssize_t i;
- char *username = NULL, *password = NULL;
-
- if (privconn->numAuths == 0)
- return 0;
-
- /* Authentication is required because the test XML contains a
- * non-empty <auth/> section. First we must ask for a username.
- */
- username = virAuthGetUsername(conn, auth, "test", NULL, "localhost"/*?*/);
- if (!username) {
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed when asking for username"));
- goto cleanup;
- }
-
- /* Does the username exist? */
- for (i = 0; i < privconn->numAuths; ++i) {
- if (STREQ(privconn->auths[i].username, username))
- goto found_user;
- }
- i = -1;
-
- found_user:
- /* Even if we didn't find the user, we still ask for a password. */
- if (i == -1 || privconn->auths[i].password != NULL) {
- password = virAuthGetPassword(conn, auth, "test",
- username, "localhost");
- if (password == NULL) {
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed when asking for password"));
- goto cleanup;
- }
- }
-
- if (i == -1 ||
- (password && STRNEQ(privconn->auths[i].password, password))) {
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed, see test XML for the correct username/password"));
- goto cleanup;
- }
-
- ret = 0;
- cleanup:
- VIR_FREE(username);
- VIR_FREE(password);
- return ret;
-}
-
-static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
- virConnectAuthPtr auth,
- virConfPtr conf ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- int ret;
-
- virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
-
- if (!conn->uri)
- return VIR_DRV_OPEN_DECLINED;
-
- if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "test"))
- return VIR_DRV_OPEN_DECLINED;
-
- /* Remote driver should handle these. */
- if (conn->uri->server)
- return VIR_DRV_OPEN_DECLINED;
-
- /* From this point on, the connection is for us. */
- if (!conn->uri->path
- || conn->uri->path[0] == '\0'
- || (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("testOpen: supply a path or use test:///default"));
- return VIR_DRV_OPEN_ERROR;
- }
-
- if (STREQ(conn->uri->path, "/default"))
- ret = testOpenDefault(conn);
- else
- ret = testOpenFromFile(conn,
- conn->uri->path);
-
- if (ret != VIR_DRV_OPEN_SUCCESS)
- return ret;
-
- /* Fake authentication. */
- if (testConnectAuthenticate(conn, auth) < 0)
- return VIR_DRV_OPEN_ERROR;
-
- return VIR_DRV_OPEN_SUCCESS;
-}
-
-static int testConnectClose(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- bool dflt = false;
-
- if (privconn == defaultConn) {
- dflt = true;
- virMutexLock(&defaultLock);
- if (--defaultConnections) {
- virMutexUnlock(&defaultLock);
- return 0;
- }
- }
-
- testDriverLock(privconn);
- testDriverFree(privconn);
-
- if (dflt) {
- defaultConn = NULL;
- virMutexUnlock(&defaultLock);
- }
-
- conn->privateData = NULL;
- return 0;
-}
-
-static int testConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned long *hvVer)
-{
- *hvVer = 2;
- return 0;
-}
-
-static char *testConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return virGetHostname();
-}
-
-
-static int testConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 1;
-}
-
-static int testConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-static int testConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 1;
-}
-
-static int testConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char *type ATTRIBUTE_UNUSED)
-{
- return 32;
-}
-
-static char *
-testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char **xmlCPUs,
- unsigned int ncpus,
- unsigned int flags)
-{
- char *cpu;
-
- virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
-
- cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
-
- return cpu;
-}
-
-static int testNodeGetInfo(virConnectPtr conn,
- virNodeInfoPtr info)
-{
- testDriverPtr privconn = conn->privateData;
- testDriverLock(privconn);
- memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo));
- testDriverUnlock(privconn);
- return 0;
-}
-
-static char *testConnectGetCapabilities(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- char *xml;
- testDriverLock(privconn);
- xml = virCapabilitiesFormatXML(privconn->caps);
- testDriverUnlock(privconn);
- return xml;
-}
-
-static char *
-testConnectGetSysinfo(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- char *ret;
- const char *sysinfo = "<sysinfo type='smbios'>\n"
- " <bios>\n"
- " <entry name='vendor'>LENOVO</entry>\n"
- " <entry name='version'>G4ETA1WW (2.61 )</entry>\n"
- " <entry name='date'>05/07/2014</entry>\n"
- " <entry name='release'>2.61</entry>\n"
- " </bios>\n"
- "</sysinfo>\n";
-
- virCheckFlags(0, NULL);
-
- ignore_value(VIR_STRDUP(ret, sysinfo));
- return ret;
-}
-
-static const char *
-testConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return "TEST";
-}
-
-static int testConnectNumOfDomains(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int count;
-
- testDriverLock(privconn);
- count = virDomainObjListNumOfDomains(privconn->domains, true, NULL, NULL);
- testDriverUnlock(privconn);
-
- return count;
-}
-
-static int testDomainIsActive(virDomainPtr dom)
-{
- virDomainObjPtr obj;
- int ret;
-
- if (!(obj = testDomObjFromDomain(dom)))
- return -1;
-
- ret = virDomainObjIsActive(obj);
- virDomainObjEndAPI(&obj);
- return ret;
-}
-
-static int testDomainIsPersistent(virDomainPtr dom)
-{
- virDomainObjPtr obj;
- int ret;
-
- if (!(obj = testDomObjFromDomain(dom)))
- return -1;
-
- ret = obj->persistent;
-
- virDomainObjEndAPI(&obj);
- return ret;
-}
-
-static int testDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-static virDomainPtr
-testDomainCreateXML(virConnectPtr conn, const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainDefPtr def;
- virDomainObjPtr dom = NULL;
- virObjectEventPtr event = NULL;
- unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
- virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
-
- if (flags & VIR_DOMAIN_START_VALIDATE)
- parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
- testDriverLock(privconn);
- if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
- parse_flags)) == NULL)
- goto cleanup;
-
- if (testDomainGenerateIfnames(def) < 0)
- goto cleanup;
- if (!(dom = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
- VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
- NULL)))
- goto cleanup;
- def = NULL;
-
- if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
- if (!dom->persistent) {
- virDomainObjListRemove(privconn->domains, dom);
- dom = NULL;
- }
- goto cleanup;
- }
-
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- if (dom)
- virObjectUnlock(dom);
- testObjectEventQueue(privconn, event);
- virDomainDefFree(def);
- testDriverUnlock(privconn);
- return ret;
-}
-
-
-static virDomainPtr testDomainLookupByID(virConnectPtr conn,
- int id)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainObjPtr dom;
-
- if (!(dom = virDomainObjListFindByID(privconn->domains, id))) {
- virReportError(VIR_ERR_NO_DOMAIN, NULL);
- goto cleanup;
- }
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- if (dom)
- virObjectUnlock(dom);
- return ret;
-}
-
-static virDomainPtr testDomainLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainObjPtr dom;
-
- if (!(dom = virDomainObjListFindByUUID(privconn->domains, uuid))) {
- virReportError(VIR_ERR_NO_DOMAIN, NULL);
- goto cleanup;
- }
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- if (dom)
- virObjectUnlock(dom);
- return ret;
-}
-
-static virDomainPtr testDomainLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainObjPtr dom;
-
- if (!(dom = virDomainObjListFindByName(privconn->domains, name))) {
- virReportError(VIR_ERR_NO_DOMAIN, NULL);
- goto cleanup;
- }
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- virDomainObjEndAPI(&dom);
- return ret;
-}
-
-static int testConnectListDomains(virConnectPtr conn,
- int *ids,
- int maxids)
-{
- testDriverPtr privconn = conn->privateData;
-
- return virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
- NULL, NULL);
-}
-
-static int testDomainDestroy(virDomainPtr domain)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_DESTROYED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainResume(virDomainPtr domain)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_PAUSED) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not paused"),
- domain->name);
- goto cleanup;
- }
-
- virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_UNPAUSED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_RESUMED,
- VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainSuspend(virDomainPtr domain)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
- int state;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- state = virDomainObjGetState(privdom, NULL);
- if (state == VIR_DOMAIN_SHUTOFF || state == VIR_DOMAIN_PAUSED) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not running"),
- domain->name);
- goto cleanup;
- }
-
- virDomainObjSetState(privdom, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainShutdownFlags(virDomainPtr domain,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("domain '%s' not running"), domain->name);
- goto cleanup;
- }
-
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainShutdown(virDomainPtr domain)
-{
- return testDomainShutdownFlags(domain, 0);
-}
-
-/* Similar behaviour as shutdown */
-static int testDomainReboot(virDomainPtr domain,
- unsigned int action ATTRIBUTE_UNUSED)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTDOWN,
- VIR_DOMAIN_SHUTDOWN_USER);
-
- switch (privdom->def->onReboot) {
- case VIR_DOMAIN_LIFECYCLE_DESTROY:
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
- VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- break;
-
- case VIR_DOMAIN_LIFECYCLE_RESTART:
- virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_BOOTED);
- break;
-
- case VIR_DOMAIN_LIFECYCLE_PRESERVE:
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
- VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- break;
-
- case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME:
- virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_BOOTED);
- break;
-
- default:
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
- VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- break;
- }
-
- if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
- }
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainGetInfo(virDomainPtr domain,
- virDomainInfoPtr info)
-{
- struct timeval tv;
- virDomainObjPtr privdom;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("getting time of day"));
- goto cleanup;
- }
-
- info->state = virDomainObjGetState(privdom, NULL);
- info->memory = privdom->def->mem.cur_balloon;
- info->maxMem = virDomainDefGetMemoryTotal(privdom->def);
- info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
- info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll));
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetState(virDomainPtr domain,
- int *state,
- int *reason,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
-
- virCheckFlags(0, -1);
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- *state = virDomainObjGetState(privdom, reason);
-
- virDomainObjEndAPI(&privdom);
-
- return 0;
-}
-
-#define TEST_SAVE_MAGIC "TestGuestMagic"
-
-static int
-testDomainSaveFlags(virDomainPtr domain, const char *path,
- const char *dxml, unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- char *xml = NULL;
- int fd = -1;
- int len;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
- if (dxml) {
- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
- _("xml modification unsupported"));
- return -1;
- }
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- xml = virDomainDefFormat(privdom->def, privconn->caps,
- VIR_DOMAIN_DEF_FORMAT_SECURE);
-
- if (xml == NULL) {
- virReportSystemError(errno,
- _("saving domain '%s' failed to allocate space for metadata"),
- domain->name);
- goto cleanup;
- }
-
- if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': open failed"),
- domain->name, path);
- goto cleanup;
- }
- len = strlen(xml);
- if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
- if (safewrite(fd, (char*)&len, sizeof(len)) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
- if (safewrite(fd, xml, len) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
-
- if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
- fd = -1;
-
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SAVED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SAVED);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
- cleanup:
- VIR_FREE(xml);
-
- /* Don't report failure in close or unlink, because
- * in either case we're already in a failure scenario
- * and have reported a earlier error */
- if (ret != 0) {
- VIR_FORCE_CLOSE(fd);
- unlink(path);
- }
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int
-testDomainSave(virDomainPtr domain,
- const char *path)
-{
- return testDomainSaveFlags(domain, path, NULL, 0);
-}
-
-static int
-testDomainRestoreFlags(virConnectPtr conn,
- const char *path,
- const char *dxml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- char *xml = NULL;
- char magic[15];
- int fd = -1;
- int len;
- virDomainDefPtr def = NULL;
- virDomainObjPtr dom = NULL;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
- if (dxml) {
- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
- _("xml modification unsupported"));
- return -1;
- }
-
- if ((fd = open(path, O_RDONLY)) < 0) {
- virReportSystemError(errno,
- _("cannot read domain image '%s'"),
- path);
- goto cleanup;
- }
- if (saferead(fd, magic, sizeof(magic)) != sizeof(magic)) {
- virReportSystemError(errno,
- _("incomplete save header in '%s'"),
- path);
- goto cleanup;
- }
- if (memcmp(magic, TEST_SAVE_MAGIC, sizeof(magic))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("mismatched header magic"));
- goto cleanup;
- }
- if (saferead(fd, (char*)&len, sizeof(len)) != sizeof(len)) {
- virReportSystemError(errno,
- _("failed to read metadata length in '%s'"),
- path);
- goto cleanup;
- }
- if (len < 1 || len > 8192) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("length of metadata out of range"));
- goto cleanup;
- }
- if (VIR_ALLOC_N(xml, len+1) < 0)
- goto cleanup;
- if (saferead(fd, xml, len) != len) {
- virReportSystemError(errno,
- _("incomplete metadata in '%s'"), path);
- goto cleanup;
- }
- xml[len] = '\0';
-
- def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
- VIR_DOMAIN_DEF_PARSE_INACTIVE);
- if (!def)
- goto cleanup;
-
- if (testDomainGenerateIfnames(def) < 0)
- goto cleanup;
- if (!(dom = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
- VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
- NULL)))
- goto cleanup;
- def = NULL;
-
- if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_RESTORED) < 0) {
- if (!dom->persistent) {
- virDomainObjListRemove(privconn->domains, dom);
- dom = NULL;
- }
- goto cleanup;
- }
-
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_RESTORED);
- ret = 0;
-
- cleanup:
- virDomainDefFree(def);
- VIR_FREE(xml);
- VIR_FORCE_CLOSE(fd);
- if (dom)
- virObjectUnlock(dom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int
-testDomainRestore(virConnectPtr conn,
- const char *path)
-{
- return testDomainRestoreFlags(conn, path, NULL, 0);
-}
-
-static int testDomainCoreDumpWithFormat(virDomainPtr domain,
- const char *to,
- unsigned int dumpformat,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- int fd = -1;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DUMP_CRASH, -1);
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
- virReportSystemError(errno,
- _("domain '%s' coredump: failed to open %s"),
- domain->name, to);
- goto cleanup;
- }
- if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
- virReportSystemError(errno,
- _("domain '%s' coredump: failed to write header to %s"),
- domain->name, to);
- goto cleanup;
- }
- if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno,
- _("domain '%s' coredump: write failed: %s"),
- domain->name, to);
- goto cleanup;
- }
-
- /* we don't support non-raw formats in test driver */
- if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
- virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
- _("kdump-compressed format is not supported here"));
- goto cleanup;
- }
-
- if (flags & VIR_DUMP_CRASH) {
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_CRASHED);
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
- }
-
- ret = 0;
- cleanup:
- VIR_FORCE_CLOSE(fd);
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-
-static int
-testDomainCoreDump(virDomainPtr domain,
- const char *to,
- unsigned int flags)
-{
- return testDomainCoreDumpWithFormat(domain, to,
- VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags);
-}
-
-
-static char *
-testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
-{
- char *ret;
-
- ignore_value(VIR_STRDUP(ret, "linux"));
- return ret;
-}
-
-
-static unsigned long long
-testDomainGetMaxMemory(virDomainPtr domain)
-{
- virDomainObjPtr privdom;
- unsigned long long ret = 0;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return 0;
-
- ret = virDomainDefGetMemoryTotal(privdom->def);
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainSetMaxMemory(virDomainPtr domain,
- unsigned long memory)
-{
- virDomainObjPtr privdom;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- /* XXX validate not over host memory wrt to other domains */
- virDomainDefSetMemoryTotal(privdom->def, memory);
-
- virDomainObjEndAPI(&privdom);
- return 0;
-}
-
-static int testDomainSetMemory(virDomainPtr domain,
- unsigned long memory)
-{
- virDomainObjPtr privdom;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (memory > virDomainDefGetMemoryTotal(privdom->def)) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privdom->def->mem.cur_balloon = memory;
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainDefPtr def;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG |
- VIR_DOMAIN_VCPU_MAXIMUM, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- if (!(def = virDomainObjGetOneDef(vm, flags)))
- goto cleanup;
-
- if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
- ret = virDomainDefGetVcpusMax(def);
- else
- ret = virDomainDefGetVcpus(def);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainGetMaxVcpus(virDomainPtr domain)
-{
- return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_VCPU_MAXIMUM));
-}
-
-static int
-testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
- unsigned int flags)
-{
- testDriverPtr driver = domain->conn->privateData;
- virDomainObjPtr privdom = NULL;
- virDomainDefPtr def;
- virDomainDefPtr persistentDef;
- int ret = -1, maxvcpus;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG |
- VIR_DOMAIN_VCPU_MAXIMUM, -1);
-
- if ((maxvcpus = testConnectGetMaxVcpus(domain->conn, NULL)) < 0)
- return -1;
-
- if (nrCpus > maxvcpus) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested cpu amount exceeds maximum supported amount "
- "(%d > %d)"), nrCpus, maxvcpus);
- return -1;
- }
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (virDomainObjGetDefs(privdom, flags, &def, &persistentDef) < 0)
- goto cleanup;
-
- if (def && virDomainDefGetVcpusMax(def) < nrCpus) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested cpu amount exceeds maximum (%d > %d)"),
- nrCpus, virDomainDefGetVcpusMax(def));
- goto cleanup;
- }
-
- if (persistentDef &&
- !(flags & VIR_DOMAIN_VCPU_MAXIMUM) &&
- virDomainDefGetVcpusMax(persistentDef) < nrCpus) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested cpu amount exceeds maximum (%d > %d)"),
- nrCpus, virDomainDefGetVcpusMax(persistentDef));
- goto cleanup;
- }
-
- if (def &&
- virDomainDefSetVcpus(def, nrCpus) < 0)
- goto cleanup;
-
- if (persistentDef) {
- if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
- if (virDomainDefSetVcpusMax(persistentDef, nrCpus,
- driver->xmlopt) < 0)
- goto cleanup;
- } else {
- if (virDomainDefSetVcpus(persistentDef, nrCpus) < 0)
- goto cleanup;
- }
- }
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainSetVcpus(virDomainPtr domain, unsigned int nrCpus)
-{
- return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_AFFECT_LIVE);
-}
-
-static int testDomainGetVcpus(virDomainPtr domain,
- virVcpuInfoPtr info,
- int maxinfo,
- unsigned char *cpumaps,
- int maplen)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virDomainDefPtr def;
- size_t i;
- int maxcpu, hostcpus;
- int ret = -1;
- struct timeval tv;
- unsigned long long statbase;
- virBitmapPtr allcpumap = NULL;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (!virDomainObjIsActive(privdom)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot list vcpus for an inactive domain"));
- goto cleanup;
- }
-
- def = privdom->def;
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportSystemError(errno,
- "%s", _("getting time of day"));
- goto cleanup;
- }
-
- statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
-
- hostcpus = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo);
- maxcpu = maplen * 8;
- if (maxcpu > hostcpus)
- maxcpu = hostcpus;
-
- if (!(allcpumap = virBitmapNew(hostcpus)))
- goto cleanup;
-
- virBitmapSetAll(allcpumap);
-
- /* Clamp to actual number of vcpus */
- if (maxinfo > virDomainDefGetVcpus(privdom->def))
- maxinfo = virDomainDefGetVcpus(privdom->def);
-
- memset(info, 0, sizeof(*info) * maxinfo);
- memset(cpumaps, 0, maxinfo * maplen);
-
- for (i = 0; i < maxinfo; i++) {
- virDomainVcpuDefPtr vcpu = virDomainDefGetVcpu(def, i);
- virBitmapPtr bitmap = NULL;
-
- if (!vcpu->online)
- continue;
-
- if (vcpu->cpumask)
- bitmap = vcpu->cpumask;
- else if (def->cpumask)
- bitmap = def->cpumask;
- else
- bitmap = allcpumap;
-
- if (cpumaps)
- virBitmapToDataBuf(bitmap, VIR_GET_CPUMAP(cpumaps, maplen, i), maplen);
-
- info[i].number = i;
- info[i].state = VIR_VCPU_RUNNING;
- info[i].cpu = virBitmapLastSetBit(bitmap);
-
- /* Fake an increasing cpu time value */
- info[i].cpuTime = statbase / 10;
- }
-
- ret = maxinfo;
- cleanup:
- virBitmapFree(allcpumap);
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainPinVcpu(virDomainPtr domain,
- unsigned int vcpu,
- unsigned char *cpumap,
- int maplen)
-{
- virDomainVcpuDefPtr vcpuinfo;
- virDomainObjPtr privdom;
- virDomainDefPtr def;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- def = privdom->def;
-
- if (!virDomainObjIsActive(privdom)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot pin vcpus on an inactive domain"));
- goto cleanup;
- }
-
- if (!(vcpuinfo = virDomainDefGetVcpu(def, vcpu)) ||
- !vcpuinfo->online) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested vcpu '%d' is not present in the domain"),
- vcpu);
- goto cleanup;
- }
-
- virBitmapFree(vcpuinfo->cpumask);
-
- if (!(vcpuinfo->cpumask = virBitmapNewData(cpumap, maplen)))
- goto cleanup;
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetVcpuPinInfo(virDomainPtr dom,
- int ncpumaps,
- unsigned char *cpumaps,
- int maplen,
- unsigned int flags)
-{
- testDriverPtr driver = dom->conn->privateData;
- virDomainObjPtr privdom;
- virDomainDefPtr def;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(dom)))
- return -1;
-
- if (!(def = virDomainObjGetOneDef(privdom, flags)))
- goto cleanup;
-
- ret = virDomainDefGetVcpuPinInfoHelper(def, maplen, ncpumaps, cpumaps,
- VIR_NODEINFO_MAXCPUS(driver->nodeInfo),
- NULL);
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainDefPtr def;
- virDomainObjPtr privdom;
- char *ret = NULL;
-
- /* Flags checked by virDomainDefFormat */
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return NULL;
-
- def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
- privdom->newDef ? privdom->newDef : privdom->def;
-
- ret = virDomainDefFormat(def, privconn->caps,
- virDomainDefFormatConvertXMLFlags(flags));
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testConnectNumOfDefinedDomains(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
-
- return virDomainObjListNumOfDomains(privconn->domains, false, NULL, NULL);
-}
-
-static int testConnectListDefinedDomains(virConnectPtr conn,
- char **const names,
- int maxnames)
-{
-
- testDriverPtr privconn = conn->privateData;
-
- memset(names, 0, sizeof(*names)*maxnames);
- return virDomainObjListGetInactiveNames(privconn->domains, names, maxnames,
- NULL, NULL);
-}
-
-static virDomainPtr testDomainDefineXMLFlags(virConnectPtr conn,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainDefPtr def;
- virDomainObjPtr dom = NULL;
- virObjectEventPtr event = NULL;
- virDomainDefPtr oldDef = NULL;
- unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
- virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
-
- if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
- parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
- if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
- parse_flags)) == NULL)
- goto cleanup;
-
- if (testDomainGenerateIfnames(def) < 0)
- goto cleanup;
- if (!(dom = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- 0,
- &oldDef)))
- goto cleanup;
- def = NULL;
- dom->persistent = 1;
-
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_DEFINED,
- !oldDef ?
- VIR_DOMAIN_EVENT_DEFINED_ADDED :
- VIR_DOMAIN_EVENT_DEFINED_UPDATED);
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- virDomainDefFree(def);
- virDomainDefFree(oldDef);
- if (dom)
- virObjectUnlock(dom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static virDomainPtr
-testDomainDefineXML(virConnectPtr conn, const char *xml)
-{
- return testDomainDefineXMLFlags(conn, xml, 0);
-}
-
-static char *testDomainGetMetadata(virDomainPtr dom,
- int type,
- const char *uri,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
- char *ret;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG, NULL);
-
- if (!(privdom = testDomObjFromDomain(dom)))
- return NULL;
-
- ret = virDomainObjGetMetadata(privdom, type, uri, flags);
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainSetMetadata(virDomainPtr dom,
- int type,
- const char *metadata,
- const char *key,
- const char *uri,
- unsigned int flags)
-{
- testDriverPtr privconn = dom->conn->privateData;
- virDomainObjPtr privdom;
- int ret;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG, -1);
-
- if (!(privdom = testDomObjFromDomain(dom)))
- return -1;
-
- ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
- privconn->caps, privconn->xmlopt,
- NULL, NULL, flags);
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-
-static int testNodeGetCellsFreeMemory(virConnectPtr conn,
- unsigned long long *freemems,
- int startCell, int maxCells)
-{
- testDriverPtr privconn = conn->privateData;
- int cell;
- size_t i;
- int ret = -1;
-
- testDriverLock(privconn);
- if (startCell > privconn->numCells) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("Range exceeds available cells"));
- goto cleanup;
- }
-
- for (cell = startCell, i = 0;
- (cell < privconn->numCells && i < maxCells);
- ++cell, ++i) {
- freemems[i] = privconn->cells[cell].mem;
- }
- ret = i;
-
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-#define TEST_NB_CPU_STATS 4
-
-static int
-testNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
- int cpuNum ATTRIBUTE_UNUSED,
- virNodeCPUStatsPtr params,
- int *nparams,
- unsigned int flags)
-{
- size_t i = 0;
-
- virCheckFlags(0, -1);
-
- if (params == NULL) {
- *nparams = TEST_NB_CPU_STATS;
- return 0;
- }
-
- for (i = 0; i < *nparams && i < 4; i++) {
- switch (i) {
- case 0:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_USER, 9797400000) < 0)
- return -1;
- break;
- case 1:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_KERNEL, 34678723400000) < 0)
- return -1;
- break;
- case 2:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_IDLE, 87264900000) < 0)
- return -1;
- break;
- case 3:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_IOWAIT, 763600000) < 0)
- return -1;
- break;
- }
- }
-
- *nparams = i;
- return 0;
-}
-
-static unsigned long long
-testNodeGetFreeMemory(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- unsigned int freeMem = 0;
- size_t i;
-
- testDriverLock(privconn);
-
- for (i = 0; i < privconn->numCells; i++)
- freeMem += privconn->cells[i].freeMem;
-
- testDriverUnlock(privconn);
- return freeMem;
-}
-
-static int
-testNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned int npages,
- unsigned int *pages ATTRIBUTE_UNUSED,
- int startCell ATTRIBUTE_UNUSED,
- unsigned int cellCount,
- unsigned long long *counts,
- unsigned int flags)
-{
- size_t i = 0, j = 0;
- int x = 6;
-
- virCheckFlags(0, -1);
-
- for (i = 0; i < cellCount; i++) {
- for (j = 0; j < npages; j++) {
- x = x * 2 + 7;
- counts[(i * npages) + j] = x;
- }
- }
-
- return 0;
-}
-
-static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Domain '%s' is already running"), domain->name);
- goto cleanup;
- }
-
- if (testDomainStartState(privconn, privdom,
- VIR_DOMAIN_RUNNING_BOOTED) < 0)
- goto cleanup;
- domain->id = privdom->def->id;
-
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testDomainCreate(virDomainPtr domain)
-{
- return testDomainCreateWithFlags(domain, 0);
-}
-
-static int testDomainUndefineFlags(virDomainPtr domain,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int nsnapshots;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
- VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (privdom->hasManagedSave &&
- !(flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("Refusing to undefine while domain managed "
- "save image exists"));
- goto cleanup;
- }
-
- /* Requiring an inactive VM is part of the documented API for
- * UNDEFINE_SNAPSHOTS_METADATA
- */
- if (!virDomainObjIsActive(privdom) &&
- (nsnapshots = virDomainSnapshotObjListNum(privdom->snapshots,
- NULL, 0))) {
- if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("cannot delete inactive domain with %d "
- "snapshots"),
- nsnapshots);
- goto cleanup;
- }
-
- /* There isn't actually anything to do, we are just emulating qemu
- * behavior here. */
- }
-
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_UNDEFINED,
- VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
- privdom->hasManagedSave = false;
-
- if (virDomainObjIsActive(privdom))
- privdom->persistent = 0;
- else
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainUndefine(virDomainPtr domain)
-{
- return testDomainUndefineFlags(domain, 0);
-}
-
-static int testDomainGetAutostart(virDomainPtr domain,
- int *autostart)
-{
- virDomainObjPtr privdom;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- *autostart = privdom->autostart;
-
- virDomainObjEndAPI(&privdom);
- return 0;
-}
-
-
-static int testDomainSetAutostart(virDomainPtr domain,
- int autostart)
-{
- virDomainObjPtr privdom;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- privdom->autostart = autostart ? 1 : 0;
-
- virDomainObjEndAPI(&privdom);
- return 0;
-}
-
-static char *testDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
- int *nparams)
-{
- char *type = NULL;
-
- if (nparams)
- *nparams = 1;
-
- ignore_value(VIR_STRDUP(type, "fair"));
-
- return type;
-}
-
-static int
-testDomainGetSchedulerParametersFlags(virDomainPtr domain,
- virTypedParameterPtr params,
- int *nparams,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (virTypedParameterAssign(params, VIR_DOMAIN_SCHEDULER_WEIGHT,
- VIR_TYPED_PARAM_UINT, 50) < 0)
- goto cleanup;
- /* XXX */
- /*params[0].value.ui = privdom->weight;*/
-
- *nparams = 1;
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetSchedulerParameters(virDomainPtr domain,
- virTypedParameterPtr params,
- int *nparams)
-{
- return testDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
-}
-
-static int
-testDomainSetSchedulerParametersFlags(virDomainPtr domain,
- virTypedParameterPtr params,
- int nparams,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
- int ret = -1;
- size_t i;
-
- virCheckFlags(0, -1);
- if (virTypedParamsValidate(params, nparams,
- VIR_DOMAIN_SCHEDULER_WEIGHT,
- VIR_TYPED_PARAM_UINT,
- NULL) < 0)
- return -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- for (i = 0; i < nparams; i++) {
- if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) {
- /* XXX */
- /*privdom->weight = params[i].value.ui;*/
- }
- }
-
- ret = 0;
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainSetSchedulerParameters(virDomainPtr domain,
- virTypedParameterPtr params,
- int nparams)
-{
- return testDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
-}
-
-static int testDomainBlockStats(virDomainPtr domain,
- const char *path,
- virDomainBlockStatsPtr stats)
-{
- virDomainObjPtr privdom;
- struct timeval tv;
- unsigned long long statbase;
- int ret = -1;
-
- if (!*path) {
- virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
- _("summary statistics are not supported yet"));
- return ret;
- }
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return ret;
-
- if (virDomainDiskIndexByName(privdom->def, path, false) < 0) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("invalid path: %s"), path);
- goto error;
- }
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportSystemError(errno,
- "%s", _("getting time of day"));
- goto error;
- }
-
- /* No significance to these numbers, just enough to mix it up*/
- statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
- stats->rd_req = statbase / 10;
- stats->rd_bytes = statbase / 20;
- stats->wr_req = statbase / 30;
- stats->wr_bytes = statbase / 40;
- stats->errs = tv.tv_sec / 2;
-
- ret = 0;
- error:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainInterfaceStats(virDomainPtr domain,
- const char *path,
- virDomainInterfaceStatsPtr stats)
-{
- virDomainObjPtr privdom;
- struct timeval tv;
- unsigned long long statbase;
- size_t i;
- int found = 0, ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- for (i = 0; i < privdom->def->nnets; i++) {
- if (privdom->def->nets[i]->ifname &&
- STREQ(privdom->def->nets[i]->ifname, path)) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("invalid path, '%s' is not a known interface"), path);
- goto error;
- }
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportSystemError(errno,
- "%s", _("getting time of day"));
- goto error;
- }
-
- /* No significance to these numbers, just enough to mix it up*/
- statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
- stats->rx_bytes = statbase / 10;
- stats->rx_packets = statbase / 100;
- stats->rx_errs = tv.tv_sec / 1;
- stats->rx_drop = tv.tv_sec / 2;
- stats->tx_bytes = statbase / 20;
- stats->tx_packets = statbase / 110;
- stats->tx_errs = tv.tv_sec / 3;
- stats->tx_drop = tv.tv_sec / 4;
-
- ret = 0;
- error:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-
-static virNetworkPtr testNetworkLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkObjPtr net;
- virNetworkPtr ret = NULL;
-
- net = virNetworkObjFindByUUID(privconn->networks, uuid);
- if (net == NULL) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-static virNetworkPtr testNetworkLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkObjPtr net;
- virNetworkPtr ret = NULL;
-
- net = virNetworkObjFindByName(privconn->networks, name);
- if (net == NULL) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-
-static int testConnectNumOfNetworks(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numActive;
-
- numActive = virNetworkObjListNumOfNetworks(privconn->networks,
- true, NULL, conn);
- return numActive;
-}
-
-static int testConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
- testDriverPtr privconn = conn->privateData;
- int n;
-
- n = virNetworkObjListGetNames(privconn->networks,
- true, names, nnames, NULL, conn);
- return n;
-}
-
-static int testConnectNumOfDefinedNetworks(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numInactive;
-
- numInactive = virNetworkObjListNumOfNetworks(privconn->networks,
- false, NULL, conn);
- return numInactive;
-}
-
-static int testConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
- testDriverPtr privconn = conn->privateData;
- int n;
-
- n = virNetworkObjListGetNames(privconn->networks,
- false, names, nnames, NULL, conn);
- return n;
-}
-
-static int
-testConnectListAllNetworks(virConnectPtr conn,
- virNetworkPtr **nets,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
-
- virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
-
- return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags);
-}
-
-static int testNetworkIsActive(virNetworkPtr net)
-{
- testDriverPtr privconn = net->conn->privateData;
- virNetworkObjPtr obj;
- int ret = -1;
-
- obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
- if (!obj) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
- ret = virNetworkObjIsActive(obj);
-
- cleanup:
- virNetworkObjEndAPI(&obj);
- return ret;
-}
-
-static int testNetworkIsPersistent(virNetworkPtr net)
-{
- testDriverPtr privconn = net->conn->privateData;
- virNetworkObjPtr obj;
- int ret = -1;
-
- obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
- if (!obj) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
- ret = obj->persistent;
-
- cleanup:
- virNetworkObjEndAPI(&obj);
- return ret;
-}
-
-
-static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkDefPtr def;
- virNetworkObjPtr net = NULL;
- virNetworkPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- if ((def = virNetworkDefParseString(xml)) == NULL)
- goto cleanup;
-
- if (!(net = virNetworkAssignDef(privconn->networks, def,
- VIR_NETWORK_OBJ_LIST_ADD_LIVE |
- VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
- goto cleanup;
- def = NULL;
- net->active = 1;
-
- event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
- VIR_NETWORK_EVENT_STARTED,
- 0);
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkDefFree(def);
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-static
-virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkDefPtr def;
- virNetworkObjPtr net = NULL;
- virNetworkPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- if ((def = virNetworkDefParseString(xml)) == NULL)
- goto cleanup;
-
- if (!(net = virNetworkAssignDef(privconn->networks, def, 0)))
- goto cleanup;
- def = NULL;
-
- event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
- VIR_NETWORK_EVENT_DEFINED,
- 0);
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkDefFree(def);
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-static int testNetworkUndefine(virNetworkPtr network)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
-
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virNetworkObjIsActive(privnet)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("Network '%s' is still running"), network->name);
- goto cleanup;
- }
-
- event = virNetworkEventLifecycleNew(network->name, network->uuid,
- VIR_NETWORK_EVENT_UNDEFINED,
- 0);
-
- virNetworkRemoveInactive(privconn->networks, privnet);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static int
-testNetworkUpdate(virNetworkPtr net,
- unsigned int command,
- unsigned int section,
- int parentIndex,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = net->conn->privateData;
- virNetworkObjPtr network = NULL;
- int isActive, ret = -1;
-
- virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
- VIR_NETWORK_UPDATE_AFFECT_CONFIG,
- -1);
-
- network = virNetworkObjFindByUUID(privconn->networks, net->uuid);
- if (!network) {
- virReportError(VIR_ERR_NO_NETWORK,
- "%s", _("no network with matching uuid"));
- goto cleanup;
- }
-
- /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
- * is active, else change CONFIG
- */
- isActive = virNetworkObjIsActive(network);
- if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE
- | VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
- VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
- if (isActive)
- flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
- else
- flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
- }
-
- /* update the network config in memory/on disk */
- if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0)
- goto cleanup;
-
- ret = 0;
- cleanup:
- virNetworkObjEndAPI(&network);
- return ret;
-}
-
-static int testNetworkCreate(virNetworkPtr network)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virNetworkObjIsActive(privnet)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("Network '%s' is already running"), network->name);
- goto cleanup;
- }
-
- privnet->active = 1;
- event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
- VIR_NETWORK_EVENT_STARTED,
- 0);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static int testNetworkDestroy(virNetworkPtr network)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privnet->active = 0;
- event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
- VIR_NETWORK_EVENT_STOPPED,
- 0);
- if (!privnet->persistent)
- virNetworkRemoveInactive(privconn->networks, privnet);
-
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static char *testNetworkGetXMLDesc(virNetworkPtr network,
- unsigned int flags)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- ret = virNetworkDefFormat(privnet->def, flags);
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static char *testNetworkGetBridgeName(virNetworkPtr network) {
- testDriverPtr privconn = network->conn->privateData;
- char *bridge = NULL;
- virNetworkObjPtr privnet;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!(privnet->def->bridge)) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("network '%s' does not have a bridge name."),
- privnet->def->name);
- goto cleanup;
- }
-
- ignore_value(VIR_STRDUP(bridge, privnet->def->bridge));
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return bridge;
-}
-
-static int testNetworkGetAutostart(virNetworkPtr network,
- int *autostart)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- *autostart = privnet->autostart;
- ret = 0;
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static int testNetworkSetAutostart(virNetworkPtr network,
- int autostart)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privnet->autostart = autostart ? 1 : 0;
- ret = 0;
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-
-/*
- * Physical host interface routines
- */
-
-
-static int testConnectNumOfInterfaces(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- int count = 0;
-
- testDriverLock(privconn);
- for (i = 0; (i < privconn->ifaces.count); i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (virInterfaceObjIsActive(privconn->ifaces.objs[i]))
- count++;
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
- return count;
-}
-
-static int testConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
- if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- goto error;
- }
- }
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static int testConnectNumOfDefinedInterfaces(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- int count = 0;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->ifaces.count; i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (!virInterfaceObjIsActive(privconn->ifaces.objs[i]))
- count++;
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
- return count;
-}
-
-static int testConnectListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (!virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
- if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- goto error;
- }
- }
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static virInterfacePtr testInterfaceLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virInterfaceObjPtr iface;
- virInterfacePtr ret = NULL;
-
- testDriverLock(privconn);
- iface = virInterfaceFindByName(&privconn->ifaces, name);
- testDriverUnlock(privconn);
-
- if (iface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
- if (iface)
- virInterfaceObjUnlock(iface);
- return ret;
-}
-
-static virInterfacePtr testInterfaceLookupByMACString(virConnectPtr conn,
- const char *mac)
-{
- testDriverPtr privconn = conn->privateData;
- virInterfaceObjPtr iface;
- int ifacect;
- virInterfacePtr ret = NULL;
-
- testDriverLock(privconn);
- ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1);
- testDriverUnlock(privconn);
-
- if (ifacect == 0) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- if (ifacect > 1) {
- virReportError(VIR_ERR_MULTIPLE_INTERFACES, NULL);
- goto cleanup;
- }
-
- ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
- if (iface)
- virInterfaceObjUnlock(iface);
- return ret;
-}
-
-static int testInterfaceIsActive(virInterfacePtr iface)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr obj;
- int ret = -1;
-
- testDriverLock(privconn);
- obj = virInterfaceFindByName(&privconn->ifaces, iface->name);
- testDriverUnlock(privconn);
- if (!obj) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
- ret = virInterfaceObjIsActive(obj);
-
- cleanup:
- if (obj)
- virInterfaceObjUnlock(obj);
- return ret;
-}
-
-static int testInterfaceChangeBegin(virConnectPtr conn,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- if (privconn->transaction_running) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("there is another transaction running."));
- goto cleanup;
- }
-
- privconn->transaction_running = true;
-
- if (virInterfaceObjListClone(&privconn->ifaces,
- &privconn->backupIfaces) < 0)
- goto cleanup;
-
- ret = 0;
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceChangeCommit(virConnectPtr conn,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
-
- if (!privconn->transaction_running) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("no transaction running, "
- "nothing to be committed."));
- goto cleanup;
- }
-
- virInterfaceObjListFree(&privconn->backupIfaces);
- privconn->transaction_running = false;
-
- ret = 0;
-
- cleanup:
- testDriverUnlock(privconn);
-
- return ret;
-}
-
-static int testInterfaceChangeRollback(virConnectPtr conn,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
-
- if (!privconn->transaction_running) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("no transaction running, "
- "nothing to rollback."));
- goto cleanup;
- }
-
- virInterfaceObjListFree(&privconn->ifaces);
- privconn->ifaces.count = privconn->backupIfaces.count;
- privconn->ifaces.objs = privconn->backupIfaces.objs;
- privconn->backupIfaces.count = 0;
- privconn->backupIfaces.objs = NULL;
-
- privconn->transaction_running = false;
-
- ret = 0;
-
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-static char *testInterfaceGetXMLDesc(virInterfacePtr iface,
- unsigned int flags)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
- testDriverUnlock(privconn);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, __FUNCTION__);
- goto cleanup;
- }
-
- ret = virInterfaceDefFormat(privinterface->def);
-
- cleanup:
- if (privinterface)
- virInterfaceObjUnlock(privinterface);
- return ret;
-}
-
-
-static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virInterfaceDefPtr def;
- virInterfaceObjPtr iface = NULL;
- virInterfacePtr ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- if ((def = virInterfaceDefParseString(xmlStr)) == NULL)
- goto cleanup;
-
- if ((iface = virInterfaceAssignDef(&privconn->ifaces, def)) == NULL)
- goto cleanup;
- def = NULL;
-
- ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
- virInterfaceDefFree(def);
- if (iface)
- virInterfaceObjUnlock(iface);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceUndefine(virInterfacePtr iface)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- int ret = -1;
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- virInterfaceRemove(&privconn->ifaces,
- privinterface);
- ret = 0;
-
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceCreate(virInterfacePtr iface,
- unsigned int flags)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- if (privinterface->active != 0) {
- virReportError(VIR_ERR_OPERATION_INVALID, NULL);
- goto cleanup;
- }
-
- privinterface->active = 1;
- ret = 0;
-
- cleanup:
- if (privinterface)
- virInterfaceObjUnlock(privinterface);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceDestroy(virInterfacePtr iface,
- unsigned int flags)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- if (privinterface->active == 0) {
- virReportError(VIR_ERR_OPERATION_INVALID, NULL);
- goto cleanup;
- }
-
- privinterface->active = 0;
- ret = 0;
-
- cleanup:
- if (privinterface)
- virInterfaceObjUnlock(privinterface);
- testDriverUnlock(privconn);
- return ret;
-}
-
-
-
-/*
- * Storage Driver routines
- */
-
-
-static int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool)
-{
-
- pool->def->capacity = defaultPoolCap;
- pool->def->allocation = defaultPoolAlloc;
- pool->def->available = defaultPoolCap - defaultPoolAlloc;
-
- return VIR_STRDUP(pool->configFile, "");
-}
-
-
-static virStoragePoolPtr
-testStoragePoolLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolObjPtr pool;
- virStoragePoolPtr ret = NULL;
-
- testDriverLock(privconn);
- pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
- testDriverUnlock(privconn);
-
- if (pool == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- if (pool)
- virStoragePoolObjUnlock(pool);
- return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolObjPtr pool;
- virStoragePoolPtr ret = NULL;
-
- testDriverLock(privconn);
- pool = virStoragePoolObjFindByName(&privconn->pools, name);
- testDriverUnlock(privconn);
-
- if (pool == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- if (pool)
- virStoragePoolObjUnlock(pool);
- return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolLookupByVolume(virStorageVolPtr vol)
-{
- return testStoragePoolLookupByName(vol->conn, vol->pool);
-}
-
-static int
-testConnectNumOfStoragePools(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numActive = 0;
- size_t i;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++)
- if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
- numActive++;
- testDriverUnlock(privconn);
-
- return numActive;
-}
-
-static int
-testConnectListStoragePools(virConnectPtr conn,
- char **const names,
- int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; i < privconn->pools.count && n < nnames; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
- VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- goto error;
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static int
-testConnectNumOfDefinedStoragePools(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numInactive = 0;
- size_t i;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
- numInactive++;
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return numInactive;
-}
-
-static int
-testConnectListDefinedStoragePools(virConnectPtr conn,
- char **const names,
- int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; i < privconn->pools.count && n < nnames; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
- VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- goto error;
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static int
-testConnectListAllStoragePools(virConnectPtr conn,
- virStoragePoolPtr **pools,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1);
-
- testDriverLock(privconn);
- ret = virStoragePoolObjListExport(conn, privconn->pools, pools,
- NULL, flags);
- testDriverUnlock(privconn);
-
- return ret;
-}
-
-static int testStoragePoolIsActive(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr obj;
- int ret = -1;
-
- testDriverLock(privconn);
- obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
- testDriverUnlock(privconn);
- if (!obj) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
- ret = virStoragePoolObjIsActive(obj);
-
- cleanup:
- if (obj)
- virStoragePoolObjUnlock(obj);
- return ret;
-}
-
-static int testStoragePoolIsPersistent(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr obj;
- int ret = -1;
-
- testDriverLock(privconn);
- obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
- testDriverUnlock(privconn);
- if (!obj) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
- ret = obj->configFile ? 1 : 0;
-
- cleanup:
- if (obj)
- virStoragePoolObjUnlock(obj);
- return ret;
-}
-
-
-
-static int
-testStoragePoolCreate(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
-
- privpool->active = 1;
-
- event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
- VIR_STORAGE_POOL_EVENT_STARTED,
- 0);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testConnectFindStoragePoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char *type,
- const char *srcSpec,
- unsigned int flags)
-{
- virStoragePoolSourcePtr source = NULL;
- int pool_type;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- pool_type = virStoragePoolTypeFromString(type);
- if (!pool_type) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown storage pool type %s"), type);
- goto cleanup;
- }
-
- if (srcSpec) {
- source = virStoragePoolDefParseSourceString(srcSpec, pool_type);
- if (!source)
- goto cleanup;
- }
-
- switch (pool_type) {
-
- case VIR_STORAGE_POOL_LOGICAL:
- ignore_value(VIR_STRDUP(ret, defaultPoolSourcesLogicalXML));
- break;
-
- case VIR_STORAGE_POOL_NETFS:
- if (!source || !source->hosts[0].name) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("hostname must be specified for netfs sources"));
- goto cleanup;
- }
-
- ignore_value(virAsprintf(&ret, defaultPoolSourcesNetFSXML,
- source->hosts[0].name));
- break;
-
- default:
- virReportError(VIR_ERR_NO_SUPPORT,
- _("pool type '%s' does not support source discovery"), type);
- }
-
- cleanup:
- virStoragePoolSourceFree(source);
- return ret;
-}
-
-
-static virStoragePoolPtr
-testStoragePoolCreateXML(virConnectPtr conn,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolDefPtr def;
- virStoragePoolObjPtr pool = NULL;
- virStoragePoolPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- if (!(def = virStoragePoolDefParseString(xml)))
- goto cleanup;
-
- pool = virStoragePoolObjFindByUUID(&privconn->pools, def->uuid);
- if (!pool)
- pool = virStoragePoolObjFindByName(&privconn->pools, def->name);
- if (pool) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("storage pool already exists"));
- goto cleanup;
- }
-
- if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
- goto cleanup;
- def = NULL;
-
- if (testStoragePoolObjSetDefaults(pool) == -1) {
- virStoragePoolObjRemove(&privconn->pools, pool);
- pool = NULL;
- goto cleanup;
- }
- pool->active = 1;
-
- event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
- VIR_STORAGE_POOL_EVENT_STARTED,
- 0);
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- virStoragePoolDefFree(def);
- testObjectEventQueue(privconn, event);
- if (pool)
- virStoragePoolObjUnlock(pool);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolDefineXML(virConnectPtr conn,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolDefPtr def;
- virStoragePoolObjPtr pool = NULL;
- virStoragePoolPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- if (!(def = virStoragePoolDefParseString(xml)))
- goto cleanup;
-
- def->capacity = defaultPoolCap;
- def->allocation = defaultPoolAlloc;
- def->available = defaultPoolCap - defaultPoolAlloc;
-
- if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
- goto cleanup;
- def = NULL;
-
- event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
- VIR_STORAGE_POOL_EVENT_DEFINED,
- 0);
-
- if (testStoragePoolObjSetDefaults(pool) == -1) {
- virStoragePoolObjRemove(&privconn->pools, pool);
- pool = NULL;
- goto cleanup;
- }
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- virStoragePoolDefFree(def);
- testObjectEventQueue(privconn, event);
- if (pool)
- virStoragePoolObjUnlock(pool);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int
-testStoragePoolUndefine(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
-
- event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
- VIR_STORAGE_POOL_EVENT_UNDEFINED,
- 0);
-
- virStoragePoolObjRemove(&privconn->pools, privpool);
- privpool = NULL;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- testObjectEventQueue(privconn, event);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int
-testStoragePoolBuild(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolDestroy(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privpool->active = 0;
- event = virStoragePoolEventLifecycleNew(privpool->def->name, privpool->def->uuid,
- VIR_STORAGE_POOL_EVENT_STOPPED,
- 0);
-
- if (privpool->configFile == NULL) {
- virStoragePoolObjRemove(&privconn->pools, privpool);
- privpool = NULL;
- }
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- testDriverUnlock(privconn);
- return ret;
-}
-
-
-static int
-testStoragePoolDelete(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
-
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolRefresh(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- event = virStoragePoolEventRefreshNew(pool->name, pool->uuid);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolGetInfo(virStoragePoolPtr pool,
- virStoragePoolInfoPtr info)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- memset(info, 0, sizeof(virStoragePoolInfo));
- if (privpool->active)
- info->state = VIR_STORAGE_POOL_RUNNING;
- else
- info->state = VIR_STORAGE_POOL_INACTIVE;
- info->capacity = privpool->def->capacity;
- info->allocation = privpool->def->allocation;
- info->available = privpool->def->available;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testStoragePoolGetXMLDesc(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- ret = virStoragePoolDefFormat(privpool->def);
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStoragePoolGetAutostart(virStoragePoolPtr pool,
- int *autostart)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!privpool->configFile) {
- *autostart = 0;
- } else {
- *autostart = privpool->autostart;
- }
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStoragePoolSetAutostart(virStoragePoolPtr pool,
- int autostart)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!privpool->configFile) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("pool has no config file"));
- goto cleanup;
- }
-
- autostart = (autostart != 0);
- privpool->autostart = autostart;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolNumOfVolumes(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- ret = privpool->volumes.count;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStoragePoolListVolumes(virStoragePoolPtr pool,
- char **const names,
- int maxnames)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- size_t i = 0;
- int n = 0;
-
- memset(names, 0, maxnames * sizeof(*names));
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
- if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0)
- goto cleanup;
- }
-
- virStoragePoolObjUnlock(privpool);
- return n;
-
- cleanup:
- for (n = 0; n < maxnames; n++)
- VIR_FREE(names[i]);
-
- memset(names, 0, maxnames * sizeof(*names));
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return -1;
-}
-
-static int
-testStoragePoolListAllVolumes(virStoragePoolPtr obj,
- virStorageVolPtr **vols,
- unsigned int flags)
-{
- testDriverPtr privconn = obj->conn->privateData;
- virStoragePoolObjPtr pool;
- size_t i;
- virStorageVolPtr *tmp_vols = NULL;
- virStorageVolPtr vol = NULL;
- int nvols = 0;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- pool = virStoragePoolObjFindByUUID(&privconn->pools, obj->uuid);
- testDriverUnlock(privconn);
-
- if (!pool) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, "%s",
- _("no storage pool with matching uuid"));
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(pool)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("storage pool is not active"));
- goto cleanup;
- }
-
- /* Just returns the volumes count */
- if (!vols) {
- ret = pool->volumes.count;
- goto cleanup;
- }
-
- if (VIR_ALLOC_N(tmp_vols, pool->volumes.count + 1) < 0)
- goto cleanup;
-
- 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,
- NULL, NULL)))
- goto cleanup;
- tmp_vols[nvols++] = vol;
- }
-
- *vols = tmp_vols;
- tmp_vols = NULL;
- ret = nvols;
-
- cleanup:
- if (tmp_vols) {
- for (i = 0; i < nvols; i++) {
- if (tmp_vols[i])
- virStorageVolFree(tmp_vols[i]);
- }
- VIR_FREE(tmp_vols);
- }
-
- if (pool)
- virStoragePoolObjUnlock(pool);
-
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolLookupByName(virStoragePoolPtr pool,
- const char *name ATTRIBUTE_UNUSED)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- virStorageVolPtr ret = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, name);
-
- if (!privvol) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"), name);
- goto cleanup;
- }
-
- ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key,
- NULL, NULL);
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static virStorageVolPtr
-testStorageVolLookupByKey(virConnectPtr conn,
- const char *key)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- virStorageVolPtr ret = NULL;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
- virStorageVolDefPtr privvol =
- virStorageVolDefFindByKey(privconn->pools.objs[i], key);
-
- if (privvol) {
- ret = virGetStorageVol(conn,
- privconn->pools.objs[i]->def->name,
- privvol->name,
- privvol->key,
- NULL, NULL);
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- break;
- }
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- if (!ret)
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching key '%s'"), key);
-
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolLookupByPath(virConnectPtr conn,
- const char *path)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- virStorageVolPtr ret = NULL;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
- virStorageVolDefPtr privvol =
- virStorageVolDefFindByPath(privconn->pools.objs[i], path);
-
- if (privvol) {
- ret = virGetStorageVol(conn,
- privconn->pools.objs[i]->def->name,
- privvol->name,
- privvol->key,
- NULL, NULL);
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- break;
- }
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- if (!ret)
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching path '%s'"), path);
-
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolCreateXML(virStoragePoolPtr pool,
- const char *xmldesc,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol = NULL;
- virStorageVolPtr ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
- if (privvol == NULL)
- goto cleanup;
-
- if (virStorageVolDefFindByName(privpool, privvol->name)) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("storage vol already exists"));
- goto cleanup;
- }
-
- /* Make sure enough space */
- if ((privpool->def->allocation + privvol->target.allocation) >
- privpool->def->capacity) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Not enough free space in pool for volume '%s'"),
- privvol->name);
- goto cleanup;
- }
-
- if (virAsprintf(&privvol->target.path, "%s/%s",
- privpool->def->target.path,
- privvol->name) == -1)
- goto cleanup;
-
- if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
- VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
- privpool->volumes.count, privvol) < 0)
- goto cleanup;
-
- privpool->def->allocation += privvol->target.allocation;
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key,
- NULL, NULL);
- privvol = NULL;
-
- cleanup:
- virStorageVolDefFree(privvol);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolCreateXMLFrom(virStoragePoolPtr pool,
- const char *xmldesc,
- virStorageVolPtr clonevol,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol = NULL, origvol = NULL;
- virStorageVolPtr ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
- if (privvol == NULL)
- goto cleanup;
-
- if (virStorageVolDefFindByName(privpool, privvol->name)) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("storage vol already exists"));
- goto cleanup;
- }
-
- origvol = virStorageVolDefFindByName(privpool, clonevol->name);
- if (!origvol) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- clonevol->name);
- goto cleanup;
- }
-
- /* Make sure enough space */
- if ((privpool->def->allocation + privvol->target.allocation) >
- privpool->def->capacity) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Not enough free space in pool for volume '%s'"),
- privvol->name);
- goto cleanup;
- }
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- if (virAsprintf(&privvol->target.path, "%s/%s",
- privpool->def->target.path,
- privvol->name) == -1)
- goto cleanup;
-
- if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
- VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
- privpool->volumes.count, privvol) < 0)
- goto cleanup;
-
- privpool->def->allocation += privvol->target.allocation;
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key,
- NULL, NULL);
- privvol = NULL;
-
- cleanup:
- virStorageVolDefFree(privvol);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStorageVolDelete(virStorageVolPtr vol,
- unsigned int flags)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- size_t i;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
-
- privpool->def->allocation -= privvol->target.allocation;
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- for (i = 0; i < privpool->volumes.count; i++) {
- if (privpool->volumes.objs[i] == privvol) {
- virStorageVolDefFree(privvol);
-
- VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count);
- break;
- }
- }
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int testStorageVolumeTypeForPool(int pooltype)
-{
-
- switch (pooltype) {
- case VIR_STORAGE_POOL_DIR:
- case VIR_STORAGE_POOL_FS:
- case VIR_STORAGE_POOL_NETFS:
- return VIR_STORAGE_VOL_FILE;
- default:
- return VIR_STORAGE_VOL_BLOCK;
- }
-}
-
-static int
-testStorageVolGetInfo(virStorageVolPtr vol,
- virStorageVolInfoPtr info)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
- memset(info, 0, sizeof(*info));
- info->type = testStorageVolumeTypeForPool(privpool->def->type);
- info->capacity = privvol->target.capacity;
- info->allocation = privvol->target.allocation;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testStorageVolGetXMLDesc(virStorageVolPtr vol,
- unsigned int flags)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
- ret = virStorageVolDefFormat(privpool->def, privvol);
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testStorageVolGetPath(virStorageVolPtr vol)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- char *ret = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
- ignore_value(VIR_STRDUP(ret, privvol->target.path));
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-/* Node device implementations */
-
-static int
-testNodeNumOfDevices(virConnectPtr conn,
- const char *cap,
- unsigned int flags)
-{
- testDriverPtr driver = conn->privateData;
- int ndevs = 0;
- size_t i;
-
- virCheckFlags(0, -1);
-
- testDriverLock(driver);
- for (i = 0; i < driver->devs.count; i++)
- if ((cap == NULL) ||
- virNodeDeviceHasCap(driver->devs.objs[i], cap))
- ++ndevs;
- testDriverUnlock(driver);
-
- return ndevs;
-}
-
-static int
-testNodeListDevices(virConnectPtr conn,
- const char *cap,
- char **const names,
- int maxnames,
- unsigned int flags)
-{
- testDriverPtr driver = conn->privateData;
- int ndevs = 0;
- size_t i;
-
- virCheckFlags(0, -1);
-
- testDriverLock(driver);
- for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) {
- virNodeDeviceObjLock(driver->devs.objs[i]);
- if (cap == NULL ||
- virNodeDeviceHasCap(driver->devs.objs[i], cap)) {
- if (VIR_STRDUP(names[ndevs++], driver->devs.objs[i]->def->name) < 0) {
- virNodeDeviceObjUnlock(driver->devs.objs[i]);
- goto failure;
- }
- }
- virNodeDeviceObjUnlock(driver->devs.objs[i]);
- }
- testDriverUnlock(driver);
-
- return ndevs;
-
- failure:
- testDriverUnlock(driver);
- --ndevs;
- while (--ndevs >= 0)
- VIR_FREE(names[ndevs]);
- return -1;
-}
-
-static virNodeDevicePtr
-testNodeDeviceLookupByName(virConnectPtr conn, const char *name)
-{
- testDriverPtr driver = conn->privateData;
- virNodeDeviceObjPtr obj;
- virNodeDevicePtr ret = NULL;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- name);
- goto cleanup;
- }
-
- ret = virGetNodeDevice(conn, name);
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-static char *
-testNodeDeviceGetXMLDesc(virNodeDevicePtr dev,
- unsigned int flags)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- ret = virNodeDeviceDefFormat(obj->def);
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-static char *
-testNodeDeviceGetParent(virNodeDevicePtr dev)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- char *ret = NULL;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- if (obj->def->parent) {
- ignore_value(VIR_STRDUP(ret, obj->def->parent));
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("no parent for this device"));
- }
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-
-static int
-testNodeDeviceNumOfCaps(virNodeDevicePtr dev)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- virNodeDevCapsDefPtr caps;
- int ncaps = 0;
- int ret = -1;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- for (caps = obj->def->caps; caps; caps = caps->next)
- ++ncaps;
- ret = ncaps;
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-
-static int
-testNodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- virNodeDevCapsDefPtr caps;
- int ncaps = 0;
- int ret = -1;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) {
- if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps->data.type)) < 0)
- goto cleanup;
- }
- ret = ncaps;
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- if (ret == -1) {
- --ncaps;
- while (--ncaps >= 0)
- VIR_FREE(names[ncaps]);
- }
- return ret;
-}
-
-static virNodeDevicePtr
-testNodeDeviceCreateXML(virConnectPtr conn,
- const char *xmlDesc,
- unsigned int flags)
-{
- testDriverPtr driver = conn->privateData;
- virNodeDeviceDefPtr def = NULL;
- virNodeDeviceObjPtr obj = NULL;
- char *wwnn = NULL, *wwpn = NULL;
- int parent_host = -1;
- virNodeDevicePtr dev = NULL;
- virNodeDevCapsDefPtr caps;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(driver);
-
- def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, NULL);
- if (def == NULL)
- goto cleanup;
-
- /* We run these next two simply for validation */
- if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1)
- goto cleanup;
-
- if (virNodeDeviceGetParentHost(&driver->devs,
- def->name,
- def->parent,
- &parent_host) == -1) {
- goto cleanup;
- }
-
- /* 'name' is supposed to be filled in by the node device backend, which
- * we don't have. Use WWPN instead. */
- VIR_FREE(def->name);
- if (VIR_STRDUP(def->name, wwpn) < 0)
- goto cleanup;
-
- /* Fill in a random 'host' and 'unique_id' value,
- * since this would also come from the backend */
- caps = def->caps;
- while (caps) {
- if (caps->data.type != VIR_NODE_DEV_CAP_SCSI_HOST)
- continue;
-
- caps->data.scsi_host.host = virRandomBits(10);
- caps->data.scsi_host.unique_id = 2;
- caps = caps->next;
- }
-
-
- if (!(obj = virNodeDeviceAssignDef(&driver->devs, def)))
- goto cleanup;
- virNodeDeviceObjUnlock(obj);
-
- event = virNodeDeviceEventLifecycleNew(def->name,
- VIR_NODE_DEVICE_EVENT_CREATED,
- 0);
-
- dev = virGetNodeDevice(conn, def->name);
- def = NULL;
- cleanup:
- testDriverUnlock(driver);
- virNodeDeviceDefFree(def);
- testObjectEventQueue(driver, event);
- VIR_FREE(wwnn);
- VIR_FREE(wwpn);
- return dev;
-}
-
-static int
-testNodeDeviceDestroy(virNodeDevicePtr dev)
-{
- int ret = 0;
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj = NULL;
- char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
- int parent_host = -1;
- virObjectEventPtr event = NULL;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto out;
- }
-
- if (virNodeDeviceGetWWNs(obj->def, &wwnn, &wwpn) == -1)
- goto out;
-
- if (VIR_STRDUP(parent_name, obj->def->parent) < 0)
- goto out;
-
- /* virNodeDeviceGetParentHost will cause the device object's lock to be
- * taken, so we have to dup the parent's name and drop the lock
- * before calling it. We don't need the reference to the object
- * any more once we have the parent's name. */
- virNodeDeviceObjUnlock(obj);
-
- /* We do this just for basic validation */
- if (virNodeDeviceGetParentHost(&driver->devs,
- dev->name,
- parent_name,
- &parent_host) == -1) {
- obj = NULL;
- goto out;
- }
-
- event = virNodeDeviceEventLifecycleNew(dev->name,
- VIR_NODE_DEVICE_EVENT_DELETED,
- 0);
-
- virNodeDeviceObjLock(obj);
- virNodeDeviceObjRemove(&driver->devs, &obj);
-
- out:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- testObjectEventQueue(driver, event);
- VIR_FREE(parent_name);
- VIR_FREE(wwnn);
- VIR_FREE(wwpn);
- return ret;
-}
-
-
-/* Domain event implementations */
-static int
-testConnectDomainEventRegister(virConnectPtr conn,
- virConnectDomainEventCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virDomainEventStateRegister(conn, driver->eventState,
- callback, opaque, freecb) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static int
-testConnectDomainEventDeregister(virConnectPtr conn,
- virConnectDomainEventCallback callback)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virDomainEventStateDeregister(conn, driver->eventState,
- callback) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static int
-testConnectDomainEventRegisterAny(virConnectPtr conn,
- virDomainPtr dom,
- int eventID,
- virConnectDomainEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virDomainEventStateRegisterID(conn, driver->eventState,
- dom, eventID,
- callback, opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectDomainEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static int
-testConnectNetworkEventRegisterAny(virConnectPtr conn,
- virNetworkPtr net,
- int eventID,
- virConnectNetworkEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virNetworkEventStateRegisterID(conn, driver->eventState,
- net, eventID, callback,
- opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectNetworkEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectStoragePoolEventRegisterAny(virConnectPtr conn,
- virStoragePoolPtr pool,
- int eventID,
- virConnectStoragePoolEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virStoragePoolEventStateRegisterID(conn, driver->eventState,
- pool, eventID, callback,
- opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectStoragePoolEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
- virNodeDevicePtr dev,
- int eventID,
- virConnectNodeDeviceEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virNodeDeviceEventStateRegisterID(conn, driver->eventState,
- dev, eventID, callback,
- opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int testConnectListAllDomains(virConnectPtr conn,
- virDomainPtr **domains,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
-
- virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
-
- return virDomainObjListExport(privconn->domains, conn, domains,
- NULL, flags);
-}
-
-static int
-testNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned char **cpumap,
- unsigned int *online,
- unsigned int flags)
-{
- virCheckFlags(0, -1);
-
- if (cpumap) {
- if (VIR_ALLOC_N(*cpumap, 1) < 0)
- return -1;
- *cpumap[0] = 0x15;
- }
-
- if (online)
- *online = 3;
-
- return 8;
-}
-
-static char *
-testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED,
- virStreamPtr st,
- unsigned int screen ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- if (VIR_STRDUP(ret, "image/png") < 0)
- return NULL;
-
- if (virFDStreamOpenFile(st, PKGDATADIR "/libvirtLogo.png", 0, 0, O_RDONLY) < 0)
- VIR_FREE(ret);
-
- return ret;
-}
-
-static int
-testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char *arch,
- char ***models,
- unsigned int flags)
-{
- virCheckFlags(0, -1);
- return cpuGetModels(arch, models);
-}
-
-static int
-testDomainManagedSave(virDomainPtr dom, unsigned int flags)
-{
- testDriverPtr privconn = dom->conn->privateData;
- virDomainObjPtr vm = NULL;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
- VIR_DOMAIN_SAVE_RUNNING |
- VIR_DOMAIN_SAVE_PAUSED, -1);
-
- if (!(vm = testDomObjFromDomain(dom)))
- return -1;
-
- if (!virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
-
- if (!vm->persistent) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot do managed save for transient domain"));
- goto cleanup;
- }
-
- testDomainShutdownState(dom, vm, VIR_DOMAIN_SHUTOFF_SAVED);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SAVED);
- vm->hasManagedSave = true;
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&vm);
- testObjectEventQueue(privconn, event);
-
- return ret;
-}
-
-
-static int
-testDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
-{
- virDomainObjPtr vm;
- int ret;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromDomain(dom)))
- return -1;
-
- ret = vm->hasManagedSave;
-
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
-{
- virDomainObjPtr vm;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromDomain(dom)))
- return -1;
-
- vm->hasManagedSave = false;
-
- virDomainObjEndAPI(&vm);
- return 0;
-}
-
-
-/*
- * Snapshot APIs
- */
-
-static virDomainSnapshotObjPtr
-testSnapObjFromName(virDomainObjPtr vm,
- const char *name)
-{
- virDomainSnapshotObjPtr snap = NULL;
- snap = virDomainSnapshotFindByName(vm->snapshots, name);
- if (!snap)
- virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
- _("no domain snapshot with matching name '%s'"),
- name);
- return snap;
-}
-
-static virDomainSnapshotObjPtr
-testSnapObjFromSnapshot(virDomainObjPtr vm,
- virDomainSnapshotPtr snapshot)
-{
- return testSnapObjFromName(vm, snapshot->name);
-}
-
-static virDomainObjPtr
-testDomObjFromSnapshot(virDomainSnapshotPtr snapshot)
-{
- return testDomObjFromDomain(snapshot->domain);
-}
-
-static int
-testDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int n;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
-
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotListNames(virDomainPtr domain,
- char **names,
- int nameslen,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int n;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
- flags);
-
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainListAllSnapshots(virDomainPtr domain,
- virDomainSnapshotPtr **snaps,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int n;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
-
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
- char **names,
- int nameslen,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- int n = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
- flags);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- int n = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
- virDomainSnapshotPtr **snaps,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- int n = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
- flags);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotLookupByName(virDomainPtr domain,
- const char *name,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotPtr snapshot = NULL;
-
- virCheckFlags(0, NULL);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return NULL;
-
- if (!(snap = testSnapObjFromName(vm, name)))
- goto cleanup;
-
- snapshot = virGetDomainSnapshot(domain, snap->def->name);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return snapshot;
-}
-
-static int
-testDomainHasCurrentSnapshot(virDomainPtr domain,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- int ret;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- ret = (vm->current_snapshot != NULL);
-
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotPtr parent = NULL;
-
- virCheckFlags(0, NULL);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return NULL;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- if (!snap->def->parent) {
- virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
- _("snapshot '%s' does not have a parent"),
- snap->def->name);
- goto cleanup;
- }
-
- parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return parent;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotCurrent(virDomainPtr domain,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainSnapshotPtr snapshot = NULL;
-
- virCheckFlags(0, NULL);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return NULL;
-
- if (!vm->current_snapshot) {
- virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
- _("the domain does not have a current snapshot"));
- goto cleanup;
- }
-
- snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return snapshot;
-}
-
-static char *
-testDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- char *xml = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- testDriverPtr privconn = snapshot->domain->conn->privateData;
-
- virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return NULL;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- virUUIDFormat(snapshot->domain->uuid, uuidstr);
-
- xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->caps,
- virDomainDefFormatConvertXMLFlags(flags),
- 0);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return xml;
-}
-
-static int
-testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int ret;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- ret = (vm->current_snapshot &&
- STREQ(snapshot->name, vm->current_snapshot->def->name));
-
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-
-static int
-testDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!testSnapObjFromSnapshot(vm, snapshot))
- goto cleanup;
-
- ret = 1;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainSnapshotAlignDisks(virDomainObjPtr vm,
- virDomainSnapshotDefPtr def,
- unsigned int flags)
-{
- int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
- bool align_match = true;
-
- if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
- align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
- align_match = false;
- if (virDomainObjIsActive(vm))
- def->state = VIR_DOMAIN_DISK_SNAPSHOT;
- else
- def->state = VIR_DOMAIN_SHUTOFF;
- def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
- } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
- def->state = virDomainObjGetState(vm, NULL);
- align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
- align_match = false;
- } else {
- def->state = virDomainObjGetState(vm, NULL);
- def->memory = def->state == VIR_DOMAIN_SHUTOFF ?
- VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
- VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
- }
-
- return virDomainSnapshotAlignDisks(def, align_location, align_match);
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotCreateXML(virDomainPtr domain,
- const char *xmlDesc,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr vm = NULL;
- virDomainSnapshotDefPtr def = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotPtr snapshot = NULL;
- virObjectEventPtr event = NULL;
- char *xml = NULL;
- bool update_current = true;
- bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
- unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
-
- /*
- * DISK_ONLY: Not implemented yet
- * REUSE_EXT: Not implemented yet
- *
- * NO_METADATA: Explicitly not implemented
- *
- * REDEFINE + CURRENT: Implemented
- * HALT: Implemented
- * QUIESCE: Nothing to do
- * ATOMIC: Nothing to do
- * LIVE: Nothing to do
- */
- virCheckFlags(
- VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
- VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
- VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
- VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
- VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
- VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
-
- if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)))
- update_current = false;
- if (redefine)
- parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
-
- if (!(vm = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot halt after transient domain snapshot"));
- goto cleanup;
- }
-
- if (!(def = virDomainSnapshotDefParseString(xmlDesc,
- privconn->caps,
- privconn->xmlopt,
- parse_flags)))
- goto cleanup;
-
- if (redefine) {
- if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
- &update_current, flags) < 0)
- goto cleanup;
- } else {
- if (!(def->dom = virDomainDefCopy(vm->def,
- privconn->caps,
- privconn->xmlopt,
- true)))
- goto cleanup;
-
- if (testDomainSnapshotAlignDisks(vm, def, flags) < 0)
- goto cleanup;
- }
-
- if (!snap) {
- if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
- goto cleanup;
- def = NULL;
- }
-
- if (!redefine) {
- if (vm->current_snapshot &&
- (VIR_STRDUP(snap->def->parent,
- vm->current_snapshot->def->name) < 0))
- goto cleanup;
-
- if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) &&
- virDomainObjIsActive(vm)) {
- testDomainShutdownState(domain, vm,
- VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
- event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
- }
- }
-
- snapshot = virGetDomainSnapshot(domain, snap->def->name);
- cleanup:
- VIR_FREE(xml);
- if (vm) {
- if (snapshot) {
- virDomainSnapshotObjPtr other;
- if (update_current)
- vm->current_snapshot = snap;
- other = virDomainSnapshotFindByName(vm->snapshots,
- snap->def->parent);
- snap->parent = other;
- other->nchildren++;
- snap->sibling = other->first_child;
- other->first_child = snap;
- }
- virDomainObjEndAPI(&vm);
- }
- testObjectEventQueue(privconn, event);
- virDomainSnapshotDefFree(def);
- return snapshot;
-}
-
-
-typedef struct _testSnapRemoveData testSnapRemoveData;
-typedef testSnapRemoveData *testSnapRemoveDataPtr;
-struct _testSnapRemoveData {
- virDomainObjPtr vm;
- bool current;
-};
-
-static int
-testDomainSnapshotDiscardAll(void *payload,
- const void *name ATTRIBUTE_UNUSED,
- void *data)
-{
- virDomainSnapshotObjPtr snap = payload;
- testSnapRemoveDataPtr curr = data;
-
- if (snap->def->current)
- curr->current = true;
- virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
- return 0;
-}
-
-typedef struct _testSnapReparentData testSnapReparentData;
-typedef testSnapReparentData *testSnapReparentDataPtr;
-struct _testSnapReparentData {
- virDomainSnapshotObjPtr parent;
- virDomainObjPtr vm;
- int err;
- virDomainSnapshotObjPtr last;
-};
-
-static int
-testDomainSnapshotReparentChildren(void *payload,
- const void *name ATTRIBUTE_UNUSED,
- void *data)
-{
- virDomainSnapshotObjPtr snap = payload;
- testSnapReparentDataPtr rep = data;
-
- if (rep->err < 0)
- return 0;
-
- VIR_FREE(snap->def->parent);
- snap->parent = rep->parent;
-
- if (rep->parent->def &&
- VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
- rep->err = -1;
- return 0;
- }
-
- if (!snap->sibling)
- rep->last = snap;
- return 0;
-}
-
-static int
-testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotObjPtr parentsnap = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
- VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
- VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
- testSnapRemoveData rem;
- rem.vm = vm;
- rem.current = false;
- virDomainSnapshotForEachDescendant(snap,
- testDomainSnapshotDiscardAll,
- &rem);
- if (rem.current) {
- if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)
- snap->def->current = true;
- vm->current_snapshot = snap;
- }
- } else if (snap->nchildren) {
- testSnapReparentData rep;
- rep.parent = snap->parent;
- rep.vm = vm;
- rep.err = 0;
- rep.last = NULL;
- virDomainSnapshotForEachChild(snap,
- testDomainSnapshotReparentChildren,
- &rep);
- if (rep.err < 0)
- goto cleanup;
-
- /* Can't modify siblings during ForEachChild, so do it now. */
- snap->parent->nchildren += snap->nchildren;
- rep.last->sibling = snap->parent->first_child;
- snap->parent->first_child = snap->first_child;
- }
-
- if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
- snap->nchildren = 0;
- snap->first_child = NULL;
- } else {
- virDomainSnapshotDropParent(snap);
- if (snap == vm->current_snapshot) {
- if (snap->def->parent) {
- parentsnap = virDomainSnapshotFindByName(vm->snapshots,
- snap->def->parent);
- if (!parentsnap) {
- VIR_WARN("missing parent snapshot matching name '%s'",
- snap->def->parent);
- } else {
- parentsnap->def->current = true;
- }
- }
- vm->current_snapshot = parentsnap;
- }
- virDomainSnapshotObjListRemove(vm->snapshots, snap);
- }
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- testDriverPtr privconn = snapshot->domain->conn->privateData;
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- virObjectEventPtr event = NULL;
- virObjectEventPtr event2 = NULL;
- virDomainDefPtr config = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
- VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
-
- /* We have the following transitions, which create the following events:
- * 1. inactive -> inactive: none
- * 2. inactive -> running: EVENT_STARTED
- * 3. inactive -> paused: EVENT_STARTED, EVENT_PAUSED
- * 4. running -> inactive: EVENT_STOPPED
- * 5. running -> running: none
- * 6. running -> paused: EVENT_PAUSED
- * 7. paused -> inactive: EVENT_STOPPED
- * 8. paused -> running: EVENT_RESUMED
- * 9. paused -> paused: none
- * Also, several transitions occur even if we fail partway through,
- * and use of FORCE can cause multiple transitions.
- */
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- if (!vm->persistent &&
- snap->def->state != VIR_DOMAIN_RUNNING &&
- snap->def->state != VIR_DOMAIN_PAUSED &&
- (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("transient domain needs to request run or pause "
- "to revert to inactive snapshot"));
- goto cleanup;
- }
-
- if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
- if (!snap->def->dom) {
- virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
- _("snapshot '%s' lacks domain '%s' rollback info"),
- snap->def->name, vm->def->name);
- goto cleanup;
- }
- if (virDomainObjIsActive(vm) &&
- !(snap->def->state == VIR_DOMAIN_RUNNING
- || snap->def->state == VIR_DOMAIN_PAUSED) &&
- (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
- virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
- _("must respawn guest to start inactive snapshot"));
- goto cleanup;
- }
- }
-
-
- if (vm->current_snapshot) {
- vm->current_snapshot->def->current = false;
- vm->current_snapshot = NULL;
- }
-
- snap->def->current = true;
- config = virDomainDefCopy(snap->def->dom,
- privconn->caps, privconn->xmlopt, true);
- if (!config)
- goto cleanup;
-
- if (snap->def->state == VIR_DOMAIN_RUNNING ||
- snap->def->state == VIR_DOMAIN_PAUSED) {
- /* Transitions 2, 3, 5, 6, 8, 9 */
- bool was_running = false;
- bool was_stopped = false;
-
- if (virDomainObjIsActive(vm)) {
- /* Transitions 5, 6, 8, 9 */
- /* Check for ABI compatibility. */
- if (!virDomainDefCheckABIStability(vm->def, config)) {
- virErrorPtr err = virGetLastError();
-
- if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
- /* Re-spawn error using correct category. */
- if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
- virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
- err->str2);
- goto cleanup;
- }
-
- virResetError(err);
- testDomainShutdownState(snapshot->domain, vm,
- VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
- testObjectEventQueue(privconn, event);
- goto load;
- }
-
- if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
- /* Transitions 5, 6 */
- was_running = true;
- virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
- VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
- /* Create an event now in case the restore fails, so
- * that user will be alerted that they are now paused.
- * If restore later succeeds, we might replace this. */
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
- }
- virDomainObjAssignDef(vm, config, false, NULL);
-
- } else {
- /* Transitions 2, 3 */
- load:
- was_stopped = true;
- virDomainObjAssignDef(vm, config, false, NULL);
- if (testDomainStartState(privconn, vm,
- VIR_DOMAIN_RUNNING_FROM_SNAPSHOT) < 0)
- goto cleanup;
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
- }
-
- /* Touch up domain state. */
- if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
- (snap->def->state == VIR_DOMAIN_PAUSED ||
- (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
- /* Transitions 3, 6, 9 */
- virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
- VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
- if (was_stopped) {
- /* Transition 3, use event as-is and add event2 */
- event2 = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
- } /* else transition 6 and 9 use event as-is */
- } else {
- /* Transitions 2, 5, 8 */
- virObjectUnref(event);
- event = NULL;
-
- if (was_stopped) {
- /* Transition 2 */
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
- } else if (was_running) {
- /* Transition 8 */
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_RESUMED,
- VIR_DOMAIN_EVENT_RESUMED);
- }
- }
- } else {
- /* Transitions 1, 4, 7 */
- virDomainObjAssignDef(vm, config, false, NULL);
-
- if (virDomainObjIsActive(vm)) {
- /* Transitions 4, 7 */
- testDomainShutdownState(snapshot->domain, vm,
- VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
- }
-
- if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
- /* Flush first event, now do transition 2 or 3 */
- bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
-
- testObjectEventQueue(privconn, event);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
- if (paused) {
- event2 = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
- }
- }
- }
-
- vm->current_snapshot = snap;
- ret = 0;
- cleanup:
- if (event) {
- testObjectEventQueue(privconn, event);
- testObjectEventQueue(privconn, event2);
- } else {
- virObjectUnref(event2);
- }
- virDomainObjEndAPI(&vm);
-
- return ret;
-}
-
-
-
-static virHypervisorDriver testHypervisorDriver = {
- .name = "Test",
- .connectOpen = testConnectOpen, /* 0.1.1 */
- .connectClose = testConnectClose, /* 0.1.1 */
- .connectGetVersion = testConnectGetVersion, /* 0.1.1 */
- .connectGetHostname = testConnectGetHostname, /* 0.6.3 */
- .connectGetMaxVcpus = testConnectGetMaxVcpus, /* 0.3.2 */
- .nodeGetInfo = testNodeGetInfo, /* 0.1.1 */
- .nodeGetCPUStats = testNodeGetCPUStats, /* 2.3.0 */
- .nodeGetFreeMemory = testNodeGetFreeMemory, /* 2.3.0 */
- .nodeGetFreePages = testNodeGetFreePages, /* 2.3.0 */
- .connectGetCapabilities = testConnectGetCapabilities, /* 0.2.1 */
- .connectGetSysinfo = testConnectGetSysinfo, /* 2.3.0 */
- .connectGetType = testConnectGetType, /* 2.3.0 */
- .connectListDomains = testConnectListDomains, /* 0.1.1 */
- .connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
- .connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
- .domainCreateXML = testDomainCreateXML, /* 0.1.4 */
- .domainLookupByID = testDomainLookupByID, /* 0.1.1 */
- .domainLookupByUUID = testDomainLookupByUUID, /* 0.1.1 */
- .domainLookupByName = testDomainLookupByName, /* 0.1.1 */
- .domainSuspend = testDomainSuspend, /* 0.1.1 */
- .domainResume = testDomainResume, /* 0.1.1 */
- .domainShutdown = testDomainShutdown, /* 0.1.1 */
- .domainShutdownFlags = testDomainShutdownFlags, /* 0.9.10 */
- .domainReboot = testDomainReboot, /* 0.1.1 */
- .domainDestroy = testDomainDestroy, /* 0.1.1 */
- .domainGetOSType = testDomainGetOSType, /* 0.1.9 */
- .domainGetMaxMemory = testDomainGetMaxMemory, /* 0.1.4 */
- .domainSetMaxMemory = testDomainSetMaxMemory, /* 0.1.1 */
- .domainSetMemory = testDomainSetMemory, /* 0.1.4 */
- .domainGetInfo = testDomainGetInfo, /* 0.1.1 */
- .domainGetState = testDomainGetState, /* 0.9.2 */
- .domainSave = testDomainSave, /* 0.3.2 */
- .domainSaveFlags = testDomainSaveFlags, /* 0.9.4 */
- .domainRestore = testDomainRestore, /* 0.3.2 */
- .domainRestoreFlags = testDomainRestoreFlags, /* 0.9.4 */
- .domainCoreDump = testDomainCoreDump, /* 0.3.2 */
- .domainCoreDumpWithFormat = testDomainCoreDumpWithFormat, /* 1.2.3 */
- .domainSetVcpus = testDomainSetVcpus, /* 0.1.4 */
- .domainSetVcpusFlags = testDomainSetVcpusFlags, /* 0.8.5 */
- .domainGetVcpusFlags = testDomainGetVcpusFlags, /* 0.8.5 */
- .domainPinVcpu = testDomainPinVcpu, /* 0.7.3 */
- .domainGetVcpus = testDomainGetVcpus, /* 0.7.3 */
- .domainGetVcpuPinInfo = testDomainGetVcpuPinInfo, /* 1.2.18 */
- .domainGetMaxVcpus = testDomainGetMaxVcpus, /* 0.7.3 */
- .domainGetXMLDesc = testDomainGetXMLDesc, /* 0.1.4 */
- .connectListDefinedDomains = testConnectListDefinedDomains, /* 0.1.11 */
- .connectNumOfDefinedDomains = testConnectNumOfDefinedDomains, /* 0.1.11 */
- .domainCreate = testDomainCreate, /* 0.1.11 */
- .domainCreateWithFlags = testDomainCreateWithFlags, /* 0.8.2 */
- .domainDefineXML = testDomainDefineXML, /* 0.1.11 */
- .domainDefineXMLFlags = testDomainDefineXMLFlags, /* 1.2.12 */
- .domainUndefine = testDomainUndefine, /* 0.1.11 */
- .domainUndefineFlags = testDomainUndefineFlags, /* 0.9.4 */
- .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */
- .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */
- .domainGetSchedulerType = testDomainGetSchedulerType, /* 0.3.2 */
- .domainGetSchedulerParameters = testDomainGetSchedulerParameters, /* 0.3.2 */
- .domainGetSchedulerParametersFlags = testDomainGetSchedulerParametersFlags, /* 0.9.2 */
- .domainSetSchedulerParameters = testDomainSetSchedulerParameters, /* 0.3.2 */
- .domainSetSchedulerParametersFlags = testDomainSetSchedulerParametersFlags, /* 0.9.2 */
- .domainBlockStats = testDomainBlockStats, /* 0.7.0 */
- .domainInterfaceStats = testDomainInterfaceStats, /* 0.7.0 */
- .nodeGetCellsFreeMemory = testNodeGetCellsFreeMemory, /* 0.4.2 */
- .connectDomainEventRegister = testConnectDomainEventRegister, /* 0.6.0 */
- .connectDomainEventDeregister = testConnectDomainEventDeregister, /* 0.6.0 */
- .connectIsEncrypted = testConnectIsEncrypted, /* 0.7.3 */
- .connectIsSecure = testConnectIsSecure, /* 0.7.3 */
- .domainIsActive = testDomainIsActive, /* 0.7.3 */
- .domainIsPersistent = testDomainIsPersistent, /* 0.7.3 */
- .domainIsUpdated = testDomainIsUpdated, /* 0.8.6 */
- .connectDomainEventRegisterAny = testConnectDomainEventRegisterAny, /* 0.8.0 */
- .connectDomainEventDeregisterAny = testConnectDomainEventDeregisterAny, /* 0.8.0 */
- .connectIsAlive = testConnectIsAlive, /* 0.9.8 */
- .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */
- .domainScreenshot = testDomainScreenshot, /* 1.0.5 */
- .domainGetMetadata = testDomainGetMetadata, /* 1.1.3 */
- .domainSetMetadata = testDomainSetMetadata, /* 1.1.3 */
- .connectGetCPUModelNames = testConnectGetCPUModelNames, /* 1.1.3 */
- .domainManagedSave = testDomainManagedSave, /* 1.1.4 */
- .domainHasManagedSaveImage = testDomainHasManagedSaveImage, /* 1.1.4 */
- .domainManagedSaveRemove = testDomainManagedSaveRemove, /* 1.1.4 */
-
- .domainSnapshotNum = testDomainSnapshotNum, /* 1.1.4 */
- .domainSnapshotListNames = testDomainSnapshotListNames, /* 1.1.4 */
- .domainListAllSnapshots = testDomainListAllSnapshots, /* 1.1.4 */
- .domainSnapshotGetXMLDesc = testDomainSnapshotGetXMLDesc, /* 1.1.4 */
- .domainSnapshotNumChildren = testDomainSnapshotNumChildren, /* 1.1.4 */
- .domainSnapshotListChildrenNames = testDomainSnapshotListChildrenNames, /* 1.1.4 */
- .domainSnapshotListAllChildren = testDomainSnapshotListAllChildren, /* 1.1.4 */
- .domainSnapshotLookupByName = testDomainSnapshotLookupByName, /* 1.1.4 */
- .domainHasCurrentSnapshot = testDomainHasCurrentSnapshot, /* 1.1.4 */
- .domainSnapshotGetParent = testDomainSnapshotGetParent, /* 1.1.4 */
- .domainSnapshotCurrent = testDomainSnapshotCurrent, /* 1.1.4 */
- .domainSnapshotIsCurrent = testDomainSnapshotIsCurrent, /* 1.1.4 */
- .domainSnapshotHasMetadata = testDomainSnapshotHasMetadata, /* 1.1.4 */
- .domainSnapshotCreateXML = testDomainSnapshotCreateXML, /* 1.1.4 */
- .domainRevertToSnapshot = testDomainRevertToSnapshot, /* 1.1.4 */
- .domainSnapshotDelete = testDomainSnapshotDelete, /* 1.1.4 */
-
- .connectBaselineCPU = testConnectBaselineCPU, /* 1.2.0 */
-};
-
-static virNetworkDriver testNetworkDriver = {
- .connectNumOfNetworks = testConnectNumOfNetworks, /* 0.3.2 */
- .connectListNetworks = testConnectListNetworks, /* 0.3.2 */
- .connectNumOfDefinedNetworks = testConnectNumOfDefinedNetworks, /* 0.3.2 */
- .connectListDefinedNetworks = testConnectListDefinedNetworks, /* 0.3.2 */
- .connectListAllNetworks = testConnectListAllNetworks, /* 0.10.2 */
- .connectNetworkEventRegisterAny = testConnectNetworkEventRegisterAny, /* 1.2.1 */
- .connectNetworkEventDeregisterAny = testConnectNetworkEventDeregisterAny, /* 1.2.1 */
- .networkLookupByUUID = testNetworkLookupByUUID, /* 0.3.2 */
- .networkLookupByName = testNetworkLookupByName, /* 0.3.2 */
- .networkCreateXML = testNetworkCreateXML, /* 0.3.2 */
- .networkDefineXML = testNetworkDefineXML, /* 0.3.2 */
- .networkUndefine = testNetworkUndefine, /* 0.3.2 */
- .networkUpdate = testNetworkUpdate, /* 0.10.2 */
- .networkCreate = testNetworkCreate, /* 0.3.2 */
- .networkDestroy = testNetworkDestroy, /* 0.3.2 */
- .networkGetXMLDesc = testNetworkGetXMLDesc, /* 0.3.2 */
- .networkGetBridgeName = testNetworkGetBridgeName, /* 0.3.2 */
- .networkGetAutostart = testNetworkGetAutostart, /* 0.3.2 */
- .networkSetAutostart = testNetworkSetAutostart, /* 0.3.2 */
- .networkIsActive = testNetworkIsActive, /* 0.7.3 */
- .networkIsPersistent = testNetworkIsPersistent, /* 0.7.3 */
-};
-
-static virInterfaceDriver testInterfaceDriver = {
- .connectNumOfInterfaces = testConnectNumOfInterfaces, /* 0.7.0 */
- .connectListInterfaces = testConnectListInterfaces, /* 0.7.0 */
- .connectNumOfDefinedInterfaces = testConnectNumOfDefinedInterfaces, /* 0.7.0 */
- .connectListDefinedInterfaces = testConnectListDefinedInterfaces, /* 0.7.0 */
- .interfaceLookupByName = testInterfaceLookupByName, /* 0.7.0 */
- .interfaceLookupByMACString = testInterfaceLookupByMACString, /* 0.7.0 */
- .interfaceGetXMLDesc = testInterfaceGetXMLDesc, /* 0.7.0 */
- .interfaceDefineXML = testInterfaceDefineXML, /* 0.7.0 */
- .interfaceUndefine = testInterfaceUndefine, /* 0.7.0 */
- .interfaceCreate = testInterfaceCreate, /* 0.7.0 */
- .interfaceDestroy = testInterfaceDestroy, /* 0.7.0 */
- .interfaceIsActive = testInterfaceIsActive, /* 0.7.3 */
- .interfaceChangeBegin = testInterfaceChangeBegin, /* 0.9.2 */
- .interfaceChangeCommit = testInterfaceChangeCommit, /* 0.9.2 */
- .interfaceChangeRollback = testInterfaceChangeRollback, /* 0.9.2 */
-};
-
-
-static virStorageDriver testStorageDriver = {
- .connectNumOfStoragePools = testConnectNumOfStoragePools, /* 0.5.0 */
- .connectListStoragePools = testConnectListStoragePools, /* 0.5.0 */
- .connectNumOfDefinedStoragePools = testConnectNumOfDefinedStoragePools, /* 0.5.0 */
- .connectListDefinedStoragePools = testConnectListDefinedStoragePools, /* 0.5.0 */
- .connectListAllStoragePools = testConnectListAllStoragePools, /* 0.10.2 */
- .connectFindStoragePoolSources = testConnectFindStoragePoolSources, /* 0.5.0 */
- .connectStoragePoolEventRegisterAny = testConnectStoragePoolEventRegisterAny, /* 2.0.0 */
- .connectStoragePoolEventDeregisterAny = testConnectStoragePoolEventDeregisterAny, /* 2.0.0 */
- .storagePoolLookupByName = testStoragePoolLookupByName, /* 0.5.0 */
- .storagePoolLookupByUUID = testStoragePoolLookupByUUID, /* 0.5.0 */
- .storagePoolLookupByVolume = testStoragePoolLookupByVolume, /* 0.5.0 */
- .storagePoolCreateXML = testStoragePoolCreateXML, /* 0.5.0 */
- .storagePoolDefineXML = testStoragePoolDefineXML, /* 0.5.0 */
- .storagePoolBuild = testStoragePoolBuild, /* 0.5.0 */
- .storagePoolUndefine = testStoragePoolUndefine, /* 0.5.0 */
- .storagePoolCreate = testStoragePoolCreate, /* 0.5.0 */
- .storagePoolDestroy = testStoragePoolDestroy, /* 0.5.0 */
- .storagePoolDelete = testStoragePoolDelete, /* 0.5.0 */
- .storagePoolRefresh = testStoragePoolRefresh, /* 0.5.0 */
- .storagePoolGetInfo = testStoragePoolGetInfo, /* 0.5.0 */
- .storagePoolGetXMLDesc = testStoragePoolGetXMLDesc, /* 0.5.0 */
- .storagePoolGetAutostart = testStoragePoolGetAutostart, /* 0.5.0 */
- .storagePoolSetAutostart = testStoragePoolSetAutostart, /* 0.5.0 */
- .storagePoolNumOfVolumes = testStoragePoolNumOfVolumes, /* 0.5.0 */
- .storagePoolListVolumes = testStoragePoolListVolumes, /* 0.5.0 */
- .storagePoolListAllVolumes = testStoragePoolListAllVolumes, /* 0.10.2 */
-
- .storageVolLookupByName = testStorageVolLookupByName, /* 0.5.0 */
- .storageVolLookupByKey = testStorageVolLookupByKey, /* 0.5.0 */
- .storageVolLookupByPath = testStorageVolLookupByPath, /* 0.5.0 */
- .storageVolCreateXML = testStorageVolCreateXML, /* 0.5.0 */
- .storageVolCreateXMLFrom = testStorageVolCreateXMLFrom, /* 0.6.4 */
- .storageVolDelete = testStorageVolDelete, /* 0.5.0 */
- .storageVolGetInfo = testStorageVolGetInfo, /* 0.5.0 */
- .storageVolGetXMLDesc = testStorageVolGetXMLDesc, /* 0.5.0 */
- .storageVolGetPath = testStorageVolGetPath, /* 0.5.0 */
- .storagePoolIsActive = testStoragePoolIsActive, /* 0.7.3 */
- .storagePoolIsPersistent = testStoragePoolIsPersistent, /* 0.7.3 */
-};
-
-static virNodeDeviceDriver testNodeDeviceDriver = {
- .connectNodeDeviceEventRegisterAny = testConnectNodeDeviceEventRegisterAny, /* 2.2.0 */
- .connectNodeDeviceEventDeregisterAny = testConnectNodeDeviceEventDeregisterAny, /* 2.2.0 */
- .nodeNumOfDevices = testNodeNumOfDevices, /* 0.7.2 */
- .nodeListDevices = testNodeListDevices, /* 0.7.2 */
- .nodeDeviceLookupByName = testNodeDeviceLookupByName, /* 0.7.2 */
- .nodeDeviceGetXMLDesc = testNodeDeviceGetXMLDesc, /* 0.7.2 */
- .nodeDeviceGetParent = testNodeDeviceGetParent, /* 0.7.2 */
- .nodeDeviceNumOfCaps = testNodeDeviceNumOfCaps, /* 0.7.2 */
- .nodeDeviceListCaps = testNodeDeviceListCaps, /* 0.7.2 */
- .nodeDeviceCreateXML = testNodeDeviceCreateXML, /* 0.7.3 */
- .nodeDeviceDestroy = testNodeDeviceDestroy, /* 0.7.3 */
-};
static virConnectDriver testConnectDriver = {
.hypervisorDriver = &testHypervisorDriver,
diff --git a/src/test/test_hypervisor_driver.c b/src/test/test_hypervisor_driver.c
new file mode 100644
index 0000000..96e04b6
--- /dev/null
+++ b/src/test/test_hypervisor_driver.c
@@ -0,0 +1,4152 @@
+/*
+ * test_hypervisor_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_hypervisor_driver.h"
+
+#include "test_private_driver.h"
+
+VIR_LOG_INIT("test.test_driver");
+
+static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
+
+static int
+testConnectAuthenticate(virConnectPtr conn,
+ virConnectAuthPtr auth)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+ ssize_t i;
+ char *username = NULL, *password = NULL;
+
+ if (privconn->numAuths == 0)
+ return 0;
+
+ /* Authentication is required because the test XML contains a
+ * non-empty <auth/> section. First we must ask for a username.
+ */
+ username = virAuthGetUsername(conn, auth, "test", NULL, "localhost"/*?*/);
+ if (!username) {
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed when asking for username"));
+ goto cleanup;
+ }
+
+ /* Does the username exist? */
+ for (i = 0; i < privconn->numAuths; ++i) {
+ if (STREQ(privconn->auths[i].username, username))
+ goto found_user;
+ }
+ i = -1;
+
+ found_user:
+ /* Even if we didn't find the user, we still ask for a password. */
+ if (i == -1 || privconn->auths[i].password != NULL) {
+ password = virAuthGetPassword(conn, auth, "test",
+ username, "localhost");
+ if (password == NULL) {
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed when asking for password"));
+ goto cleanup;
+ }
+ }
+
+ if (i == -1 ||
+ (password && STRNEQ(privconn->auths[i].password, password))) {
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed, see test XML for the correct username/password"));
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(username);
+ VIR_FREE(password);
+ return ret;
+}
+
+static int
+testParseNodeInfo(virNodeInfoPtr nodeInfo, xmlXPathContextPtr ctxt)
+{
+ char *str;
+ long l;
+ int ret;
+
+ ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->nodes = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu nodes value"));
+ goto error;
+ }
+
+ ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->sockets = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu sockets value"));
+ goto error;
+ }
+
+ ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->cores = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu cores value"));
+ goto error;
+ }
+
+ ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->threads = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu threads value"));
+ goto error;
+ }
+
+ nodeInfo->cpus = (nodeInfo->cores * nodeInfo->threads *
+ nodeInfo->sockets * nodeInfo->nodes);
+ ret = virXPathLong("string(/node/cpu/active[1])", ctxt, &l);
+ if (ret == 0) {
+ if (l < nodeInfo->cpus)
+ nodeInfo->cpus = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu active value"));
+ goto error;
+ }
+ ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->mhz = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu mhz value"));
+ goto error;
+ }
+
+ str = virXPathString("string(/node/cpu/model[1])", ctxt);
+ if (str != NULL) {
+ if (virStrcpyStatic(nodeInfo->model, str) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Model %s too big for destination"), str);
+ VIR_FREE(str);
+ goto error;
+ }
+ VIR_FREE(str);
+ }
+
+ ret = virXPathLong("string(/node/memory[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->memory = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node memory value"));
+ goto error;
+ }
+
+ return 0;
+ error:
+ return -1;
+}
+
+static char *testBuildFilename(const char *relativeTo,
+ const char *filename)
+{
+ char *offset;
+ int baseLen;
+ char *ret;
+
+ if (!filename || filename[0] == '\0')
+ return NULL;
+ if (filename[0] == '/') {
+ ignore_value(VIR_STRDUP(ret, filename));
+ return ret;
+ }
+
+ offset = strrchr(relativeTo, '/');
+ if ((baseLen = (offset-relativeTo+1))) {
+ char *absFile;
+ int totalLen = baseLen + strlen(filename) + 1;
+ if (VIR_ALLOC_N(absFile, totalLen) < 0)
+ return NULL;
+ if (virStrncpy(absFile, relativeTo, baseLen, totalLen) == NULL) {
+ VIR_FREE(absFile);
+ return NULL;
+ }
+ strcat(absFile, filename);
+ return absFile;
+ } else {
+ ignore_value(VIR_STRDUP(ret, filename));
+ return ret;
+ }
+}
+
+static xmlNodePtr
+testParseXMLDocFromFile(xmlNodePtr node, const char *file, const char *type)
+{
+ xmlNodePtr ret = NULL;
+ xmlDocPtr doc = NULL;
+ char *absFile = NULL;
+ char *relFile = virXMLPropString(node, "file");
+
+ if (relFile != NULL) {
+ absFile = testBuildFilename(file, relFile);
+ VIR_FREE(relFile);
+ if (!absFile) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("resolving %s filename"), type);
+ return NULL;
+ }
+
+ if (!(doc = virXMLParse(absFile, NULL, type)))
+ goto error;
+
+ ret = xmlCopyNode(xmlDocGetRootElement(doc), 1);
+ if (!ret) {
+ virReportOOMError();
+ goto error;
+ }
+ xmlReplaceNode(node, ret);
+ xmlFreeNode(node);
+ } else {
+ ret = node;
+ }
+
+ error:
+ xmlFreeDoc(doc);
+ VIR_FREE(absFile);
+ return ret;
+}
+
+#define TEST_NAMESPACE_HREF "http://libvirt.org/schemas/domain/test/1.0"
+
+typedef struct _testDomainNamespaceDef testDomainNamespaceDef;
+typedef testDomainNamespaceDef *testDomainNamespaceDefPtr;
+struct _testDomainNamespaceDef {
+ int runstate;
+ bool transient;
+ bool hasManagedSave;
+
+ unsigned int num_snap_nodes;
+ xmlNodePtr *snap_nodes;
+};
+
+static void
+testDomainDefNamespaceFree(void *data)
+{
+ testDomainNamespaceDefPtr nsdata = data;
+ size_t i;
+
+ if (!nsdata)
+ return;
+
+ for (i = 0; i < nsdata->num_snap_nodes; i++)
+ xmlFreeNode(nsdata->snap_nodes[i]);
+
+ VIR_FREE(nsdata->snap_nodes);
+ VIR_FREE(nsdata);
+}
+
+static int
+testDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
+ xmlNodePtr root ATTRIBUTE_UNUSED,
+ xmlXPathContextPtr ctxt,
+ void **data)
+{
+ testDomainNamespaceDefPtr nsdata = NULL;
+ xmlNodePtr *nodes = NULL;
+ int tmp, n;
+ size_t i;
+ unsigned int tmpuint;
+
+ if (xmlXPathRegisterNs(ctxt, BAD_CAST "test",
+ BAD_CAST TEST_NAMESPACE_HREF) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to register xml namespace '%s'"),
+ TEST_NAMESPACE_HREF);
+ return -1;
+ }
+
+ if (VIR_ALLOC(nsdata) < 0)
+ return -1;
+
+ n = virXPathNodeSet("./test:domainsnapshot", ctxt, &nodes);
+ if (n < 0)
+ goto error;
+
+ if (n && VIR_ALLOC_N(nsdata->snap_nodes, n) < 0)
+ goto error;
+
+ for (i = 0; i < n; i++) {
+ xmlNodePtr newnode = xmlCopyNode(nodes[i], 1);
+ if (!newnode) {
+ virReportOOMError();
+ goto error;
+ }
+
+ nsdata->snap_nodes[nsdata->num_snap_nodes] = newnode;
+ nsdata->num_snap_nodes++;
+ }
+ VIR_FREE(nodes);
+
+ tmp = virXPathBoolean("boolean(./test:transient)", ctxt);
+ if (tmp == -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid transient"));
+ goto error;
+ }
+ nsdata->transient = tmp;
+
+ tmp = virXPathBoolean("boolean(./test:hasmanagedsave)", ctxt);
+ if (tmp == -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid hasmanagedsave"));
+ goto error;
+ }
+ nsdata->hasManagedSave = tmp;
+
+ tmp = virXPathUInt("string(./test:runstate)", ctxt, &tmpuint);
+ if (tmp == 0) {
+ if (tmpuint >= VIR_DOMAIN_LAST) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("runstate '%d' out of range'"), tmpuint);
+ goto error;
+ }
+ nsdata->runstate = tmpuint;
+ } else if (tmp == -1) {
+ nsdata->runstate = VIR_DOMAIN_RUNNING;
+ } else if (tmp == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid runstate"));
+ goto error;
+ }
+
+ if (nsdata->transient && nsdata->runstate == VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("transient domain cannot have runstate 'shutoff'"));
+ goto error;
+ }
+ if (nsdata->hasManagedSave && nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("domain with managedsave data can only have runstate 'shutoff'"));
+ goto error;
+ }
+
+ *data = nsdata;
+ return 0;
+
+ error:
+ VIR_FREE(nodes);
+ testDomainDefNamespaceFree(nsdata);
+ return -1;
+}
+
+static int
+testParseDomainSnapshots(testDriverPtr privconn,
+ virDomainObjPtr domobj,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ size_t i;
+ int ret = -1;
+ testDomainNamespaceDefPtr nsdata = domobj->def->namespaceData;
+ xmlNodePtr *nodes = nsdata->snap_nodes;
+
+ for (i = 0; i < nsdata->num_snap_nodes; i++) {
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "domainsnapshot");
+ if (!node)
+ goto error;
+
+ def = virDomainSnapshotDefParseNode(ctxt->doc, node,
+ privconn->caps,
+ privconn->xmlopt,
+ VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
+ VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL |
+ VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
+ if (!def)
+ goto error;
+
+ if (!(snap = virDomainSnapshotAssignDef(domobj->snapshots, def))) {
+ virDomainSnapshotDefFree(def);
+ goto error;
+ }
+
+ if (def->current) {
+ if (domobj->current_snapshot) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("more than one snapshot claims to be active"));
+ goto error;
+ }
+
+ domobj->current_snapshot = snap;
+ }
+ }
+
+ if (virDomainSnapshotUpdateRelations(domobj->snapshots) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Snapshots have inconsistent relations for "
+ "domain %s"), domobj->def->name);
+ goto error;
+ }
+
+ ret = 0;
+ error:
+ return ret;
+}
+
+static void
+testDomainShutdownState(virDomainPtr domain,
+ virDomainObjPtr privdom,
+ virDomainShutoffReason reason)
+{
+ virDomainObjRemoveTransientDef(privdom);
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason);
+
+ if (domain)
+ domain->id = -1;
+}
+
+/* Set up domain runtime state */
+static int
+testDomainStartState(testDriverPtr privconn,
+ virDomainObjPtr dom,
+ virDomainRunningReason reason)
+{
+ int ret = -1;
+
+ virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason);
+ dom->def->id = virAtomicIntAdd(&privconn->nextDomID, 1);
+
+ if (virDomainObjSetDefTransient(privconn->caps,
+ privconn->xmlopt,
+ dom) < 0) {
+ goto cleanup;
+ }
+
+ dom->hasManagedSave = false;
+ ret = 0;
+ cleanup:
+ if (ret < 0)
+ testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED);
+ return ret;
+}
+
+static char *
+testDomainGenerateIfname(virDomainDefPtr domdef)
+{
+ int maxif = 1024;
+ int ifctr;
+ size_t i;
+
+ for (ifctr = 0; ifctr < maxif; ++ifctr) {
+ char *ifname;
+ int found = 0;
+
+ if (virAsprintf(&ifname, "testnet%d", ifctr) < 0)
+ return NULL;
+
+ /* Generate network interface names */
+ for (i = 0; i < domdef->nnets; i++) {
+ if (domdef->nets[i]->ifname &&
+ STREQ(domdef->nets[i]->ifname, ifname)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return ifname;
+ VIR_FREE(ifname);
+ }
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Exceeded max iface limit %d"), maxif);
+ return NULL;
+}
+
+static int
+testDomainGenerateIfnames(virDomainDefPtr domdef)
+{
+ size_t i = 0;
+
+ for (i = 0; i < domdef->nnets; i++) {
+ char *ifname;
+ if (domdef->nets[i]->ifname)
+ continue;
+
+ ifname = testDomainGenerateIfname(domdef);
+ if (!ifname)
+ return -1;
+
+ domdef->nets[i]->ifname = ifname;
+ }
+
+ return 0;
+}
+
+static int
+testParseDomains(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virDomainObjPtr obj;
+
+ num = virXPathNodeSet("/node/domain", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virDomainDefPtr def;
+ testDomainNamespaceDefPtr nsdata;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "domain");
+ if (!node)
+ goto error;
+
+ def = virDomainDefParseNode(ctxt->doc, node,
+ privconn->caps, privconn->xmlopt,
+ VIR_DOMAIN_DEF_PARSE_INACTIVE);
+ if (!def)
+ goto error;
+
+ if (testDomainGenerateIfnames(def) < 0 ||
+ !(obj = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ 0, NULL))) {
+ virDomainDefFree(def);
+ goto error;
+ }
+
+ if (testParseDomainSnapshots(privconn, obj, file, ctxt) < 0) {
+ virObjectUnlock(obj);
+ goto error;
+ }
+
+ nsdata = def->namespaceData;
+ obj->persistent = !nsdata->transient;
+ obj->hasManagedSave = nsdata->hasManagedSave;
+
+ if (nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
+ if (testDomainStartState(privconn, obj,
+ VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+ virObjectUnlock(obj);
+ goto error;
+ }
+ } else {
+ testDomainShutdownState(NULL, obj, 0);
+ }
+ virDomainObjSetState(obj, nsdata->runstate, 0);
+
+ virObjectUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseNetworks(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virNetworkObjPtr obj;
+
+ num = virXPathNodeSet("/node/network", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virNetworkDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "network");
+ if (!node)
+ goto error;
+
+ def = virNetworkDefParseNode(ctxt->doc, node);
+ if (!def)
+ goto error;
+
+ if (!(obj = virNetworkAssignDef(privconn->networks, def, 0))) {
+ virNetworkDefFree(def);
+ goto error;
+ }
+
+ obj->active = 1;
+ virNetworkObjEndAPI(&obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseInterfaces(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virInterfaceObjPtr obj;
+
+ num = virXPathNodeSet("/node/interface", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virInterfaceDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "interface");
+ if (!node)
+ goto error;
+
+ def = virInterfaceDefParseNode(ctxt->doc, node);
+ if (!def)
+ goto error;
+
+ if (!(obj = virInterfaceAssignDef(&privconn->ifaces, def))) {
+ virInterfaceDefFree(def);
+ goto error;
+ }
+
+ obj->active = 1;
+ virInterfaceObjUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testOpenVolumesForPool(const char *file,
+ xmlXPathContextPtr ctxt,
+ virStoragePoolObjPtr pool,
+ int poolidx)
+{
+ char *vol_xpath;
+ size_t i;
+ int num, ret = -1;
+ xmlNodePtr *nodes = NULL;
+ virStorageVolDefPtr def = NULL;
+
+ /* Find storage volumes */
+ if (virAsprintf(&vol_xpath, "/node/pool[%d]/volume", poolidx) < 0)
+ goto error;
+
+ num = virXPathNodeSet(vol_xpath, ctxt, &nodes);
+ VIR_FREE(vol_xpath);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "volume");
+ if (!node)
+ goto error;
+
+ def = virStorageVolDefParseNode(pool->def, ctxt->doc, node, 0);
+ if (!def)
+ goto error;
+
+ if (def->target.path == NULL) {
+ if (virAsprintf(&def->target.path, "%s/%s",
+ pool->def->target.path,
+ def->name) == -1)
+ goto error;
+ }
+
+ if (!def->key && VIR_STRDUP(def->key, def->target.path) < 0)
+ goto error;
+ if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, def) < 0)
+ goto error;
+
+ pool->def->allocation += def->target.allocation;
+ pool->def->available = (pool->def->capacity -
+ pool->def->allocation);
+ def = NULL;
+ }
+
+ ret = 0;
+ error:
+ virStorageVolDefFree(def);
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseStorage(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virStoragePoolObjPtr obj;
+
+ num = virXPathNodeSet("/node/pool", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virStoragePoolDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "pool");
+ if (!node)
+ goto error;
+
+ def = virStoragePoolDefParseNode(ctxt->doc, node);
+ if (!def)
+ goto error;
+
+ if (!(obj = virStoragePoolObjAssignDef(&privconn->pools,
+ def))) {
+ virStoragePoolDefFree(def);
+ goto error;
+ }
+
+ if (testStoragePoolObjSetDefaults(obj) == -1) {
+ virStoragePoolObjUnlock(obj);
+ goto error;
+ }
+ obj->active = 1;
+
+ /* Find storage volumes */
+ if (testOpenVolumesForPool(file, ctxt, obj, i+1) < 0) {
+ virStoragePoolObjUnlock(obj);
+ goto error;
+ }
+
+ virStoragePoolObjUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseNodedevs(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virNodeDeviceObjPtr obj;
+
+ num = virXPathNodeSet("/node/device", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virNodeDeviceDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "nodedev");
+ if (!node)
+ goto error;
+
+ def = virNodeDeviceDefParseNode(ctxt->doc, node, 0, NULL);
+ if (!def)
+ goto error;
+
+ if (!(obj = virNodeDeviceAssignDef(&privconn->devs, def))) {
+ virNodeDeviceDefFree(def);
+ goto error;
+ }
+
+ virNodeDeviceObjUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseAuthUsers(testDriverPtr privconn,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+
+ num = virXPathNodeSet("/node/auth/user", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ privconn->numAuths = num;
+ if (num && VIR_ALLOC_N(privconn->auths, num) < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ char *username, *password;
+
+ ctxt->node = nodes[i];
+ username = virXPathString("string(.)", ctxt);
+ if (!username || STREQ(username, "")) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing username in /node/auth/user field"));
+ VIR_FREE(username);
+ goto error;
+ }
+ /* This field is optional. */
+ password = virXMLPropString(nodes[i], "password");
+
+ privconn->auths[i].username = username;
+ privconn->auths[i].password = password;
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testOpenParse(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ if (!xmlStrEqual(ctxt->node->name, BAD_CAST "node")) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Root element is not 'node'"));
+ goto error;
+ }
+
+ if (testParseNodeInfo(&privconn->nodeInfo, ctxt) < 0)
+ goto error;
+ if (testParseDomains(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseNetworks(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseInterfaces(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseStorage(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseNodedevs(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseAuthUsers(privconn, ctxt) < 0)
+ goto error;
+
+ return 0;
+ error:
+ return -1;
+}
+
+static const char *defaultConnXML =
+"<node>"
+"<domain type='test'>"
+" <name>test</name>"
+" <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>"
+" <memory>8388608</memory>"
+" <currentMemory>2097152</currentMemory>"
+" <vcpu>2</vcpu>"
+" <os>"
+" <type>hvm</type>"
+" </os>"
+"</domain>"
+""
+"<network>"
+" <name>default</name>"
+" <uuid>dd8fe884-6c02-601e-7551-cca97df1c5df</uuid>"
+" <bridge name='virbr0'/>"
+" <forward/>"
+" <ip address='192.168.122.1' netmask='255.255.255.0'>"
+" <dhcp>"
+" <range start='192.168.122.2' end='192.168.122.254'/>"
+" </dhcp>"
+" </ip>"
+"</network>"
+""
+"<interface type=\"ethernet\" name=\"eth1\">"
+" <start mode=\"onboot\"/>"
+" <mac address=\"aa:bb:cc:dd:ee:ff\"/>"
+" <mtu size=\"1492\"/>"
+" <protocol family=\"ipv4\">"
+" <ip address=\"192.168.0.5\" prefix=\"24\"/>"
+" <route gateway=\"192.168.0.1\"/>"
+" </protocol>"
+"</interface>"
+""
+"<pool type='dir'>"
+" <name>default-pool</name>"
+" <uuid>dfe224cb-28fb-8dd0-c4b2-64eb3f0f4566</uuid>"
+" <target>"
+" <path>/default-pool</path>"
+" </target>"
+"</pool>"
+""
+"<device>"
+" <name>computer</name>"
+" <capability type='system'>"
+" <hardware>"
+" <vendor>Libvirt</vendor>"
+" <version>Test driver</version>"
+" <serial>123456</serial>"
+" <uuid>11111111-2222-3333-4444-555555555555</uuid>"
+" </hardware>"
+" <firmware>"
+" <vendor>Libvirt</vendor>"
+" <version>Test Driver</version>"
+" <release_date>01/22/2007</release_date>"
+" </firmware>"
+" </capability>"
+"</device>"
+"<device>"
+" <name>test-scsi-host-vport</name>"
+" <parent>computer</parent>"
+" <capability type='scsi_host'>"
+" <host>1</host>"
+" <capability type='fc_host'>"
+" <wwnn>2000000012341234</wwnn>"
+" <wwpn>1000000012341234</wwpn>"
+" </capability>"
+" <capability type='vport_ops'/>"
+" </capability>"
+"</device>"
+"</node>";
+
+static void
+testDriverFree(testDriverPtr driver)
+{
+ if (!driver)
+ return;
+
+ virObjectUnref(driver->caps);
+ virObjectUnref(driver->xmlopt);
+ virObjectUnref(driver->domains);
+ virNodeDeviceObjListFree(&driver->devs);
+ virObjectUnref(driver->networks);
+ virInterfaceObjListFree(&driver->ifaces);
+ virStoragePoolObjListFree(&driver->pools);
+ virObjectEventStateFree(driver->eventState);
+ virMutexUnlock(&driver->lock);
+ virMutexDestroy(&driver->lock);
+
+ VIR_FREE(driver);
+}
+
+static testDriverPtr
+testDriverNew(void)
+{
+ virDomainXMLNamespace ns = {
+ .parse = testDomainDefNamespaceParse,
+ .free = testDomainDefNamespaceFree,
+ };
+ testDriverPtr ret;
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ if (virMutexInit(&ret->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot initialize mutex"));
+ goto error;
+ }
+
+ if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns)) ||
+ !(ret->eventState = virObjectEventStateNew()) ||
+ !(ret->domains = virDomainObjListNew()) ||
+ !(ret->networks = virNetworkObjListNew()))
+ goto error;
+
+ virAtomicIntSet(&ret->nextDomID, 1);
+
+ return ret;
+
+ error:
+ testDriverFree(ret);
+ return NULL;
+}
+
+#define TEST_EMULATOR "/usr/bin/test-hv"
+
+static virCapsPtr
+testBuildCapabilities(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ virCapsPtr caps;
+ virCapsGuestPtr guest;
+ int guest_types[] = { VIR_DOMAIN_OSTYPE_HVM,
+ VIR_DOMAIN_OSTYPE_XEN };
+ size_t i, j;
+
+ if ((caps = virCapabilitiesNew(VIR_ARCH_I686, false, false)) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddHostFeature(caps, "pae") < 0)
+ goto error;
+ if (virCapabilitiesAddHostFeature(caps, "nonpae") < 0)
+ goto error;
+
+ if (VIR_ALLOC_N(caps->host.pagesSize, 2) < 0)
+ goto error;
+
+ caps->host.pagesSize[caps->host.nPagesSize++] = 4;
+ caps->host.pagesSize[caps->host.nPagesSize++] = 2048;
+
+ for (i = 0; i < privconn->numCells; i++) {
+ virCapsHostNUMACellCPUPtr cpu_cells;
+ virCapsHostNUMACellPageInfoPtr pages;
+ size_t nPages;
+
+ if (VIR_ALLOC_N(cpu_cells, privconn->cells[i].numCpus) < 0 ||
+ VIR_ALLOC_N(pages, caps->host.nPagesSize) < 0) {
+ VIR_FREE(cpu_cells);
+ goto error;
+ }
+
+ nPages = caps->host.nPagesSize;
+
+ memcpy(cpu_cells, privconn->cells[i].cpus,
+ sizeof(*cpu_cells) * privconn->cells[i].numCpus);
+
+ for (j = 0; j < nPages; j++)
+ pages[j].size = caps->host.pagesSize[j];
+
+ pages[0].avail = privconn->cells[i].mem / pages[0].size;
+
+ if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].mem,
+ privconn->cells[i].numCpus,
+ cpu_cells, 0, NULL, nPages, pages) < 0)
+ goto error;
+ }
+
+ for (i = 0; i < ARRAY_CARDINALITY(guest_types); i++) {
+ if ((guest = virCapabilitiesAddGuest(caps,
+ guest_types[i],
+ VIR_ARCH_I686,
+ TEST_EMULATOR,
+ NULL,
+ 0,
+ NULL)) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ VIR_DOMAIN_VIRT_TEST,
+ NULL,
+ NULL,
+ 0,
+ NULL) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddGuestFeature(guest, "pae", true, true) == NULL)
+ goto error;
+ if (virCapabilitiesAddGuestFeature(guest, "nonpae", true, true) == NULL)
+ goto error;
+ }
+
+ caps->host.nsecModels = 1;
+ if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
+ goto error;
+ if (VIR_STRDUP(caps->host.secModels[0].model, "testSecurity") < 0)
+ goto error;
+
+ if (VIR_STRDUP(caps->host.secModels[0].doi, "") < 0)
+ goto error;
+
+ return caps;
+
+ error:
+ virObjectUnref(caps);
+ return NULL;
+}
+
+#define TEST_MODEL "i686"
+
+static const virNodeInfo defaultNodeInfo = {
+ TEST_MODEL,
+ 1024*1024*3, /* 3 GB */
+ 16,
+ 1400,
+ 2,
+ 2,
+ 2,
+ 2,
+};
+
+static virMutex defaultLock = VIR_MUTEX_INITIALIZER;
+
+static testDriverPtr defaultConn;
+static int defaultConnections;
+
+/* Simultaneous test:///default connections should share the same
+ * common state (among other things, this allows testing event
+ * detection in one connection for an action caused in another). */
+static int
+testOpenDefault(virConnectPtr conn)
+{
+ int u;
+ testDriverPtr privconn = NULL;
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+
+ virMutexLock(&defaultLock);
+ if (defaultConnections++) {
+ conn->privateData = defaultConn;
+ virMutexUnlock(&defaultLock);
+ return VIR_DRV_OPEN_SUCCESS;
+ }
+
+ if (!(privconn = testDriverNew()))
+ goto error;
+
+ conn->privateData = privconn;
+
+ memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+ /* Numa setup */
+ privconn->numCells = 2;
+ for (u = 0; u < privconn->numCells; ++u) {
+ privconn->cells[u].numCpus = 8;
+ privconn->cells[u].mem = (u + 1) * 2048 * 1024;
+ privconn->cells[u].freeMem = (u + 1) * 1024 * 1024;
+ }
+ for (u = 0; u < 16; u++) {
+ virBitmapPtr siblings = virBitmapNew(16);
+ if (!siblings)
+ goto error;
+ ignore_value(virBitmapSetBit(siblings, u));
+ privconn->cells[u / 8].cpus[(u % 8)].id = u;
+ privconn->cells[u / 8].cpus[(u % 8)].socket_id = u / 8;
+ privconn->cells[u / 8].cpus[(u % 8)].core_id = u % 8;
+ privconn->cells[u / 8].cpus[(u % 8)].siblings = siblings;
+ }
+
+ if (!(privconn->caps = testBuildCapabilities(conn)))
+ goto error;
+
+ if (!(doc = virXMLParseStringCtxt(defaultConnXML,
+ _("(test driver)"), &ctxt)))
+ goto error;
+
+ if (testOpenParse(privconn, NULL, ctxt) < 0)
+ goto error;
+
+ defaultConn = privconn;
+
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ virMutexUnlock(&defaultLock);
+
+ return VIR_DRV_OPEN_SUCCESS;
+
+ error:
+ testDriverFree(privconn);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ conn->privateData = NULL;
+ defaultConnections--;
+ virMutexUnlock(&defaultLock);
+ return VIR_DRV_OPEN_ERROR;
+}
+
+static int
+testOpenFromFile(virConnectPtr conn, const char *file)
+{
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ testDriverPtr privconn;
+
+ if (!(privconn = testDriverNew()))
+ return VIR_DRV_OPEN_ERROR;
+
+ testDriverLock(privconn);
+ conn->privateData = privconn;
+
+ if (!(privconn->caps = testBuildCapabilities(conn)))
+ goto error;
+
+ if (!(doc = virXMLParseFileCtxt(file, &ctxt)))
+ goto error;
+
+ privconn->numCells = 0;
+ memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+ if (testOpenParse(privconn, file, ctxt) < 0)
+ goto error;
+
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ testDriverUnlock(privconn);
+
+ return 0;
+
+ error:
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ testDriverFree(privconn);
+ conn->privateData = NULL;
+ return VIR_DRV_OPEN_ERROR;
+}
+
+static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
+ virConnectAuthPtr auth,
+ virConfPtr conf ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ int ret;
+
+ virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
+
+ if (!conn->uri)
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "test"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* Remote driver should handle these. */
+ if (conn->uri->server)
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* From this point on, the connection is for us. */
+ if (!conn->uri->path
+ || conn->uri->path[0] == '\0'
+ || (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("testOpen: supply a path or use test:///default"));
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ if (STREQ(conn->uri->path, "/default"))
+ ret = testOpenDefault(conn);
+ else
+ ret = testOpenFromFile(conn,
+ conn->uri->path);
+
+ if (ret != VIR_DRV_OPEN_SUCCESS)
+ return ret;
+
+ /* Fake authentication. */
+ if (testConnectAuthenticate(conn, auth) < 0)
+ return VIR_DRV_OPEN_ERROR;
+
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int testConnectClose(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ bool dflt = false;
+
+ if (privconn == defaultConn) {
+ dflt = true;
+ virMutexLock(&defaultLock);
+ if (--defaultConnections) {
+ virMutexUnlock(&defaultLock);
+ return 0;
+ }
+ }
+
+ testDriverLock(privconn);
+ testDriverFree(privconn);
+
+ if (dflt) {
+ defaultConn = NULL;
+ virMutexUnlock(&defaultLock);
+ }
+
+ conn->privateData = NULL;
+ return 0;
+}
+
+static int testConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned long *hvVer)
+{
+ *hvVer = 2;
+ return 0;
+}
+
+static char *testConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return virGetHostname();
+}
+
+static int testConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *type ATTRIBUTE_UNUSED)
+{
+ return 32;
+}
+
+int testNodeGetInfo(virConnectPtr conn,
+ virNodeInfoPtr info)
+{
+ testDriverPtr privconn = conn->privateData;
+ testDriverLock(privconn);
+ memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo));
+ testDriverUnlock(privconn);
+ return 0;
+}
+
+#define TEST_NB_CPU_STATS 4
+
+static int
+testNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
+ int cpuNum ATTRIBUTE_UNUSED,
+ virNodeCPUStatsPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ size_t i = 0;
+
+ virCheckFlags(0, -1);
+
+ if (params == NULL) {
+ *nparams = TEST_NB_CPU_STATS;
+ return 0;
+ }
+
+ for (i = 0; i < *nparams && i < 4; i++) {
+ switch (i) {
+ case 0:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_USER, 9797400000) < 0)
+ return -1;
+ break;
+ case 1:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_KERNEL, 34678723400000) < 0)
+ return -1;
+ break;
+ case 2:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_IDLE, 87264900000) < 0)
+ return -1;
+ break;
+ case 3:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_IOWAIT, 763600000) < 0)
+ return -1;
+ break;
+ }
+ }
+
+ *nparams = i;
+ return 0;
+}
+
+static unsigned long long
+testNodeGetFreeMemory(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ unsigned int freeMem = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+
+ for (i = 0; i < privconn->numCells; i++)
+ freeMem += privconn->cells[i].freeMem;
+
+ testDriverUnlock(privconn);
+ return freeMem;
+}
+
+static int
+testNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned int npages,
+ unsigned int *pages ATTRIBUTE_UNUSED,
+ int startCell ATTRIBUTE_UNUSED,
+ unsigned int cellCount,
+ unsigned long long *counts,
+ unsigned int flags)
+{
+ size_t i = 0, j = 0;
+ int x = 6;
+
+ virCheckFlags(0, -1);
+
+ for (i = 0; i < cellCount; i++) {
+ for (j = 0; j < npages; j++) {
+ x = x * 2 + 7;
+ counts[(i * npages) + j] = x;
+ }
+ }
+
+ return 0;
+}
+
+static char *testConnectGetCapabilities(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ char *xml;
+ testDriverLock(privconn);
+ xml = virCapabilitiesFormatXML(privconn->caps);
+ testDriverUnlock(privconn);
+ return xml;
+}
+
+static char *
+testConnectGetSysinfo(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ char *ret;
+ const char *sysinfo = "<sysinfo type='smbios'>\n"
+ " <bios>\n"
+ " <entry name='vendor'>LENOVO</entry>\n"
+ " <entry name='version'>G4ETA1WW (2.61 )</entry>\n"
+ " <entry name='date'>05/07/2014</entry>\n"
+ " <entry name='release'>2.61</entry>\n"
+ " </bios>\n"
+ "</sysinfo>\n";
+
+ virCheckFlags(0, NULL);
+
+ ignore_value(VIR_STRDUP(ret, sysinfo));
+ return ret;
+}
+
+static const char *
+testConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return "TEST";
+}
+
+static int testConnectListDomains(virConnectPtr conn,
+ int *ids,
+ int maxids)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ return virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
+ NULL, NULL);
+}
+
+static int testConnectNumOfDomains(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int count;
+
+ testDriverLock(privconn);
+ count = virDomainObjListNumOfDomains(privconn->domains, true, NULL, NULL);
+ testDriverUnlock(privconn);
+
+ return count;
+}
+
+static int testConnectListAllDomains(virConnectPtr conn,
+ virDomainPtr **domains,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
+
+ return virDomainObjListExport(privconn->domains, conn, domains,
+ NULL, flags);
+}
+
+static virDomainPtr
+testDomainCreateXML(virConnectPtr conn, const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainDefPtr def;
+ virDomainObjPtr dom = NULL;
+ virObjectEventPtr event = NULL;
+ unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
+
+ virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
+
+ if (flags & VIR_DOMAIN_START_VALIDATE)
+ parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
+
+ testDriverLock(privconn);
+ if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+ parse_flags)) == NULL)
+ goto cleanup;
+
+ if (testDomainGenerateIfnames(def) < 0)
+ goto cleanup;
+ if (!(dom = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+ VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+ NULL)))
+ goto cleanup;
+ def = NULL;
+
+ if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+ if (!dom->persistent) {
+ virDomainObjListRemove(privconn->domains, dom);
+ dom = NULL;
+ }
+ goto cleanup;
+ }
+
+ event = virDomainEventLifecycleNewFromObj(dom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ if (dom)
+ virObjectUnlock(dom);
+ testObjectEventQueue(privconn, event);
+ virDomainDefFree(def);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+
+static virDomainPtr testDomainLookupByID(virConnectPtr conn,
+ int id)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainObjPtr dom;
+
+ if (!(dom = virDomainObjListFindByID(privconn->domains, id))) {
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ if (dom)
+ virObjectUnlock(dom);
+ return ret;
+}
+
+static virDomainPtr testDomainLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainObjPtr dom;
+
+ if (!(dom = virDomainObjListFindByUUID(privconn->domains, uuid))) {
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ if (dom)
+ virObjectUnlock(dom);
+ return ret;
+}
+
+static virDomainPtr testDomainLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainObjPtr dom;
+
+ if (!(dom = virDomainObjListFindByName(privconn->domains, name))) {
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ virDomainObjEndAPI(&dom);
+ return ret;
+}
+
+static virDomainObjPtr
+testDomObjFromDomain(virDomainPtr domain)
+{
+ virDomainObjPtr vm;
+ testDriverPtr driver = domain->conn->privateData;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
+ if (!vm) {
+ virUUIDFormat(domain->uuid, uuidstr);
+ virReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s' (%s)"),
+ uuidstr, domain->name);
+ }
+
+ return vm;
+}
+
+static int testDomainSuspend(virDomainPtr domain)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+ int state;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ state = virDomainObjGetState(privdom, NULL);
+ if (state == VIR_DOMAIN_SHUTOFF || state == VIR_DOMAIN_PAUSED) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not running"),
+ domain->name);
+ goto cleanup;
+ }
+
+ virDomainObjSetState(privdom, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainResume(virDomainPtr domain)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_PAUSED) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not paused"),
+ domain->name);
+ goto cleanup;
+ }
+
+ virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+ VIR_DOMAIN_RUNNING_UNPAUSED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainShutdownFlags(virDomainPtr domain,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("domain '%s' not running"), domain->name);
+ goto cleanup;
+ }
+
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainShutdown(virDomainPtr domain)
+{
+ return testDomainShutdownFlags(domain, 0);
+}
+
+/* Similar behaviour as shutdown */
+static int testDomainReboot(virDomainPtr domain,
+ unsigned int action ATTRIBUTE_UNUSED)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTDOWN,
+ VIR_DOMAIN_SHUTDOWN_USER);
+
+ switch (privdom->def->onReboot) {
+ case VIR_DOMAIN_LIFECYCLE_DESTROY:
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+ VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ break;
+
+ case VIR_DOMAIN_LIFECYCLE_RESTART:
+ virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+ VIR_DOMAIN_RUNNING_BOOTED);
+ break;
+
+ case VIR_DOMAIN_LIFECYCLE_PRESERVE:
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+ VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ break;
+
+ case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME:
+ virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+ VIR_DOMAIN_RUNNING_BOOTED);
+ break;
+
+ default:
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+ VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ break;
+ }
+
+ if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+ }
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainDestroy(virDomainPtr domain)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_DESTROYED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static char *
+testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+ char *ret;
+
+ ignore_value(VIR_STRDUP(ret, "linux"));
+ return ret;
+}
+
+static unsigned long long
+testDomainGetMaxMemory(virDomainPtr domain)
+{
+ virDomainObjPtr privdom;
+ unsigned long long ret = 0;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return 0;
+
+ ret = virDomainDefGetMemoryTotal(privdom->def);
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainSetMaxMemory(virDomainPtr domain,
+ unsigned long memory)
+{
+ virDomainObjPtr privdom;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ /* XXX validate not over host memory wrt to other domains */
+ virDomainDefSetMemoryTotal(privdom->def, memory);
+
+ virDomainObjEndAPI(&privdom);
+ return 0;
+}
+
+static int testDomainSetMemory(virDomainPtr domain,
+ unsigned long memory)
+{
+ virDomainObjPtr privdom;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (memory > virDomainDefGetMemoryTotal(privdom->def)) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privdom->def->mem.cur_balloon = memory;
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainGetInfo(virDomainPtr domain,
+ virDomainInfoPtr info)
+{
+ struct timeval tv;
+ virDomainObjPtr privdom;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("getting time of day"));
+ goto cleanup;
+ }
+
+ info->state = virDomainObjGetState(privdom, NULL);
+ info->memory = privdom->def->mem.cur_balloon;
+ info->maxMem = virDomainDefGetMemoryTotal(privdom->def);
+ info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
+ info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll));
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetState(virDomainPtr domain,
+ int *state,
+ int *reason,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+
+ virCheckFlags(0, -1);
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ *state = virDomainObjGetState(privdom, reason);
+
+ virDomainObjEndAPI(&privdom);
+
+ return 0;
+}
+
+#define TEST_SAVE_MAGIC "TestGuestMagic"
+
+static int
+testDomainSaveFlags(virDomainPtr domain, const char *path,
+ const char *dxml, unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ char *xml = NULL;
+ int fd = -1;
+ int len;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+ if (dxml) {
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+ _("xml modification unsupported"));
+ return -1;
+ }
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ xml = virDomainDefFormat(privdom->def, privconn->caps,
+ VIR_DOMAIN_DEF_FORMAT_SECURE);
+
+ if (xml == NULL) {
+ virReportSystemError(errno,
+ _("saving domain '%s' failed to allocate space for metadata"),
+ domain->name);
+ goto cleanup;
+ }
+
+ if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': open failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ len = strlen(xml);
+ if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ if (safewrite(fd, (char*)&len, sizeof(len)) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ if (safewrite(fd, xml, len) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+
+ if (VIR_CLOSE(fd) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ fd = -1;
+
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SAVED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(xml);
+
+ /* Don't report failure in close or unlink, because
+ * in either case we're already in a failure scenario
+ * and have reported a earlier error */
+ if (ret != 0) {
+ VIR_FORCE_CLOSE(fd);
+ unlink(path);
+ }
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int
+testDomainSave(virDomainPtr domain,
+ const char *path)
+{
+ return testDomainSaveFlags(domain, path, NULL, 0);
+}
+
+static int
+testDomainRestoreFlags(virConnectPtr conn,
+ const char *path,
+ const char *dxml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ char *xml = NULL;
+ char magic[15];
+ int fd = -1;
+ int len;
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr dom = NULL;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+ if (dxml) {
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+ _("xml modification unsupported"));
+ return -1;
+ }
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ virReportSystemError(errno,
+ _("cannot read domain image '%s'"),
+ path);
+ goto cleanup;
+ }
+ if (saferead(fd, magic, sizeof(magic)) != sizeof(magic)) {
+ virReportSystemError(errno,
+ _("incomplete save header in '%s'"),
+ path);
+ goto cleanup;
+ }
+ if (memcmp(magic, TEST_SAVE_MAGIC, sizeof(magic))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("mismatched header magic"));
+ goto cleanup;
+ }
+ if (saferead(fd, (char*)&len, sizeof(len)) != sizeof(len)) {
+ virReportSystemError(errno,
+ _("failed to read metadata length in '%s'"),
+ path);
+ goto cleanup;
+ }
+ if (len < 1 || len > 8192) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("length of metadata out of range"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC_N(xml, len+1) < 0)
+ goto cleanup;
+ if (saferead(fd, xml, len) != len) {
+ virReportSystemError(errno,
+ _("incomplete metadata in '%s'"), path);
+ goto cleanup;
+ }
+ xml[len] = '\0';
+
+ def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+ VIR_DOMAIN_DEF_PARSE_INACTIVE);
+ if (!def)
+ goto cleanup;
+
+ if (testDomainGenerateIfnames(def) < 0)
+ goto cleanup;
+ if (!(dom = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+ VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+ NULL)))
+ goto cleanup;
+ def = NULL;
+
+ if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_RESTORED) < 0) {
+ if (!dom->persistent) {
+ virDomainObjListRemove(privconn->domains, dom);
+ dom = NULL;
+ }
+ goto cleanup;
+ }
+
+ event = virDomainEventLifecycleNewFromObj(dom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_RESTORED);
+ ret = 0;
+
+ cleanup:
+ virDomainDefFree(def);
+ VIR_FREE(xml);
+ VIR_FORCE_CLOSE(fd);
+ if (dom)
+ virObjectUnlock(dom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int
+testDomainRestore(virConnectPtr conn,
+ const char *path)
+{
+ return testDomainRestoreFlags(conn, path, NULL, 0);
+}
+
+static int testDomainCoreDumpWithFormat(virDomainPtr domain,
+ const char *to,
+ unsigned int dumpformat,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ int fd = -1;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DUMP_CRASH, -1);
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+ virReportSystemError(errno,
+ _("domain '%s' coredump: failed to open %s"),
+ domain->name, to);
+ goto cleanup;
+ }
+ if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
+ virReportSystemError(errno,
+ _("domain '%s' coredump: failed to write header to %s"),
+ domain->name, to);
+ goto cleanup;
+ }
+ if (VIR_CLOSE(fd) < 0) {
+ virReportSystemError(errno,
+ _("domain '%s' coredump: write failed: %s"),
+ domain->name, to);
+ goto cleanup;
+ }
+
+ /* we don't support non-raw formats in test driver */
+ if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("kdump-compressed format is not supported here"));
+ goto cleanup;
+ }
+
+ if (flags & VIR_DUMP_CRASH) {
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_CRASHED);
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+
+static int
+testDomainCoreDump(virDomainPtr domain,
+ const char *to,
+ unsigned int flags)
+{
+ return testDomainCoreDumpWithFormat(domain, to,
+ VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags);
+}
+
+static int
+testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
+ unsigned int flags)
+{
+ testDriverPtr driver = domain->conn->privateData;
+ virDomainObjPtr privdom = NULL;
+ virDomainDefPtr def;
+ virDomainDefPtr persistentDef;
+ int ret = -1, maxvcpus;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+ if ((maxvcpus = testConnectGetMaxVcpus(domain->conn, NULL)) < 0)
+ return -1;
+
+ if (nrCpus > maxvcpus) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested cpu amount exceeds maximum supported amount "
+ "(%d > %d)"), nrCpus, maxvcpus);
+ return -1;
+ }
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (virDomainObjGetDefs(privdom, flags, &def, &persistentDef) < 0)
+ goto cleanup;
+
+ if (def && virDomainDefGetVcpusMax(def) < nrCpus) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested cpu amount exceeds maximum (%d > %d)"),
+ nrCpus, virDomainDefGetVcpusMax(def));
+ goto cleanup;
+ }
+
+ if (persistentDef &&
+ !(flags & VIR_DOMAIN_VCPU_MAXIMUM) &&
+ virDomainDefGetVcpusMax(persistentDef) < nrCpus) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested cpu amount exceeds maximum (%d > %d)"),
+ nrCpus, virDomainDefGetVcpusMax(persistentDef));
+ goto cleanup;
+ }
+
+ if (def &&
+ virDomainDefSetVcpus(def, nrCpus) < 0)
+ goto cleanup;
+
+ if (persistentDef) {
+ if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
+ if (virDomainDefSetVcpusMax(persistentDef, nrCpus,
+ driver->xmlopt) < 0)
+ goto cleanup;
+ } else {
+ if (virDomainDefSetVcpus(persistentDef, nrCpus) < 0)
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainSetVcpus(virDomainPtr domain, unsigned int nrCpus)
+{
+ return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_AFFECT_LIVE);
+}
+
+static int testDomainGetVcpus(virDomainPtr domain,
+ virVcpuInfoPtr info,
+ int maxinfo,
+ unsigned char *cpumaps,
+ int maplen)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virDomainDefPtr def;
+ size_t i;
+ int maxcpu, hostcpus;
+ int ret = -1;
+ struct timeval tv;
+ unsigned long long statbase;
+ virBitmapPtr allcpumap = NULL;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (!virDomainObjIsActive(privdom)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot list vcpus for an inactive domain"));
+ goto cleanup;
+ }
+
+ def = privdom->def;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportSystemError(errno,
+ "%s", _("getting time of day"));
+ goto cleanup;
+ }
+
+ statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+
+ hostcpus = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo);
+ maxcpu = maplen * 8;
+ if (maxcpu > hostcpus)
+ maxcpu = hostcpus;
+
+ if (!(allcpumap = virBitmapNew(hostcpus)))
+ goto cleanup;
+
+ virBitmapSetAll(allcpumap);
+
+ /* Clamp to actual number of vcpus */
+ if (maxinfo > virDomainDefGetVcpus(privdom->def))
+ maxinfo = virDomainDefGetVcpus(privdom->def);
+
+ memset(info, 0, sizeof(*info) * maxinfo);
+ memset(cpumaps, 0, maxinfo * maplen);
+
+ for (i = 0; i < maxinfo; i++) {
+ virDomainVcpuDefPtr vcpu = virDomainDefGetVcpu(def, i);
+ virBitmapPtr bitmap = NULL;
+
+ if (!vcpu->online)
+ continue;
+
+ if (vcpu->cpumask)
+ bitmap = vcpu->cpumask;
+ else if (def->cpumask)
+ bitmap = def->cpumask;
+ else
+ bitmap = allcpumap;
+
+ if (cpumaps)
+ virBitmapToDataBuf(bitmap, VIR_GET_CPUMAP(cpumaps, maplen, i), maplen);
+
+ info[i].number = i;
+ info[i].state = VIR_VCPU_RUNNING;
+ info[i].cpu = virBitmapLastSetBit(bitmap);
+
+ /* Fake an increasing cpu time value */
+ info[i].cpuTime = statbase / 10;
+ }
+
+ ret = maxinfo;
+ cleanup:
+ virBitmapFree(allcpumap);
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainPinVcpu(virDomainPtr domain,
+ unsigned int vcpu,
+ unsigned char *cpumap,
+ int maplen)
+{
+ virDomainVcpuDefPtr vcpuinfo;
+ virDomainObjPtr privdom;
+ virDomainDefPtr def;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ def = privdom->def;
+
+ if (!virDomainObjIsActive(privdom)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot pin vcpus on an inactive domain"));
+ goto cleanup;
+ }
+
+ if (!(vcpuinfo = virDomainDefGetVcpu(def, vcpu)) ||
+ !vcpuinfo->online) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested vcpu '%d' is not present in the domain"),
+ vcpu);
+ goto cleanup;
+ }
+
+ virBitmapFree(vcpuinfo->cpumask);
+
+ if (!(vcpuinfo->cpumask = virBitmapNewData(cpumap, maplen)))
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetVcpuPinInfo(virDomainPtr dom,
+ int ncpumaps,
+ unsigned char *cpumaps,
+ int maplen,
+ unsigned int flags)
+{
+ testDriverPtr driver = dom->conn->privateData;
+ virDomainObjPtr privdom;
+ virDomainDefPtr def;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(privdom, flags)))
+ goto cleanup;
+
+ ret = virDomainDefGetVcpuPinInfoHelper(def, maplen, ncpumaps, cpumaps,
+ VIR_NODEINFO_MAXCPUS(driver->nodeInfo),
+ NULL);
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainDefPtr def;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(vm, flags)))
+ goto cleanup;
+
+ if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
+ ret = virDomainDefGetVcpusMax(def);
+ else
+ ret = virDomainDefGetVcpus(def);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainGetMaxVcpus(virDomainPtr domain)
+{
+ return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_VCPU_MAXIMUM));
+}
+
+static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainDefPtr def;
+ virDomainObjPtr privdom;
+ char *ret = NULL;
+
+ /* Flags checked by virDomainDefFormat */
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return NULL;
+
+ def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
+ privdom->newDef ? privdom->newDef : privdom->def;
+
+ ret = virDomainDefFormat(def, privconn->caps,
+ virDomainDefFormatConvertXMLFlags(flags));
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testConnectNumOfDefinedDomains(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ return virDomainObjListNumOfDomains(privconn->domains, false, NULL, NULL);
+}
+
+static int testConnectListDefinedDomains(virConnectPtr conn,
+ char **const names,
+ int maxnames)
+{
+
+ testDriverPtr privconn = conn->privateData;
+
+ memset(names, 0, sizeof(*names)*maxnames);
+ return virDomainObjListGetInactiveNames(privconn->domains, names, maxnames,
+ NULL, NULL);
+}
+
+static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Domain '%s' is already running"), domain->name);
+ goto cleanup;
+ }
+
+ if (testDomainStartState(privconn, privdom,
+ VIR_DOMAIN_RUNNING_BOOTED) < 0)
+ goto cleanup;
+ domain->id = privdom->def->id;
+
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testDomainCreate(virDomainPtr domain)
+{
+ return testDomainCreateWithFlags(domain, 0);
+}
+
+static virDomainPtr testDomainDefineXMLFlags(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainDefPtr def;
+ virDomainObjPtr dom = NULL;
+ virObjectEventPtr event = NULL;
+ virDomainDefPtr oldDef = NULL;
+ unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
+
+ virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
+
+ if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
+ parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
+
+ if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+ parse_flags)) == NULL)
+ goto cleanup;
+
+ if (testDomainGenerateIfnames(def) < 0)
+ goto cleanup;
+ if (!(dom = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ 0,
+ &oldDef)))
+ goto cleanup;
+ def = NULL;
+ dom->persistent = 1;
+
+ event = virDomainEventLifecycleNewFromObj(dom,
+ VIR_DOMAIN_EVENT_DEFINED,
+ !oldDef ?
+ VIR_DOMAIN_EVENT_DEFINED_ADDED :
+ VIR_DOMAIN_EVENT_DEFINED_UPDATED);
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ virDomainDefFree(def);
+ virDomainDefFree(oldDef);
+ if (dom)
+ virObjectUnlock(dom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static virDomainPtr
+testDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+ return testDomainDefineXMLFlags(conn, xml, 0);
+}
+
+static int testDomainUndefineFlags(virDomainPtr domain,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int nsnapshots;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
+ VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (privdom->hasManagedSave &&
+ !(flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Refusing to undefine while domain managed "
+ "save image exists"));
+ goto cleanup;
+ }
+
+ /* Requiring an inactive VM is part of the documented API for
+ * UNDEFINE_SNAPSHOTS_METADATA
+ */
+ if (!virDomainObjIsActive(privdom) &&
+ (nsnapshots = virDomainSnapshotObjListNum(privdom->snapshots,
+ NULL, 0))) {
+ if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("cannot delete inactive domain with %d "
+ "snapshots"),
+ nsnapshots);
+ goto cleanup;
+ }
+
+ /* There isn't actually anything to do, we are just emulating qemu
+ * behavior here. */
+ }
+
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+ privdom->hasManagedSave = false;
+
+ if (virDomainObjIsActive(privdom))
+ privdom->persistent = 0;
+ else
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainUndefine(virDomainPtr domain)
+{
+ return testDomainUndefineFlags(domain, 0);
+}
+
+static int testDomainGetAutostart(virDomainPtr domain,
+ int *autostart)
+{
+ virDomainObjPtr privdom;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ *autostart = privdom->autostart;
+
+ virDomainObjEndAPI(&privdom);
+ return 0;
+}
+
+
+static int testDomainSetAutostart(virDomainPtr domain,
+ int autostart)
+{
+ virDomainObjPtr privdom;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ privdom->autostart = autostart ? 1 : 0;
+
+ virDomainObjEndAPI(&privdom);
+ return 0;
+}
+
+static char *testDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
+ int *nparams)
+{
+ char *type = NULL;
+
+ if (nparams)
+ *nparams = 1;
+
+ ignore_value(VIR_STRDUP(type, "fair"));
+
+ return type;
+}
+
+static int
+testDomainGetSchedulerParametersFlags(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (virTypedParameterAssign(params, VIR_DOMAIN_SCHEDULER_WEIGHT,
+ VIR_TYPED_PARAM_UINT, 50) < 0)
+ goto cleanup;
+ /* XXX */
+ /*params[0].value.ui = privdom->weight;*/
+
+ *nparams = 1;
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetSchedulerParameters(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int *nparams)
+{
+ return testDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
+}
+
+static int
+testDomainSetSchedulerParametersFlags(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+ int ret = -1;
+ size_t i;
+
+ virCheckFlags(0, -1);
+ if (virTypedParamsValidate(params, nparams,
+ VIR_DOMAIN_SCHEDULER_WEIGHT,
+ VIR_TYPED_PARAM_UINT,
+ NULL) < 0)
+ return -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ for (i = 0; i < nparams; i++) {
+ if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) {
+ /* XXX */
+ /*privdom->weight = params[i].value.ui;*/
+ }
+ }
+
+ ret = 0;
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainSetSchedulerParameters(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int nparams)
+{
+ return testDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
+}
+
+static int testDomainBlockStats(virDomainPtr domain,
+ const char *path,
+ virDomainBlockStatsPtr stats)
+{
+ virDomainObjPtr privdom;
+ struct timeval tv;
+ unsigned long long statbase;
+ int ret = -1;
+
+ if (!*path) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("summary statistics are not supported yet"));
+ return ret;
+ }
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return ret;
+
+ if (virDomainDiskIndexByName(privdom->def, path, false) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path: %s"), path);
+ goto error;
+ }
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportSystemError(errno,
+ "%s", _("getting time of day"));
+ goto error;
+ }
+
+ /* No significance to these numbers, just enough to mix it up*/
+ statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+ stats->rd_req = statbase / 10;
+ stats->rd_bytes = statbase / 20;
+ stats->wr_req = statbase / 30;
+ stats->wr_bytes = statbase / 40;
+ stats->errs = tv.tv_sec / 2;
+
+ ret = 0;
+ error:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainInterfaceStats(virDomainPtr domain,
+ const char *path,
+ virDomainInterfaceStatsPtr stats)
+{
+ virDomainObjPtr privdom;
+ struct timeval tv;
+ unsigned long long statbase;
+ size_t i;
+ int found = 0, ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ for (i = 0; i < privdom->def->nnets; i++) {
+ if (privdom->def->nets[i]->ifname &&
+ STREQ(privdom->def->nets[i]->ifname, path)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path, '%s' is not a known interface"), path);
+ goto error;
+ }
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportSystemError(errno,
+ "%s", _("getting time of day"));
+ goto error;
+ }
+
+ /* No significance to these numbers, just enough to mix it up*/
+ statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+ stats->rx_bytes = statbase / 10;
+ stats->rx_packets = statbase / 100;
+ stats->rx_errs = tv.tv_sec / 1;
+ stats->rx_drop = tv.tv_sec / 2;
+ stats->tx_bytes = statbase / 20;
+ stats->tx_packets = statbase / 110;
+ stats->tx_errs = tv.tv_sec / 3;
+ stats->tx_drop = tv.tv_sec / 4;
+
+ ret = 0;
+ error:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testNodeGetCellsFreeMemory(virConnectPtr conn,
+ unsigned long long *freemems,
+ int startCell, int maxCells)
+{
+ testDriverPtr privconn = conn->privateData;
+ int cell;
+ size_t i;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ if (startCell > privconn->numCells) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("Range exceeds available cells"));
+ goto cleanup;
+ }
+
+ for (cell = startCell, i = 0;
+ (cell < privconn->numCells && i < maxCells);
+ ++cell, ++i) {
+ freemems[i] = privconn->cells[cell].mem;
+ }
+ ret = i;
+
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+/* Domain event implementations */
+static int
+testConnectDomainEventRegister(virConnectPtr conn,
+ virConnectDomainEventCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virDomainEventStateRegister(conn, driver->eventState,
+ callback, opaque, freecb) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int
+testConnectDomainEventDeregister(virConnectPtr conn,
+ virConnectDomainEventCallback callback)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virDomainEventStateDeregister(conn, driver->eventState,
+ callback) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int
+testConnectDomainEventRegisterAny(virConnectPtr conn,
+ virDomainPtr dom,
+ int eventID,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virDomainEventStateRegisterID(conn, driver->eventState,
+ dom, eventID,
+ callback, opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectDomainEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int testConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int testConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static int testConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static int testDomainIsActive(virDomainPtr dom)
+{
+ virDomainObjPtr obj;
+ int ret;
+
+ if (!(obj = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = virDomainObjIsActive(obj);
+ virDomainObjEndAPI(&obj);
+ return ret;
+}
+
+static int testDomainIsPersistent(virDomainPtr dom)
+{
+ virDomainObjPtr obj;
+ int ret;
+
+ if (!(obj = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = obj->persistent;
+
+ virDomainObjEndAPI(&obj);
+ return ret;
+}
+
+static int testDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+static int
+testNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned char **cpumap,
+ unsigned int *online,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (cpumap) {
+ if (VIR_ALLOC_N(*cpumap, 1) < 0)
+ return -1;
+ *cpumap[0] = 0x15;
+ }
+
+ if (online)
+ *online = 3;
+
+ return 8;
+}
+
+static char *
+testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED,
+ virStreamPtr st,
+ unsigned int screen ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (VIR_STRDUP(ret, "image/png") < 0)
+ return NULL;
+
+ if (virFDStreamOpenFile(st, PKGDATADIR "/libvirtLogo.png", 0, 0, O_RDONLY) < 0)
+ VIR_FREE(ret);
+
+ return ret;
+}
+
+static char *testDomainGetMetadata(virDomainPtr dom,
+ int type,
+ const char *uri,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+ char *ret;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, NULL);
+
+ if (!(privdom = testDomObjFromDomain(dom)))
+ return NULL;
+
+ ret = virDomainObjGetMetadata(privdom, type, uri, flags);
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainSetMetadata(virDomainPtr dom,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags)
+{
+ testDriverPtr privconn = dom->conn->privateData;
+ virDomainObjPtr privdom;
+ int ret;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ if (!(privdom = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
+ privconn->caps, privconn->xmlopt,
+ NULL, NULL, flags);
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *arch,
+ char ***models,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+ return cpuGetModels(arch, models);
+}
+
+static int
+testDomainManagedSave(virDomainPtr dom, unsigned int flags)
+{
+ testDriverPtr privconn = dom->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
+ VIR_DOMAIN_SAVE_RUNNING |
+ VIR_DOMAIN_SAVE_PAUSED, -1);
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (!vm->persistent) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot do managed save for transient domain"));
+ goto cleanup;
+ }
+
+ testDomainShutdownState(dom, vm, VIR_DOMAIN_SHUTOFF_SAVED);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+ vm->hasManagedSave = true;
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ testObjectEventQueue(privconn, event);
+
+ return ret;
+}
+
+static int
+testDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
+{
+ virDomainObjPtr vm;
+ int ret;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = vm->hasManagedSave;
+
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
+{
+ virDomainObjPtr vm;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ vm->hasManagedSave = false;
+
+ virDomainObjEndAPI(&vm);
+ return 0;
+}
+
+/*
+ * Snapshot APIs
+ */
+
+static virDomainSnapshotObjPtr
+testSnapObjFromName(virDomainObjPtr vm,
+ const char *name)
+{
+ virDomainSnapshotObjPtr snap = NULL;
+ snap = virDomainSnapshotFindByName(vm->snapshots, name);
+ if (!snap)
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+ _("no domain snapshot with matching name '%s'"),
+ name);
+ return snap;
+}
+
+static virDomainSnapshotObjPtr
+testSnapObjFromSnapshot(virDomainObjPtr vm,
+ virDomainSnapshotPtr snapshot)
+{
+ return testSnapObjFromName(vm, snapshot->name);
+}
+
+static virDomainObjPtr
+testDomObjFromSnapshot(virDomainSnapshotPtr snapshot)
+{
+ return testDomObjFromDomain(snapshot->domain);
+}
+
+static int
+testDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int n;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
+
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotListNames(virDomainPtr domain,
+ char **names,
+ int nameslen,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int n;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
+ flags);
+
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainListAllSnapshots(virDomainPtr domain,
+ virDomainSnapshotPtr **snaps,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int n;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
+
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
+ char **names,
+ int nameslen,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
+ flags);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
+ virDomainSnapshotPtr **snaps,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
+ flags);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotLookupByName(virDomainPtr domain,
+ const char *name,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotPtr snapshot = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return NULL;
+
+ if (!(snap = testSnapObjFromName(vm, name)))
+ goto cleanup;
+
+ snapshot = virGetDomainSnapshot(domain, snap->def->name);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return snapshot;
+}
+
+static int
+testDomainHasCurrentSnapshot(virDomainPtr domain,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ int ret;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ ret = (vm->current_snapshot != NULL);
+
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotPtr parent = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return NULL;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ if (!snap->def->parent) {
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+ _("snapshot '%s' does not have a parent"),
+ snap->def->name);
+ goto cleanup;
+ }
+
+ parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return parent;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotCurrent(virDomainPtr domain,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainSnapshotPtr snapshot = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return NULL;
+
+ if (!vm->current_snapshot) {
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
+ _("the domain does not have a current snapshot"));
+ goto cleanup;
+ }
+
+ snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return snapshot;
+}
+
+static char *
+testDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ char *xml = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ testDriverPtr privconn = snapshot->domain->conn->privateData;
+
+ virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return NULL;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+ xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->caps,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return xml;
+}
+
+static int
+testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int ret;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ ret = (vm->current_snapshot &&
+ STREQ(snapshot->name, vm->current_snapshot->def->name));
+
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+
+static int
+testDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!testSnapObjFromSnapshot(vm, snapshot))
+ goto cleanup;
+
+ ret = 1;
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainSnapshotAlignDisks(virDomainObjPtr vm,
+ virDomainSnapshotDefPtr def,
+ unsigned int flags)
+{
+ int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+ bool align_match = true;
+
+ if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
+ align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
+ align_match = false;
+ if (virDomainObjIsActive(vm))
+ def->state = VIR_DOMAIN_DISK_SNAPSHOT;
+ else
+ def->state = VIR_DOMAIN_SHUTOFF;
+ def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
+ } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
+ def->state = virDomainObjGetState(vm, NULL);
+ align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
+ align_match = false;
+ } else {
+ def->state = virDomainObjGetState(vm, NULL);
+ def->memory = def->state == VIR_DOMAIN_SHUTOFF ?
+ VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
+ VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+ }
+
+ return virDomainSnapshotAlignDisks(def, align_location, align_match);
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotCreateXML(virDomainPtr domain,
+ const char *xmlDesc,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotDefPtr def = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotPtr snapshot = NULL;
+ virObjectEventPtr event = NULL;
+ char *xml = NULL;
+ bool update_current = true;
+ bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
+ unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
+
+ /*
+ * DISK_ONLY: Not implemented yet
+ * REUSE_EXT: Not implemented yet
+ *
+ * NO_METADATA: Explicitly not implemented
+ *
+ * REDEFINE + CURRENT: Implemented
+ * HALT: Implemented
+ * QUIESCE: Nothing to do
+ * ATOMIC: Nothing to do
+ * LIVE: Nothing to do
+ */
+ virCheckFlags(
+ VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
+ VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
+ VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
+ VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
+ VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
+ VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
+
+ if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)))
+ update_current = false;
+ if (redefine)
+ parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot halt after transient domain snapshot"));
+ goto cleanup;
+ }
+
+ if (!(def = virDomainSnapshotDefParseString(xmlDesc,
+ privconn->caps,
+ privconn->xmlopt,
+ parse_flags)))
+ goto cleanup;
+
+ if (redefine) {
+ if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
+ &update_current, flags) < 0)
+ goto cleanup;
+ } else {
+ if (!(def->dom = virDomainDefCopy(vm->def,
+ privconn->caps,
+ privconn->xmlopt,
+ true)))
+ goto cleanup;
+
+ if (testDomainSnapshotAlignDisks(vm, def, flags) < 0)
+ goto cleanup;
+ }
+
+ if (!snap) {
+ if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
+ goto cleanup;
+ def = NULL;
+ }
+
+ if (!redefine) {
+ if (vm->current_snapshot &&
+ (VIR_STRDUP(snap->def->parent,
+ vm->current_snapshot->def->name) < 0))
+ goto cleanup;
+
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) &&
+ virDomainObjIsActive(vm)) {
+ testDomainShutdownState(domain, vm,
+ VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+ event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+ }
+ }
+
+ snapshot = virGetDomainSnapshot(domain, snap->def->name);
+ cleanup:
+ VIR_FREE(xml);
+ if (vm) {
+ if (snapshot) {
+ virDomainSnapshotObjPtr other;
+ if (update_current)
+ vm->current_snapshot = snap;
+ other = virDomainSnapshotFindByName(vm->snapshots,
+ snap->def->parent);
+ snap->parent = other;
+ other->nchildren++;
+ snap->sibling = other->first_child;
+ other->first_child = snap;
+ }
+ virDomainObjEndAPI(&vm);
+ }
+ testObjectEventQueue(privconn, event);
+ virDomainSnapshotDefFree(def);
+ return snapshot;
+}
+
+
+typedef struct _testSnapRemoveData testSnapRemoveData;
+typedef testSnapRemoveData *testSnapRemoveDataPtr;
+struct _testSnapRemoveData {
+ virDomainObjPtr vm;
+ bool current;
+};
+
+static int
+testDomainSnapshotDiscardAll(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data)
+{
+ virDomainSnapshotObjPtr snap = payload;
+ testSnapRemoveDataPtr curr = data;
+
+ if (snap->def->current)
+ curr->current = true;
+ virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
+ return 0;
+}
+
+typedef struct _testSnapReparentData testSnapReparentData;
+typedef testSnapReparentData *testSnapReparentDataPtr;
+struct _testSnapReparentData {
+ virDomainSnapshotObjPtr parent;
+ virDomainObjPtr vm;
+ int err;
+ virDomainSnapshotObjPtr last;
+};
+
+static int
+testDomainSnapshotReparentChildren(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data)
+{
+ virDomainSnapshotObjPtr snap = payload;
+ testSnapReparentDataPtr rep = data;
+
+ if (rep->err < 0)
+ return 0;
+
+ VIR_FREE(snap->def->parent);
+ snap->parent = rep->parent;
+
+ if (rep->parent->def &&
+ VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
+ rep->err = -1;
+ return 0;
+ }
+
+ if (!snap->sibling)
+ rep->last = snap;
+ return 0;
+}
+
+static int
+testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotObjPtr parentsnap = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
+ VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
+ VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
+ testSnapRemoveData rem;
+ rem.vm = vm;
+ rem.current = false;
+ virDomainSnapshotForEachDescendant(snap,
+ testDomainSnapshotDiscardAll,
+ &rem);
+ if (rem.current) {
+ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)
+ snap->def->current = true;
+ vm->current_snapshot = snap;
+ }
+ } else if (snap->nchildren) {
+ testSnapReparentData rep;
+ rep.parent = snap->parent;
+ rep.vm = vm;
+ rep.err = 0;
+ rep.last = NULL;
+ virDomainSnapshotForEachChild(snap,
+ testDomainSnapshotReparentChildren,
+ &rep);
+ if (rep.err < 0)
+ goto cleanup;
+
+ /* Can't modify siblings during ForEachChild, so do it now. */
+ snap->parent->nchildren += snap->nchildren;
+ rep.last->sibling = snap->parent->first_child;
+ snap->parent->first_child = snap->first_child;
+ }
+
+ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
+ snap->nchildren = 0;
+ snap->first_child = NULL;
+ } else {
+ virDomainSnapshotDropParent(snap);
+ if (snap == vm->current_snapshot) {
+ if (snap->def->parent) {
+ parentsnap = virDomainSnapshotFindByName(vm->snapshots,
+ snap->def->parent);
+ if (!parentsnap) {
+ VIR_WARN("missing parent snapshot matching name '%s'",
+ snap->def->parent);
+ } else {
+ parentsnap->def->current = true;
+ }
+ }
+ vm->current_snapshot = parentsnap;
+ }
+ virDomainSnapshotObjListRemove(vm->snapshots, snap);
+ }
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ testDriverPtr privconn = snapshot->domain->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ virObjectEventPtr event = NULL;
+ virObjectEventPtr event2 = NULL;
+ virDomainDefPtr config = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
+ VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
+
+ /* We have the following transitions, which create the following events:
+ * 1. inactive -> inactive: none
+ * 2. inactive -> running: EVENT_STARTED
+ * 3. inactive -> paused: EVENT_STARTED, EVENT_PAUSED
+ * 4. running -> inactive: EVENT_STOPPED
+ * 5. running -> running: none
+ * 6. running -> paused: EVENT_PAUSED
+ * 7. paused -> inactive: EVENT_STOPPED
+ * 8. paused -> running: EVENT_RESUMED
+ * 9. paused -> paused: none
+ * Also, several transitions occur even if we fail partway through,
+ * and use of FORCE can cause multiple transitions.
+ */
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ if (!vm->persistent &&
+ snap->def->state != VIR_DOMAIN_RUNNING &&
+ snap->def->state != VIR_DOMAIN_PAUSED &&
+ (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("transient domain needs to request run or pause "
+ "to revert to inactive snapshot"));
+ goto cleanup;
+ }
+
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
+ if (!snap->def->dom) {
+ virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
+ _("snapshot '%s' lacks domain '%s' rollback info"),
+ snap->def->name, vm->def->name);
+ goto cleanup;
+ }
+ if (virDomainObjIsActive(vm) &&
+ !(snap->def->state == VIR_DOMAIN_RUNNING
+ || snap->def->state == VIR_DOMAIN_PAUSED) &&
+ (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
+ virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
+ _("must respawn guest to start inactive snapshot"));
+ goto cleanup;
+ }
+ }
+
+
+ if (vm->current_snapshot) {
+ vm->current_snapshot->def->current = false;
+ vm->current_snapshot = NULL;
+ }
+
+ snap->def->current = true;
+ config = virDomainDefCopy(snap->def->dom,
+ privconn->caps, privconn->xmlopt, true);
+ if (!config)
+ goto cleanup;
+
+ if (snap->def->state == VIR_DOMAIN_RUNNING ||
+ snap->def->state == VIR_DOMAIN_PAUSED) {
+ /* Transitions 2, 3, 5, 6, 8, 9 */
+ bool was_running = false;
+ bool was_stopped = false;
+
+ if (virDomainObjIsActive(vm)) {
+ /* Transitions 5, 6, 8, 9 */
+ /* Check for ABI compatibility. */
+ if (!virDomainDefCheckABIStability(vm->def, config)) {
+ virErrorPtr err = virGetLastError();
+
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
+ /* Re-spawn error using correct category. */
+ if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
+ virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
+ err->str2);
+ goto cleanup;
+ }
+
+ virResetError(err);
+ testDomainShutdownState(snapshot->domain, vm,
+ VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+ testObjectEventQueue(privconn, event);
+ goto load;
+ }
+
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ /* Transitions 5, 6 */
+ was_running = true;
+ virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+ VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+ /* Create an event now in case the restore fails, so
+ * that user will be alerted that they are now paused.
+ * If restore later succeeds, we might replace this. */
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+ }
+ virDomainObjAssignDef(vm, config, false, NULL);
+
+ } else {
+ /* Transitions 2, 3 */
+ load:
+ was_stopped = true;
+ virDomainObjAssignDef(vm, config, false, NULL);
+ if (testDomainStartState(privconn, vm,
+ VIR_DOMAIN_RUNNING_FROM_SNAPSHOT) < 0)
+ goto cleanup;
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+ }
+
+ /* Touch up domain state. */
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
+ (snap->def->state == VIR_DOMAIN_PAUSED ||
+ (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
+ /* Transitions 3, 6, 9 */
+ virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+ VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+ if (was_stopped) {
+ /* Transition 3, use event as-is and add event2 */
+ event2 = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+ } /* else transition 6 and 9 use event as-is */
+ } else {
+ /* Transitions 2, 5, 8 */
+ virObjectUnref(event);
+ event = NULL;
+
+ if (was_stopped) {
+ /* Transition 2 */
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+ } else if (was_running) {
+ /* Transition 8 */
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED);
+ }
+ }
+ } else {
+ /* Transitions 1, 4, 7 */
+ virDomainObjAssignDef(vm, config, false, NULL);
+
+ if (virDomainObjIsActive(vm)) {
+ /* Transitions 4, 7 */
+ testDomainShutdownState(snapshot->domain, vm,
+ VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+ }
+
+ if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
+ /* Flush first event, now do transition 2 or 3 */
+ bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
+
+ testObjectEventQueue(privconn, event);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+ if (paused) {
+ event2 = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+ }
+ }
+ }
+
+ vm->current_snapshot = snap;
+ ret = 0;
+ cleanup:
+ if (event) {
+ testObjectEventQueue(privconn, event);
+ testObjectEventQueue(privconn, event2);
+ } else {
+ virObjectUnref(event2);
+ }
+ virDomainObjEndAPI(&vm);
+
+ return ret;
+}
+
+static char *
+testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char **xmlCPUs,
+ unsigned int ncpus,
+ unsigned int flags)
+{
+ char *cpu;
+
+ virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
+
+ cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
+
+ return cpu;
+}
+
+virHypervisorDriver testHypervisorDriver = {
+ .name = "Test",
+ .connectOpen = testConnectOpen, /* 0.1.1 */
+ .connectClose = testConnectClose, /* 0.1.1 */
+ .connectGetVersion = testConnectGetVersion, /* 0.1.1 */
+ .connectGetHostname = testConnectGetHostname, /* 0.6.3 */
+ .connectGetMaxVcpus = testConnectGetMaxVcpus, /* 0.3.2 */
+ .nodeGetInfo = testNodeGetInfo, /* 0.1.1 */
+ .nodeGetCPUStats = testNodeGetCPUStats, /* 2.3.0 */
+ .nodeGetFreeMemory = testNodeGetFreeMemory, /* 2.3.0 */
+ .nodeGetFreePages = testNodeGetFreePages, /* 2.3.0 */
+ .connectGetCapabilities = testConnectGetCapabilities, /* 0.2.1 */
+ .connectGetSysinfo = testConnectGetSysinfo, /* 2.3.0 */
+ .connectGetType = testConnectGetType, /* 2.3.0 */
+ .connectListDomains = testConnectListDomains, /* 0.1.1 */
+ .connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
+ .connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
+ .domainCreateXML = testDomainCreateXML, /* 0.1.4 */
+ .domainLookupByID = testDomainLookupByID, /* 0.1.1 */
+ .domainLookupByUUID = testDomainLookupByUUID, /* 0.1.1 */
+ .domainLookupByName = testDomainLookupByName, /* 0.1.1 */
+ .domainSuspend = testDomainSuspend, /* 0.1.1 */
+ .domainResume = testDomainResume, /* 0.1.1 */
+ .domainShutdown = testDomainShutdown, /* 0.1.1 */
+ .domainShutdownFlags = testDomainShutdownFlags, /* 0.9.10 */
+ .domainReboot = testDomainReboot, /* 0.1.1 */
+ .domainDestroy = testDomainDestroy, /* 0.1.1 */
+ .domainGetOSType = testDomainGetOSType, /* 0.1.9 */
+ .domainGetMaxMemory = testDomainGetMaxMemory, /* 0.1.4 */
+ .domainSetMaxMemory = testDomainSetMaxMemory, /* 0.1.1 */
+ .domainSetMemory = testDomainSetMemory, /* 0.1.4 */
+ .domainGetInfo = testDomainGetInfo, /* 0.1.1 */
+ .domainGetState = testDomainGetState, /* 0.9.2 */
+ .domainSave = testDomainSave, /* 0.3.2 */
+ .domainSaveFlags = testDomainSaveFlags, /* 0.9.4 */
+ .domainRestore = testDomainRestore, /* 0.3.2 */
+ .domainRestoreFlags = testDomainRestoreFlags, /* 0.9.4 */
+ .domainCoreDump = testDomainCoreDump, /* 0.3.2 */
+ .domainCoreDumpWithFormat = testDomainCoreDumpWithFormat, /* 1.2.3 */
+ .domainSetVcpus = testDomainSetVcpus, /* 0.1.4 */
+ .domainSetVcpusFlags = testDomainSetVcpusFlags, /* 0.8.5 */
+ .domainGetVcpusFlags = testDomainGetVcpusFlags, /* 0.8.5 */
+ .domainPinVcpu = testDomainPinVcpu, /* 0.7.3 */
+ .domainGetVcpus = testDomainGetVcpus, /* 0.7.3 */
+ .domainGetVcpuPinInfo = testDomainGetVcpuPinInfo, /* 1.2.18 */
+ .domainGetMaxVcpus = testDomainGetMaxVcpus, /* 0.7.3 */
+ .domainGetXMLDesc = testDomainGetXMLDesc, /* 0.1.4 */
+ .connectListDefinedDomains = testConnectListDefinedDomains, /* 0.1.11 */
+ .connectNumOfDefinedDomains = testConnectNumOfDefinedDomains, /* 0.1.11 */
+ .domainCreate = testDomainCreate, /* 0.1.11 */
+ .domainCreateWithFlags = testDomainCreateWithFlags, /* 0.8.2 */
+ .domainDefineXML = testDomainDefineXML, /* 0.1.11 */
+ .domainDefineXMLFlags = testDomainDefineXMLFlags, /* 1.2.12 */
+ .domainUndefine = testDomainUndefine, /* 0.1.11 */
+ .domainUndefineFlags = testDomainUndefineFlags, /* 0.9.4 */
+ .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */
+ .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */
+ .domainGetSchedulerType = testDomainGetSchedulerType, /* 0.3.2 */
+ .domainGetSchedulerParameters = testDomainGetSchedulerParameters, /* 0.3.2 */
+ .domainGetSchedulerParametersFlags = testDomainGetSchedulerParametersFlags, /* 0.9.2 */
+ .domainSetSchedulerParameters = testDomainSetSchedulerParameters, /* 0.3.2 */
+ .domainSetSchedulerParametersFlags = testDomainSetSchedulerParametersFlags, /* 0.9.2 */
+ .domainBlockStats = testDomainBlockStats, /* 0.7.0 */
+ .domainInterfaceStats = testDomainInterfaceStats, /* 0.7.0 */
+ .nodeGetCellsFreeMemory = testNodeGetCellsFreeMemory, /* 0.4.2 */
+ .connectDomainEventRegister = testConnectDomainEventRegister, /* 0.6.0 */
+ .connectDomainEventDeregister = testConnectDomainEventDeregister, /* 0.6.0 */
+ .connectIsEncrypted = testConnectIsEncrypted, /* 0.7.3 */
+ .connectIsSecure = testConnectIsSecure, /* 0.7.3 */
+ .domainIsActive = testDomainIsActive, /* 0.7.3 */
+ .domainIsPersistent = testDomainIsPersistent, /* 0.7.3 */
+ .domainIsUpdated = testDomainIsUpdated, /* 0.8.6 */
+ .connectDomainEventRegisterAny = testConnectDomainEventRegisterAny, /* 0.8.0 */
+ .connectDomainEventDeregisterAny = testConnectDomainEventDeregisterAny, /* 0.8.0 */
+ .connectIsAlive = testConnectIsAlive, /* 0.9.8 */
+ .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */
+ .domainScreenshot = testDomainScreenshot, /* 1.0.5 */
+ .domainGetMetadata = testDomainGetMetadata, /* 1.1.3 */
+ .domainSetMetadata = testDomainSetMetadata, /* 1.1.3 */
+ .connectGetCPUModelNames = testConnectGetCPUModelNames, /* 1.1.3 */
+ .domainManagedSave = testDomainManagedSave, /* 1.1.4 */
+ .domainHasManagedSaveImage = testDomainHasManagedSaveImage, /* 1.1.4 */
+ .domainManagedSaveRemove = testDomainManagedSaveRemove, /* 1.1.4 */
+
+ .domainSnapshotNum = testDomainSnapshotNum, /* 1.1.4 */
+ .domainSnapshotListNames = testDomainSnapshotListNames, /* 1.1.4 */
+ .domainListAllSnapshots = testDomainListAllSnapshots, /* 1.1.4 */
+ .domainSnapshotGetXMLDesc = testDomainSnapshotGetXMLDesc, /* 1.1.4 */
+ .domainSnapshotNumChildren = testDomainSnapshotNumChildren, /* 1.1.4 */
+ .domainSnapshotListChildrenNames = testDomainSnapshotListChildrenNames, /* 1.1.4 */
+ .domainSnapshotListAllChildren = testDomainSnapshotListAllChildren, /* 1.1.4 */
+ .domainSnapshotLookupByName = testDomainSnapshotLookupByName, /* 1.1.4 */
+ .domainHasCurrentSnapshot = testDomainHasCurrentSnapshot, /* 1.1.4 */
+ .domainSnapshotGetParent = testDomainSnapshotGetParent, /* 1.1.4 */
+ .domainSnapshotCurrent = testDomainSnapshotCurrent, /* 1.1.4 */
+ .domainSnapshotIsCurrent = testDomainSnapshotIsCurrent, /* 1.1.4 */
+ .domainSnapshotHasMetadata = testDomainSnapshotHasMetadata, /* 1.1.4 */
+ .domainSnapshotCreateXML = testDomainSnapshotCreateXML, /* 1.1.4 */
+ .domainRevertToSnapshot = testDomainRevertToSnapshot, /* 1.1.4 */
+ .domainSnapshotDelete = testDomainSnapshotDelete, /* 1.1.4 */
+
+ .connectBaselineCPU = testConnectBaselineCPU, /* 1.2.0 */
+};
diff --git a/src/test/test_hypervisor_driver.h b/src/test/test_hypervisor_driver.h
new file mode 100644
index 0000000..ffca9c2
--- /dev/null
+++ b/src/test/test_hypervisor_driver.h
@@ -0,0 +1 @@
+extern virHypervisorDriver testHypervisorDriver;
diff --git a/src/test/test_interface_driver.c b/src/test/test_interface_driver.c
new file mode 100644
index 0000000..a749b9f
--- /dev/null
+++ b/src/test/test_interface_driver.c
@@ -0,0 +1,487 @@
+/*
+ * test_interface_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_interface_driver.h"
+
+#include "test_private_driver.h"
+
+static int testConnectNumOfInterfaces(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ int count = 0;
+
+ testDriverLock(privconn);
+ for (i = 0; (i < privconn->ifaces.count); i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (virInterfaceObjIsActive(privconn->ifaces.objs[i]))
+ count++;
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+ return count;
+}
+
+static int testConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
+ if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ goto error;
+ }
+ }
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static int testConnectNumOfDefinedInterfaces(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ int count = 0;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->ifaces.count; i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (!virInterfaceObjIsActive(privconn->ifaces.objs[i]))
+ count++;
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+ return count;
+}
+
+static int testConnectListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (!virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
+ if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ goto error;
+ }
+ }
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static virInterfacePtr testInterfaceLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virInterfaceObjPtr iface;
+ virInterfacePtr ret = NULL;
+
+ testDriverLock(privconn);
+ iface = virInterfaceFindByName(&privconn->ifaces, name);
+ testDriverUnlock(privconn);
+
+ if (iface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+ if (iface)
+ virInterfaceObjUnlock(iface);
+ return ret;
+}
+
+static virInterfacePtr testInterfaceLookupByMACString(virConnectPtr conn,
+ const char *mac)
+{
+ testDriverPtr privconn = conn->privateData;
+ virInterfaceObjPtr iface;
+ int ifacect;
+ virInterfacePtr ret = NULL;
+
+ testDriverLock(privconn);
+ ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1);
+ testDriverUnlock(privconn);
+
+ if (ifacect == 0) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ if (ifacect > 1) {
+ virReportError(VIR_ERR_MULTIPLE_INTERFACES, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+ if (iface)
+ virInterfaceObjUnlock(iface);
+ return ret;
+}
+
+static char *testInterfaceGetXMLDesc(virInterfacePtr iface,
+ unsigned int flags)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+ testDriverUnlock(privconn);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, __FUNCTION__);
+ goto cleanup;
+ }
+
+ ret = virInterfaceDefFormat(privinterface->def);
+
+ cleanup:
+ if (privinterface)
+ virInterfaceObjUnlock(privinterface);
+ return ret;
+}
+
+static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virInterfaceDefPtr def;
+ virInterfaceObjPtr iface = NULL;
+ virInterfacePtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ if ((def = virInterfaceDefParseString(xmlStr)) == NULL)
+ goto cleanup;
+
+ if ((iface = virInterfaceAssignDef(&privconn->ifaces, def)) == NULL)
+ goto cleanup;
+ def = NULL;
+
+ ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+ virInterfaceDefFree(def);
+ if (iface)
+ virInterfaceObjUnlock(iface);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceUndefine(virInterfacePtr iface)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ virInterfaceRemove(&privconn->ifaces,
+ privinterface);
+ ret = 0;
+
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceCreate(virInterfacePtr iface,
+ unsigned int flags)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ if (privinterface->active != 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID, NULL);
+ goto cleanup;
+ }
+
+ privinterface->active = 1;
+ ret = 0;
+
+ cleanup:
+ if (privinterface)
+ virInterfaceObjUnlock(privinterface);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceDestroy(virInterfacePtr iface,
+ unsigned int flags)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ if (privinterface->active == 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID, NULL);
+ goto cleanup;
+ }
+
+ privinterface->active = 0;
+ ret = 0;
+
+ cleanup:
+ if (privinterface)
+ virInterfaceObjUnlock(privinterface);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceIsActive(virInterfacePtr iface)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr obj;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ obj = virInterfaceFindByName(&privconn->ifaces, iface->name);
+ testDriverUnlock(privconn);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+ ret = virInterfaceObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virInterfaceObjUnlock(obj);
+ return ret;
+}
+
+static int testInterfaceChangeBegin(virConnectPtr conn,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ if (privconn->transaction_running) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("there is another transaction running."));
+ goto cleanup;
+ }
+
+ privconn->transaction_running = true;
+
+ if (virInterfaceObjListClone(&privconn->ifaces,
+ &privconn->backupIfaces) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceChangeCommit(virConnectPtr conn,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+
+ if (!privconn->transaction_running) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("no transaction running, "
+ "nothing to be committed."));
+ goto cleanup;
+ }
+
+ virInterfaceObjListFree(&privconn->backupIfaces);
+ privconn->transaction_running = false;
+
+ ret = 0;
+
+ cleanup:
+ testDriverUnlock(privconn);
+
+ return ret;
+}
+
+static int testInterfaceChangeRollback(virConnectPtr conn,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+
+ if (!privconn->transaction_running) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("no transaction running, "
+ "nothing to rollback."));
+ goto cleanup;
+ }
+
+ virInterfaceObjListFree(&privconn->ifaces);
+ privconn->ifaces.count = privconn->backupIfaces.count;
+ privconn->ifaces.objs = privconn->backupIfaces.objs;
+ privconn->backupIfaces.count = 0;
+ privconn->backupIfaces.objs = NULL;
+
+ privconn->transaction_running = false;
+
+ ret = 0;
+
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+virInterfaceDriver testInterfaceDriver = {
+ .connectNumOfInterfaces = testConnectNumOfInterfaces, /* 0.7.0 */
+ .connectListInterfaces = testConnectListInterfaces, /* 0.7.0 */
+ .connectNumOfDefinedInterfaces = testConnectNumOfDefinedInterfaces, /* 0.7.0 */
+ .connectListDefinedInterfaces = testConnectListDefinedInterfaces, /* 0.7.0 */
+ .interfaceLookupByName = testInterfaceLookupByName, /* 0.7.0 */
+ .interfaceLookupByMACString = testInterfaceLookupByMACString, /* 0.7.0 */
+ .interfaceGetXMLDesc = testInterfaceGetXMLDesc, /* 0.7.0 */
+ .interfaceDefineXML = testInterfaceDefineXML, /* 0.7.0 */
+ .interfaceUndefine = testInterfaceUndefine, /* 0.7.0 */
+ .interfaceCreate = testInterfaceCreate, /* 0.7.0 */
+ .interfaceDestroy = testInterfaceDestroy, /* 0.7.0 */
+ .interfaceIsActive = testInterfaceIsActive, /* 0.7.3 */
+ .interfaceChangeBegin = testInterfaceChangeBegin, /* 0.9.2 */
+ .interfaceChangeCommit = testInterfaceChangeCommit, /* 0.9.2 */
+ .interfaceChangeRollback = testInterfaceChangeRollback, /* 0.9.2 */
+};
diff --git a/src/test/test_interface_driver.h b/src/test/test_interface_driver.h
new file mode 100644
index 0000000..34cdc43
--- /dev/null
+++ b/src/test/test_interface_driver.h
@@ -0,0 +1 @@
+extern virInterfaceDriver testInterfaceDriver;
diff --git a/src/test/test_network_driver.c b/src/test/test_network_driver.c
new file mode 100644
index 0000000..34b30fb
--- /dev/null
+++ b/src/test/test_network_driver.c
@@ -0,0 +1,540 @@
+/*
+ * test_network_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+#include "test_network_driver.h"
+
+#include "test_private_driver.h"
+
+static int testConnectNumOfNetworks(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numActive;
+
+ numActive = virNetworkObjListNumOfNetworks(privconn->networks,
+ true, NULL, conn);
+ return numActive;
+}
+
+static int testConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
+ testDriverPtr privconn = conn->privateData;
+ int n;
+
+ n = virNetworkObjListGetNames(privconn->networks,
+ true, names, nnames, NULL, conn);
+ return n;
+}
+
+static int testConnectNumOfDefinedNetworks(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numInactive;
+
+ numInactive = virNetworkObjListNumOfNetworks(privconn->networks,
+ false, NULL, conn);
+ return numInactive;
+}
+
+static int testConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
+ testDriverPtr privconn = conn->privateData;
+ int n;
+
+ n = virNetworkObjListGetNames(privconn->networks,
+ false, names, nnames, NULL, conn);
+ return n;
+}
+
+static int
+testConnectListAllNetworks(virConnectPtr conn,
+ virNetworkPtr **nets,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
+
+ return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags);
+}
+
+static int testNetworkIsActive(virNetworkPtr net)
+{
+ testDriverPtr privconn = net->conn->privateData;
+ virNetworkObjPtr obj;
+ int ret = -1;
+
+ obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+ ret = virNetworkObjIsActive(obj);
+
+ cleanup:
+ virNetworkObjEndAPI(&obj);
+ return ret;
+}
+
+static int testNetworkIsPersistent(virNetworkPtr net)
+{
+ testDriverPtr privconn = net->conn->privateData;
+ virNetworkObjPtr obj;
+ int ret = -1;
+
+ obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+ ret = obj->persistent;
+
+ cleanup:
+ virNetworkObjEndAPI(&obj);
+ return ret;
+}
+
+
+static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkDefPtr def;
+ virNetworkObjPtr net = NULL;
+ virNetworkPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ if ((def = virNetworkDefParseString(xml)) == NULL)
+ goto cleanup;
+
+ if (!(net = virNetworkAssignDef(privconn->networks, def,
+ VIR_NETWORK_OBJ_LIST_ADD_LIVE |
+ VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
+ goto cleanup;
+ def = NULL;
+ net->active = 1;
+
+ event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
+ VIR_NETWORK_EVENT_STARTED,
+ 0);
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkDefFree(def);
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static
+virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkDefPtr def;
+ virNetworkObjPtr net = NULL;
+ virNetworkPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ if ((def = virNetworkDefParseString(xml)) == NULL)
+ goto cleanup;
+
+ if (!(net = virNetworkAssignDef(privconn->networks, def, 0)))
+ goto cleanup;
+ def = NULL;
+
+ event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
+ VIR_NETWORK_EVENT_DEFINED,
+ 0);
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkDefFree(def);
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static int testNetworkUndefine(virNetworkPtr network)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virNetworkObjIsActive(privnet)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("Network '%s' is still running"), network->name);
+ goto cleanup;
+ }
+
+ event = virNetworkEventLifecycleNew(network->name, network->uuid,
+ VIR_NETWORK_EVENT_UNDEFINED,
+ 0);
+
+ virNetworkRemoveInactive(privconn->networks, privnet);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static int
+testNetworkUpdate(virNetworkPtr net,
+ unsigned int command,
+ unsigned int section,
+ int parentIndex,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = net->conn->privateData;
+ virNetworkObjPtr network = NULL;
+ int isActive, ret = -1;
+
+ virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
+ VIR_NETWORK_UPDATE_AFFECT_CONFIG,
+ -1);
+
+ network = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+ if (!network) {
+ virReportError(VIR_ERR_NO_NETWORK,
+ "%s", _("no network with matching uuid"));
+ goto cleanup;
+ }
+
+ /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
+ * is active, else change CONFIG
+ */
+ isActive = virNetworkObjIsActive(network);
+ if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE
+ | VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
+ VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
+ if (isActive)
+ flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
+ else
+ flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
+ }
+
+ /* update the network config in memory/on disk */
+ if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virNetworkObjEndAPI(&network);
+ return ret;
+}
+
+static int testNetworkCreate(virNetworkPtr network)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virNetworkObjIsActive(privnet)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("Network '%s' is already running"), network->name);
+ goto cleanup;
+ }
+
+ privnet->active = 1;
+ event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
+ VIR_NETWORK_EVENT_STARTED,
+ 0);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static int testNetworkDestroy(virNetworkPtr network)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privnet->active = 0;
+ event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
+ VIR_NETWORK_EVENT_STOPPED,
+ 0);
+ if (!privnet->persistent)
+ virNetworkRemoveInactive(privconn->networks, privnet);
+
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static char *testNetworkGetXMLDesc(virNetworkPtr network,
+ unsigned int flags)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ ret = virNetworkDefFormat(privnet->def, flags);
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static char *testNetworkGetBridgeName(virNetworkPtr network) {
+ testDriverPtr privconn = network->conn->privateData;
+ char *bridge = NULL;
+ virNetworkObjPtr privnet;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!(privnet->def->bridge)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("network '%s' does not have a bridge name."),
+ privnet->def->name);
+ goto cleanup;
+ }
+
+ ignore_value(VIR_STRDUP(bridge, privnet->def->bridge));
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return bridge;
+}
+
+static int testNetworkGetAutostart(virNetworkPtr network,
+ int *autostart)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ *autostart = privnet->autostart;
+ ret = 0;
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static int testNetworkSetAutostart(virNetworkPtr network,
+ int autostart)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privnet->autostart = autostart ? 1 : 0;
+ ret = 0;
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static virNetworkPtr testNetworkLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkObjPtr net;
+ virNetworkPtr ret = NULL;
+
+ net = virNetworkObjFindByUUID(privconn->networks, uuid);
+ if (net == NULL) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static virNetworkPtr testNetworkLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkObjPtr net;
+ virNetworkPtr ret = NULL;
+
+ net = virNetworkObjFindByName(privconn->networks, name);
+ if (net == NULL) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static int
+testConnectNetworkEventRegisterAny(virConnectPtr conn,
+ virNetworkPtr net,
+ int eventID,
+ virConnectNetworkEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virNetworkEventStateRegisterID(conn, driver->eventState,
+ net, eventID, callback,
+ opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectNetworkEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+virNetworkDriver testNetworkDriver = {
+ .connectNumOfNetworks = testConnectNumOfNetworks, /* 0.3.2 */
+ .connectListNetworks = testConnectListNetworks, /* 0.3.2 */
+ .connectNumOfDefinedNetworks = testConnectNumOfDefinedNetworks, /* 0.3.2 */
+ .connectListDefinedNetworks = testConnectListDefinedNetworks, /* 0.3.2 */
+ .connectListAllNetworks = testConnectListAllNetworks, /* 0.10.2 */
+ .connectNetworkEventRegisterAny = testConnectNetworkEventRegisterAny, /* 1.2.1 */
+ .connectNetworkEventDeregisterAny = testConnectNetworkEventDeregisterAny, /* 1.2.1 */
+ .networkLookupByUUID = testNetworkLookupByUUID, /* 0.3.2 */
+ .networkLookupByName = testNetworkLookupByName, /* 0.3.2 */
+ .networkCreateXML = testNetworkCreateXML, /* 0.3.2 */
+ .networkDefineXML = testNetworkDefineXML, /* 0.3.2 */
+ .networkUndefine = testNetworkUndefine, /* 0.3.2 */
+ .networkUpdate = testNetworkUpdate, /* 0.10.2 */
+ .networkCreate = testNetworkCreate, /* 0.3.2 */
+ .networkDestroy = testNetworkDestroy, /* 0.3.2 */
+ .networkGetXMLDesc = testNetworkGetXMLDesc, /* 0.3.2 */
+ .networkGetBridgeName = testNetworkGetBridgeName, /* 0.3.2 */
+ .networkGetAutostart = testNetworkGetAutostart, /* 0.3.2 */
+ .networkSetAutostart = testNetworkSetAutostart, /* 0.3.2 */
+ .networkIsActive = testNetworkIsActive, /* 0.7.3 */
+ .networkIsPersistent = testNetworkIsPersistent, /* 0.7.3 */
+};
diff --git a/src/test/test_network_driver.h b/src/test/test_network_driver.h
new file mode 100644
index 0000000..a87b7a4
--- /dev/null
+++ b/src/test/test_network_driver.h
@@ -0,0 +1 @@
+extern virNetworkDriver testNetworkDriver;
diff --git a/src/test/test_private_driver.h b/src/test/test_private_driver.h
new file mode 100644
index 0000000..751933c
--- /dev/null
+++ b/src/test/test_private_driver.h
@@ -0,0 +1,70 @@
+#ifndef __TEST_DRIVER_H__
+# define __TEST_DRIVER_H__
+
+# define MAX_CPUS 128
+
+struct _testCell {
+ unsigned long mem;
+ unsigned long freeMem;
+ int numCpus;
+ virCapsHostNUMACellCPU cpus[MAX_CPUS];
+};
+typedef struct _testCell testCell;
+typedef struct _testCell *testCellPtr;
+
+# define MAX_CELLS 128
+
+struct _testAuth {
+ char *username;
+ char *password;
+};
+typedef struct _testAuth testAuth;
+typedef struct _testAuth *testAuthPtr;
+
+struct _testDriver {
+ virMutex lock;
+
+ virNodeInfo nodeInfo;
+ virInterfaceObjList ifaces;
+ bool transaction_running;
+ virInterfaceObjList backupIfaces;
+ virStoragePoolObjList pools;
+ virNodeDeviceObjList devs;
+ int numCells;
+ testCell cells[MAX_CELLS];
+ size_t numAuths;
+ testAuthPtr auths;
+
+ /* virAtomic access only */
+ volatile int nextDomID;
+
+ /* immutable pointer, immutable object after being initialized with
+ * testBuildCapabilities */
+ virCapsPtr caps;
+
+ /* immutable pointer, immutable object */
+ virDomainXMLOptionPtr xmlopt;
+
+ /* immutable pointer, self-locking APIs */
+ virDomainObjListPtr domains;
+ virNetworkObjListPtr networks;
+ virObjectEventStatePtr eventState;
+};
+typedef struct _testDriver testDriver;
+typedef testDriver *testDriverPtr;
+
+# define VIR_FROM_THIS VIR_FROM_TEST
+
+extern unsigned long long defaultPoolAlloc;
+
+extern unsigned long long defaultPoolCap;
+
+void testDriverLock(testDriverPtr driver);
+void testDriverUnlock(testDriverPtr driver);
+
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
+
+void testObjectEventQueue(testDriverPtr driver,
+ virObjectEventPtr event);
+
+#endif /* __TEST_DRIVER_H__ */
diff --git a/src/test/test_storage_driver.c b/src/test/test_storage_driver.c
new file mode 100644
index 0000000..bda43c1
--- /dev/null
+++ b/src/test/test_storage_driver.c
@@ -0,0 +1,1517 @@
+/*
+ * test_storage_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_storage_driver.h"
+
+#include "test_private_driver.h"
+
+static int
+testConnectNumOfStoragePools(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numActive = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++)
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
+ numActive++;
+ testDriverUnlock(privconn);
+
+ return numActive;
+}
+
+static int
+testConnectListStoragePools(virConnectPtr conn,
+ char **const names,
+ int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+ VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ goto error;
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static int
+testConnectNumOfDefinedStoragePools(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numInactive = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
+ numInactive++;
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return numInactive;
+}
+
+static int
+testConnectListDefinedStoragePools(virConnectPtr conn,
+ char **const names,
+ int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+ VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ goto error;
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static int
+testConnectListAllStoragePools(virConnectPtr conn,
+ virStoragePoolPtr **pools,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1);
+
+ testDriverLock(privconn);
+ ret = virStoragePoolObjListExport(conn, privconn->pools, pools,
+ NULL, flags);
+ testDriverUnlock(privconn);
+
+ return ret;
+}
+
+static const char *defaultPoolSourcesLogicalXML =
+"<sources>\n"
+" <source>\n"
+" <device path='/dev/sda20'/>\n"
+" <name>testvg1</name>\n"
+" <format type='lvm2'/>\n"
+" </source>\n"
+" <source>\n"
+" <device path='/dev/sda21'/>\n"
+" <name>testvg2</name>\n"
+" <format type='lvm2'/>\n"
+" </source>\n"
+"</sources>\n";
+
+static const char *defaultPoolSourcesNetFSXML =
+"<sources>\n"
+" <source>\n"
+" <host name='%s'/>\n"
+" <dir path='/testshare'/>\n"
+" <format type='nfs'/>\n"
+" </source>\n"
+"</sources>\n";
+
+static char *
+testConnectFindStoragePoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *type,
+ const char *srcSpec,
+ unsigned int flags)
+{
+ virStoragePoolSourcePtr source = NULL;
+ int pool_type;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ pool_type = virStoragePoolTypeFromString(type);
+ if (!pool_type) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown storage pool type %s"), type);
+ goto cleanup;
+ }
+
+ if (srcSpec) {
+ source = virStoragePoolDefParseSourceString(srcSpec, pool_type);
+ if (!source)
+ goto cleanup;
+ }
+
+ switch (pool_type) {
+
+ case VIR_STORAGE_POOL_LOGICAL:
+ ignore_value(VIR_STRDUP(ret, defaultPoolSourcesLogicalXML));
+ break;
+
+ case VIR_STORAGE_POOL_NETFS:
+ if (!source || !source->hosts[0].name) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("hostname must be specified for netfs sources"));
+ goto cleanup;
+ }
+
+ ignore_value(virAsprintf(&ret, defaultPoolSourcesNetFSXML,
+ source->hosts[0].name));
+ break;
+
+ default:
+ virReportError(VIR_ERR_NO_SUPPORT,
+ _("pool type '%s' does not support source discovery"), type);
+ }
+
+ cleanup:
+ virStoragePoolSourceFree(source);
+ return ret;
+}
+
+static int
+testConnectStoragePoolEventRegisterAny(virConnectPtr conn,
+ virStoragePoolPtr pool,
+ int eventID,
+ virConnectStoragePoolEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virStoragePoolEventStateRegisterID(conn, driver->eventState,
+ pool, eventID, callback,
+ opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectStoragePoolEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ pool = virStoragePoolObjFindByName(&privconn->pools, name);
+ testDriverUnlock(privconn);
+
+ if (pool == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByVolume(virStorageVolPtr vol)
+{
+ return testStoragePoolLookupByName(vol->conn, vol->pool);
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
+ testDriverUnlock(privconn);
+
+ if (pool == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolCreateXML(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool = NULL;
+ virStoragePoolPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ if (!(def = virStoragePoolDefParseString(xml)))
+ goto cleanup;
+
+ pool = virStoragePoolObjFindByUUID(&privconn->pools, def->uuid);
+ if (!pool)
+ pool = virStoragePoolObjFindByName(&privconn->pools, def->name);
+ if (pool) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("storage pool already exists"));
+ goto cleanup;
+ }
+
+ if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
+ goto cleanup;
+ def = NULL;
+
+ if (testStoragePoolObjSetDefaults(pool) == -1) {
+ virStoragePoolObjRemove(&privconn->pools, pool);
+ pool = NULL;
+ goto cleanup;
+ }
+ pool->active = 1;
+
+ event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
+ VIR_STORAGE_POOL_EVENT_STARTED,
+ 0);
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ virStoragePoolDefFree(def);
+ testObjectEventQueue(privconn, event);
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolDefineXML(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool = NULL;
+ virStoragePoolPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ if (!(def = virStoragePoolDefParseString(xml)))
+ goto cleanup;
+
+ def->capacity = defaultPoolCap;
+ def->allocation = defaultPoolAlloc;
+ def->available = defaultPoolCap - defaultPoolAlloc;
+
+ if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
+ goto cleanup;
+ def = NULL;
+
+ event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
+ VIR_STORAGE_POOL_EVENT_DEFINED,
+ 0);
+
+ if (testStoragePoolObjSetDefaults(pool) == -1) {
+ virStoragePoolObjRemove(&privconn->pools, pool);
+ pool = NULL;
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ virStoragePoolDefFree(def);
+ testObjectEventQueue(privconn, event);
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+testStoragePoolUndefine(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+
+ event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
+ VIR_STORAGE_POOL_EVENT_UNDEFINED,
+ 0);
+
+ virStoragePoolObjRemove(&privconn->pools, privpool);
+ privpool = NULL;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ testObjectEventQueue(privconn, event);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+testStoragePoolBuild(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolDestroy(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privpool->active = 0;
+ event = virStoragePoolEventLifecycleNew(privpool->def->name, privpool->def->uuid,
+ VIR_STORAGE_POOL_EVENT_STOPPED,
+ 0);
+
+ if (privpool->configFile == NULL) {
+ virStoragePoolObjRemove(&privconn->pools, privpool);
+ privpool = NULL;
+ }
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+testStoragePoolDelete(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolRefresh(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ event = virStoragePoolEventRefreshNew(pool->name, pool->uuid);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolGetInfo(virStoragePoolPtr pool,
+ virStoragePoolInfoPtr info)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ memset(info, 0, sizeof(virStoragePoolInfo));
+ if (privpool->active)
+ info->state = VIR_STORAGE_POOL_RUNNING;
+ else
+ info->state = VIR_STORAGE_POOL_INACTIVE;
+ info->capacity = privpool->def->capacity;
+ info->allocation = privpool->def->allocation;
+ info->available = privpool->def->available;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+testStoragePoolGetXMLDesc(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ ret = virStoragePoolDefFormat(privpool->def);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolGetAutostart(virStoragePoolPtr pool,
+ int *autostart)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!privpool->configFile) {
+ *autostart = 0;
+ } else {
+ *autostart = privpool->autostart;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolSetAutostart(virStoragePoolPtr pool,
+ int autostart)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!privpool->configFile) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("pool has no config file"));
+ goto cleanup;
+ }
+
+ autostart = (autostart != 0);
+ privpool->autostart = autostart;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolNumOfVolumes(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ ret = privpool->volumes.count;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolListVolumes(virStoragePoolPtr pool,
+ char **const names,
+ int maxnames)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ size_t i = 0;
+ int n = 0;
+
+ memset(names, 0, maxnames * sizeof(*names));
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
+ if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0)
+ goto cleanup;
+ }
+
+ virStoragePoolObjUnlock(privpool);
+ return n;
+
+ cleanup:
+ for (n = 0; n < maxnames; n++)
+ VIR_FREE(names[i]);
+
+ memset(names, 0, maxnames * sizeof(*names));
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return -1;
+}
+
+static int
+testStoragePoolListAllVolumes(virStoragePoolPtr obj,
+ virStorageVolPtr **vols,
+ unsigned int flags)
+{
+ testDriverPtr privconn = obj->conn->privateData;
+ virStoragePoolObjPtr pool;
+ size_t i;
+ virStorageVolPtr *tmp_vols = NULL;
+ virStorageVolPtr vol = NULL;
+ int nvols = 0;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ pool = virStoragePoolObjFindByUUID(&privconn->pools, obj->uuid);
+ testDriverUnlock(privconn);
+
+ if (!pool) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, "%s",
+ _("no storage pool with matching uuid"));
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("storage pool is not active"));
+ goto cleanup;
+ }
+
+ /* Just returns the volumes count */
+ if (!vols) {
+ ret = pool->volumes.count;
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(tmp_vols, pool->volumes.count + 1) < 0)
+ goto cleanup;
+
+ 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,
+ NULL, NULL)))
+ goto cleanup;
+ tmp_vols[nvols++] = vol;
+ }
+
+ *vols = tmp_vols;
+ tmp_vols = NULL;
+ ret = nvols;
+
+ cleanup:
+ if (tmp_vols) {
+ for (i = 0; i < nvols; i++)
+ virObjectUnref(tmp_vols[i]);
+ VIR_FREE(tmp_vols);
+ }
+
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByName(virStoragePoolPtr pool,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ virStorageVolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, name);
+
+ if (!privvol) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"), name);
+ goto cleanup;
+ }
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key,
+ NULL, NULL);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByKey(virConnectPtr conn,
+ const char *key)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ virStorageVolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+ virStorageVolDefPtr privvol =
+ virStorageVolDefFindByKey(privconn->pools.objs[i], key);
+
+ if (privvol) {
+ ret = virGetStorageVol(conn,
+ privconn->pools.objs[i]->def->name,
+ privvol->name,
+ privvol->key,
+ NULL, NULL);
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ break;
+ }
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ if (!ret)
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching key '%s'"), key);
+
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByPath(virConnectPtr conn,
+ const char *path)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ virStorageVolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+ virStorageVolDefPtr privvol =
+ virStorageVolDefFindByPath(privconn->pools.objs[i], path);
+
+ if (privvol) {
+ ret = virGetStorageVol(conn,
+ privconn->pools.objs[i]->def->name,
+ privvol->name,
+ privvol->key,
+ NULL, NULL);
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ break;
+ }
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ if (!ret)
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching path '%s'"), path);
+
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolCreateXML(virStoragePoolPtr pool,
+ const char *xmldesc,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol = NULL;
+ virStorageVolPtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
+ if (privvol == NULL)
+ goto cleanup;
+
+ if (virStorageVolDefFindByName(privpool, privvol->name)) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("storage vol already exists"));
+ goto cleanup;
+ }
+
+ /* Make sure enough space */
+ if ((privpool->def->allocation + privvol->target.allocation) >
+ privpool->def->capacity) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Not enough free space in pool for volume '%s'"),
+ privvol->name);
+ goto cleanup;
+ }
+
+ if (virAsprintf(&privvol->target.path, "%s/%s",
+ privpool->def->target.path,
+ privvol->name) == -1)
+ goto cleanup;
+
+ if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
+ VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
+ privpool->volumes.count, privvol) < 0)
+ goto cleanup;
+
+ privpool->def->allocation += privvol->target.allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key,
+ NULL, NULL);
+ privvol = NULL;
+
+ cleanup:
+ virStorageVolDefFree(privvol);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolCreateXMLFrom(virStoragePoolPtr pool,
+ const char *xmldesc,
+ virStorageVolPtr clonevol,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol = NULL, origvol = NULL;
+ virStorageVolPtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
+ if (privvol == NULL)
+ goto cleanup;
+
+ if (virStorageVolDefFindByName(privpool, privvol->name)) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("storage vol already exists"));
+ goto cleanup;
+ }
+
+ origvol = virStorageVolDefFindByName(privpool, clonevol->name);
+ if (!origvol) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ clonevol->name);
+ goto cleanup;
+ }
+
+ /* Make sure enough space */
+ if ((privpool->def->allocation + privvol->target.allocation) >
+ privpool->def->capacity) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Not enough free space in pool for volume '%s'"),
+ privvol->name);
+ goto cleanup;
+ }
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ if (virAsprintf(&privvol->target.path, "%s/%s",
+ privpool->def->target.path,
+ privvol->name) == -1)
+ goto cleanup;
+
+ if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
+ VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
+ privpool->volumes.count, privvol) < 0)
+ goto cleanup;
+
+ privpool->def->allocation += privvol->target.allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key,
+ NULL, NULL);
+ privvol = NULL;
+
+ cleanup:
+ virStorageVolDefFree(privvol);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStorageVolDelete(virStorageVolPtr vol,
+ unsigned int flags)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ size_t i;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+
+ privpool->def->allocation -= privvol->target.allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ for (i = 0; i < privpool->volumes.count; i++) {
+ if (privpool->volumes.objs[i] == privvol) {
+ virStorageVolDefFree(privvol);
+
+ VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count);
+ break;
+ }
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int testStorageVolumeTypeForPool(int pooltype)
+{
+
+ switch (pooltype) {
+ case VIR_STORAGE_POOL_DIR:
+ case VIR_STORAGE_POOL_FS:
+ case VIR_STORAGE_POOL_NETFS:
+ return VIR_STORAGE_VOL_FILE;
+ default:
+ return VIR_STORAGE_VOL_BLOCK;
+ }
+}
+
+static int
+testStorageVolGetInfo(virStorageVolPtr vol,
+ virStorageVolInfoPtr info)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ memset(info, 0, sizeof(*info));
+ info->type = testStorageVolumeTypeForPool(privpool->def->type);
+ info->capacity = privvol->target.capacity;
+ info->allocation = privvol->target.allocation;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+testStorageVolGetXMLDesc(virStorageVolPtr vol,
+ unsigned int flags)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ ret = virStorageVolDefFormat(privpool->def, privvol);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+testStorageVolGetPath(virStorageVolPtr vol)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ char *ret = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ ignore_value(VIR_STRDUP(ret, privvol->target.path));
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool)
+{
+
+ pool->def->capacity = defaultPoolCap;
+ pool->def->allocation = defaultPoolAlloc;
+ pool->def->available = defaultPoolCap - defaultPoolAlloc;
+
+ return VIR_STRDUP(pool->configFile, "");
+}
+
+static int testStoragePoolIsActive(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr obj;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
+ testDriverUnlock(privconn);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+ ret = virStoragePoolObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virStoragePoolObjUnlock(obj);
+ return ret;
+}
+
+static int testStoragePoolIsPersistent(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr obj;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
+ testDriverUnlock(privconn);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+ ret = obj->configFile ? 1 : 0;
+
+ cleanup:
+ if (obj)
+ virStoragePoolObjUnlock(obj);
+ return ret;
+}
+
+static int
+testStoragePoolCreate(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+
+ privpool->active = 1;
+
+ event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
+ VIR_STORAGE_POOL_EVENT_STARTED,
+ 0);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+virStorageDriver testStorageDriver = {
+ .connectNumOfStoragePools = testConnectNumOfStoragePools, /* 0.5.0 */
+ .connectListStoragePools = testConnectListStoragePools, /* 0.5.0 */
+ .connectNumOfDefinedStoragePools = testConnectNumOfDefinedStoragePools, /* 0.5.0 */
+ .connectListDefinedStoragePools = testConnectListDefinedStoragePools, /* 0.5.0 */
+ .connectListAllStoragePools = testConnectListAllStoragePools, /* 0.10.2 */
+ .connectFindStoragePoolSources = testConnectFindStoragePoolSources, /* 0.5.0 */
+ .connectStoragePoolEventRegisterAny = testConnectStoragePoolEventRegisterAny, /* 2.0.0 */
+ .connectStoragePoolEventDeregisterAny = testConnectStoragePoolEventDeregisterAny, /* 2.0.0 */
+ .storagePoolLookupByName = testStoragePoolLookupByName, /* 0.5.0 */
+ .storagePoolLookupByUUID = testStoragePoolLookupByUUID, /* 0.5.0 */
+ .storagePoolLookupByVolume = testStoragePoolLookupByVolume, /* 0.5.0 */
+ .storagePoolCreateXML = testStoragePoolCreateXML, /* 0.5.0 */
+ .storagePoolDefineXML = testStoragePoolDefineXML, /* 0.5.0 */
+ .storagePoolBuild = testStoragePoolBuild, /* 0.5.0 */
+ .storagePoolUndefine = testStoragePoolUndefine, /* 0.5.0 */
+ .storagePoolCreate = testStoragePoolCreate, /* 0.5.0 */
+ .storagePoolDestroy = testStoragePoolDestroy, /* 0.5.0 */
+ .storagePoolDelete = testStoragePoolDelete, /* 0.5.0 */
+ .storagePoolRefresh = testStoragePoolRefresh, /* 0.5.0 */
+ .storagePoolGetInfo = testStoragePoolGetInfo, /* 0.5.0 */
+ .storagePoolGetXMLDesc = testStoragePoolGetXMLDesc, /* 0.5.0 */
+ .storagePoolGetAutostart = testStoragePoolGetAutostart, /* 0.5.0 */
+ .storagePoolSetAutostart = testStoragePoolSetAutostart, /* 0.5.0 */
+ .storagePoolNumOfVolumes = testStoragePoolNumOfVolumes, /* 0.5.0 */
+ .storagePoolListVolumes = testStoragePoolListVolumes, /* 0.5.0 */
+ .storagePoolListAllVolumes = testStoragePoolListAllVolumes, /* 0.10.2 */
+
+ .storageVolLookupByName = testStorageVolLookupByName, /* 0.5.0 */
+ .storageVolLookupByKey = testStorageVolLookupByKey, /* 0.5.0 */
+ .storageVolLookupByPath = testStorageVolLookupByPath, /* 0.5.0 */
+ .storageVolCreateXML = testStorageVolCreateXML, /* 0.5.0 */
+ .storageVolCreateXMLFrom = testStorageVolCreateXMLFrom, /* 0.6.4 */
+ .storageVolDelete = testStorageVolDelete, /* 0.5.0 */
+ .storageVolGetInfo = testStorageVolGetInfo, /* 0.5.0 */
+ .storageVolGetXMLDesc = testStorageVolGetXMLDesc, /* 0.5.0 */
+ .storageVolGetPath = testStorageVolGetPath, /* 0.5.0 */
+ .storagePoolIsActive = testStoragePoolIsActive, /* 0.7.3 */
+ .storagePoolIsPersistent = testStoragePoolIsPersistent, /* 0.7.3 */
+};
diff --git a/src/test/test_storage_driver.h b/src/test/test_storage_driver.h
new file mode 100644
index 0000000..fd29eda
--- /dev/null
+++ b/src/test/test_storage_driver.h
@@ -0,0 +1 @@
+extern virStorageDriver testStorageDriver;
--
2.9.3
8 years, 7 months
[libvirt] [PATCH 0/3] docs/Makefile.am cleanups
by Ján Tomko
The effect of 2/3 will be more apparent after apibuild.py speedups
(to be written).
Ján Tomko (3):
docs/Makefile.am: remove redundant variables
docs/Makefile.am: build hvsupport.html earlier
docs: drop todo.html
.gitignore | 1 -
docs/Makefile.am | 44 +++---------------
docs/sitemap.html.in | 4 --
docs/todo.cfg-example | 26 -----------
docs/todo.pl | 125 --------------------------------------------------
5 files changed, 7 insertions(+), 193 deletions(-)
delete mode 100644 docs/todo.cfg-example
delete mode 100755 docs/todo.pl
--
2.7.3
8 years, 7 months
[libvirt] [PATCH] qemu: map "virtio" video model to "virt" machtype correctly (arm/aarch64)
by Laszlo Ersek
Most of QEMU's PCI display device models, such as:
libvirt video/model/@type QEMU -device
------------------------- ------------
cirrus cirrus-vga
vga VGA
qxl qxl-vga
virtio virtio-vga
come with a linear framebuffer (sometimes called "VGA compatibility
framebuffer"). This linear framebuffer lives in one of the PCI device's
MMIO BARs, and allows guest code (primarily: firmware drivers, and
non-accelerated OS drivers) to display graphics with direct memory access.
Due to architectural reasons on aarch64/KVM hosts, this kind of
framebuffer doesn't / can't work in
qemu-system-(arm|aarch64) -M virt
machines. Cache coherency issues guarantee a corrupted / unusable display.
The problem has been researched by several people, including kvm-arm
maintainers, and it's been decided that the best way (practically the only
way) to have boot time graphics for such guests is to consolidate on
QEMU's "virtio-gpu-pci" device.
>From <https://bugzilla.redhat.com/show_bug.cgi?id=1195176>, libvirt
supports
<devices>
<video>
<model type='virtio'/>
</video>
</devices>
but libvirt unconditionally maps @type='virtio' to QEMU's "virtio-vga"
device model. (See the qemuBuildDeviceVideoStr() function and the
"qemuDeviceVideo" enum impl.)
According to the above, this is not right for the "virt" machine type; the
qemu-system-(arm|aarch64) binaries don't even recognize the "virtio-vga"
device model (justifiedly). Whereas "virtio-gpu-pci", which is a pure
virtio device without a compatibility framebuffer, is available, and works
fine.
(The ArmVirtQemu ("AAVMF") platform of edk2 -- that is, the UEFI firmware
for "virt" -- supports "virtio-gpu-pci", as of upstream commit
3ef3209d3028. See
<https://tianocore.acgmultimedia.com/show_bug.cgi?id=66>.)
Override the default mapping of "virtio", from "virtio-vga" to
"virtio-gpu-pci", if qemuDomainMachineIsVirt() evaluates to true.
Cc: Andrea Bolognani <abologna(a)redhat.com>
Cc: Drew Jones <drjones(a)redhat.com>
Cc: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Suggested-by: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1372901
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
---
src/qemu/qemu_command.c | 4 ++
tests/qemuxml2argvtest.c | 5 +++
tests/qemuxml2xmltest.c | 5 +++
tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args | 26 +++++++++++
tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml | 36 ++++++++++++++++
tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml | 45 ++++++++++++++++++++
6 files changed, 121 insertions(+)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3a61863b9abb..038c38f2217c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4325,6 +4325,10 @@ qemuBuildDeviceVideoStr(const virDomainDef *def,
virDomainVideoTypeToString(video->type));
goto error;
}
+ if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO &&
+ qemuDomainMachineIsVirt(def)) {
+ model = "virtio-gpu-pci";
+ }
} else {
if (video->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index dbb0e4d56142..e8540779a4b5 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1872,6 +1872,11 @@ mymain(void)
QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM,
QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI);
+ DO_TEST("aarch64-video-virtio-gpu-pci",
+ QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX,
+ QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+ QEMU_CAPS_DEVICE_VIRTIO_GPU, QEMU_CAPS_BOOTINDEX);
DO_TEST("aarch64-aavmf-virtio-mmio",
QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DTB,
QEMU_CAPS_DEVICE_VIRTIO_MMIO,
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 14c2b0ccf2ce..fb05c8571411 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -831,6 +831,11 @@ mymain(void)
QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM,
QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI);
+ DO_TEST("aarch64-video-virtio-gpu-pci",
+ QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX,
+ QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+ QEMU_CAPS_DEVICE_VIRTIO_GPU, QEMU_CAPS_BOOTINDEX);
DO_TEST_FULL("aarch64-gic-none", WHEN_BOTH, GIC_NONE, NONE);
DO_TEST_FULL("aarch64-gic-none-v2", WHEN_BOTH, GIC_V2, NONE);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args
new file mode 100644
index 000000000000..56dbdfb66fa2
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args
@@ -0,0 +1,26 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/opt/qemu-installed/bin/qemu-system-aarch64 \
+-name aarch64-vgpu \
+-S \
+-M virt \
+-cpu cortex-a57 \
+-m 1024 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid f3197c89-6457-44fe-b26d-897090ba6541 \
+-nographic \
+-nodefconfig \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-aarch64-vgpu/monitor.sock,server,nowait \
+-device ioh3420,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\
+addr=0x1 \
+-device ioh3420,port=0x9,chassis=2,id=pci.2,bus=pcie.0,multifunction=on,\
+addr=0x1.0x1 \
+-device virtio-net-pci,vlan=0,id=net0,mac=52:54:00:73:34:53,bus=pci.1,\
+addr=0x0,bootindex=1 \
+-net user,vlan=0,name=hostnet0 \
+-device virtio-gpu-pci,id=video0,bus=pci.2,addr=0x0
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml
new file mode 100644
index 000000000000..4b52a731b043
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml
@@ -0,0 +1,36 @@
+<domain type='qemu'>
+ <name>aarch64-vgpu</name>
+ <uuid>f3197c89-6457-44fe-b26d-897090ba6541</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ </os>
+ <features>
+ <acpi/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>cortex-a57</model>
+ </cpu>
+ <devices>
+ <emulator>/opt/qemu-installed/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1' multifunction='on'/>
+ </controller>
+ <interface type='user'>
+ <mac address='52:54:00:73:34:53'/>
+ <model type='virtio'/>
+ <boot order='1'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <video>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </video>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml
new file mode 100644
index 000000000000..26f6a51622ef
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml
@@ -0,0 +1,45 @@
+<domain type='qemu'>
+ <name>aarch64-vgpu</name>
+ <uuid>f3197c89-6457-44fe-b26d-897090ba6541</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ </os>
+ <features>
+ <acpi/>
+ <gic version='2'/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>cortex-a57</model>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/opt/qemu-installed/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <model name='ioh3420'/>
+ <target chassis='1' port='0x8'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <model name='ioh3420'/>
+ <target chassis='2' port='0x9'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1' multifunction='on'/>
+ </controller>
+ <interface type='user'>
+ <mac address='52:54:00:73:34:53'/>
+ <model type='virtio'/>
+ <boot order='1'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <video>
+ <model type='virtio' heads='1' primary='yes'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </video>
+ </devices>
+</domain>
--
2.9.2
8 years, 7 months
[libvirt] [PATCH] util: Expose virHostCPUStatsAssign on non-Linux
by Martin Kletzander
There is nothing Linux-specific in that function. Also since commit
8c3b5bf48123783b812b97360db7ac51f1889e17 mingw build is broken due to
the fact that this function is not compiled in the library.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
Pushed as trivial build-breaker fix.
src/util/virhostcpu.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index 856d83c3e49b..f68176f387ec 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -781,21 +781,6 @@ virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
return ret;
}
-int
-virHostCPUStatsAssign(virNodeCPUStatsPtr param,
- const char *name,
- unsigned long long value)
-{
- if (virStrcpyStatic(param->field, name) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("kernel cpu time field is too long"
- " for the destination"));
- return -1;
- }
- param->value = value;
- return 0;
-}
-
# define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK))
int
@@ -953,6 +938,22 @@ virHostCPUParseMapLinux(int max_cpuid, const char *path)
int
+virHostCPUStatsAssign(virNodeCPUStatsPtr param,
+ const char *name,
+ unsigned long long value)
+{
+ if (virStrcpyStatic(param->field, name) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("kernel cpu time field is too long"
+ " for the destination"));
+ return -1;
+ }
+ param->value = value;
+ return 0;
+}
+
+
+int
virHostCPUGetInfo(virArch hostarch ATTRIBUTE_UNUSED,
unsigned int *cpus ATTRIBUTE_UNUSED,
unsigned int *mhz ATTRIBUTE_UNUSED,
--
2.10.0
8 years, 7 months
[libvirt] [PATCH v1 1/1] qemu/gluster: add option for tuning debug logging level
by Prasanna Kumar Kalever
This helps in selecting log level of the gluster gfapi, output to stderr.
The option is 'qemu_gfapi_debuglevel', can be tuned by editing
'/etc/libvirt/qemu.conf'
Debug levels ranges 0-9, with 9 being the most verbose, and 0 representing
no debugging output. The default is the same as it was before, which
is a level of 4. The current logging levels defined in the gluster
gfapi are:
0 - None
1 - Emergency
2 - Alert
3 - Critical
4 - Error
5 - Warning
6 - Notice
7 - Info
8 - Debug
9 - Trace
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever(a)redhat.com>
--
v1: Initial post
---
src/qemu/qemu.conf | 20 ++++++++++++++++++++
src/qemu/qemu_command.c | 12 +++++++++++-
src/qemu/qemu_conf.c | 3 +++
src/qemu/qemu_conf.h | 1 +
src/util/virstoragefile.h | 2 ++
5 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index e4c2aae..c6c8f3a 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -621,3 +621,23 @@
# rollover when a size limit is hit.
#
#stdio_handler = "logd"
+
+# Qemu gluster libgfapi log level, debug levels are 0-9, with 9 being the
+# most verbose, and 0 representing no debugging output.
+#
+# The current logging levels defined in the gluster GFAPI are:
+#
+# 0 - None
+# 1 - Emergency
+# 2 - Alert
+# 3 - Critical
+# 4 - Error
+# 5 - Warning
+# 6 - Notice
+# 7 - Info
+# 8 - Debug
+# 9 - Trace
+#
+# Defaults to 4
+#
+# qemu_gfapi_debuglevel = 9
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3a61863..650eedc 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -859,6 +859,7 @@ qemuBuildGlusterDriveJSON(virStorageSourcePtr src)
/* { driver:"gluster",
* volume:"testvol",
* path:"/a.img",
+ * debug:9,
* server :[{type:"tcp", host:"1.2.3.4", port:24007},
* {type:"unix", socket:"/tmp/glusterd.socket"}, ...]}
*/
@@ -866,6 +867,7 @@ qemuBuildGlusterDriveJSON(virStorageSourcePtr src)
"s:driver", protocol,
"s:volume", src->volume,
"s:path", src->path,
+ "u:debug", src->debug_level,
"a:server", servers, NULL) < 0)
virJSONValueFree(servers);
@@ -2177,6 +2179,7 @@ qemuBuildDriveDevStr(const virDomainDef *def,
static int
qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
+ virQEMUDriverConfigPtr cfg,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
@@ -2255,6 +2258,13 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
virCommandAddArg(cmd, "-drive");
+ if (disk->src &&
+ disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
+ if(cfg->qemuGfapiDebugLevel) {
+ disk->src->debug_level = cfg->qemuGfapiDebugLevel;
+ }
+ }
+
if (!(optstr = qemuBuildDriveStr(disk, driveBoot, qemuCaps)))
return -1;
virCommandAddArg(cmd, optstr);
@@ -9613,7 +9623,7 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
if (qemuBuildHubCommandLine(cmd, def, qemuCaps) < 0)
goto error;
- if (qemuBuildDiskDriveCommandLine(cmd, def, qemuCaps) < 0)
+ if (qemuBuildDiskDriveCommandLine(cmd, cfg, def, qemuCaps) < 0)
goto error;
if (qemuBuildFSDevCommandLine(cmd, def, qemuCaps) < 0)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index dad8334..d245cec 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -311,6 +311,7 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
cfg->seccompSandbox = -1;
cfg->logTimestamp = true;
+ cfg->qemuGfapiDebugLevel = 4;
cfg->stdioLogD = true;
#ifdef DEFAULT_LOADER_NVRAM
@@ -780,6 +781,8 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
goto cleanup;
}
}
+ if (virConfGetValueUInt(conf, "qemu_gfapi_debuglevel", &cfg->qemuGfapiDebugLevel) < 0)
+ goto cleanup;
ret = 0;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index d8232cc..fe70d9b 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -190,6 +190,7 @@ struct _virQEMUDriverConfig {
virFirmwarePtr *firmwares;
size_t nfirmwares;
+ unsigned int qemuGfapiDebugLevel;
};
/* Main driver state */
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index 3d09468..9f3add3 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -237,6 +237,8 @@ struct _virStorageSource {
virStorageAuthDefPtr auth;
virStorageEncryptionPtr encryption;
+ unsigned int debug_level;
+
char *driverName;
int format; /* virStorageFileFormat in domain backing chains, but
* pool-specific enum for storage volumes */
--
2.7.4
8 years, 7 months
[libvirt] [PATCH v2 1/1] [WIP] qemu/gluster: add option for tuning debug logging level
by Prasanna Kumar Kalever
This helps in selecting log level of the gluster gfapi, output to stderr.
The option is 'qemu_gfapi_debuglevel', can be tuned by editing
'/etc/libvirt/qemu.conf'
Debug levels ranges 0-9, with 9 being the most verbose, and 0 representing
no debugging output. The default is the same as it was before, which
is a level of 4. The current logging levels defined in the gluster
gfapi are:
0 - None
1 - Emergency
2 - Alert
3 - Critical
4 - Error
5 - Warning
6 - Notice
7 - Info
8 - Debug
9 - Trace
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever(a)redhat.com>
--
v2:
Modify test cases and syntax check changes as suggested by Peter in v1.
Rename qemu_gfapi_debuglevel to glusterfs_debug_level as per Daniel comments.
Fix to make debug_level changes effects on URI along with JSON.
TODO:
* changes in libvirtd_qemu.aug
Which I don't understand for now
* comment on debug_level variable in storage source
Not sure what is the right place
* Capablities check
v1:
Initial post
---
src/qemu/qemu.conf | 20 ++++++++++++++++++++
src/qemu/qemu_command.c | 14 +++++++++++++-
src/qemu/qemu_conf.c | 3 +++
src/qemu/qemu_conf.h | 1 +
src/util/virstoragefile.h | 2 ++
.../qemuargv2xml-disk-drive-network-gluster.args | 7 ++++---
.../qemuxml2argv-disk-drive-network-gluster.args | 12 ++++++------
7 files changed, 49 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index e4c2aae..a6cdcf3 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -621,3 +621,23 @@
# rollover when a size limit is hit.
#
#stdio_handler = "logd"
+
+# Qemu gluster libgfapi log level, debug levels are 0-9, with 9 being the
+# most verbose, and 0 representing no debugging output.
+#
+# The current logging levels defined in the gluster GFAPI are:
+#
+# 0 - None
+# 1 - Emergency
+# 2 - Alert
+# 3 - Critical
+# 4 - Error
+# 5 - Warning
+# 6 - Notice
+# 7 - Info
+# 8 - Debug
+# 9 - Trace
+#
+# Defaults to 4
+#
+# glusterfs_debug_level = 9
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3a61863..c333795 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1383,6 +1383,11 @@ qemuBuildDriveSourceStr(virDomainDiskDefPtr disk,
}
virBufferAddLit(buf, ",");
+ if (disk->src &&
+ disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
+ virBufferAsprintf(buf, "file.debug=%d,", disk->src->debug_level);
+ }
+
if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
/* NB: If libvirt starts using the more modern option based
* syntax to build the command line (e.g., "-drive driver=rbd,
@@ -2177,6 +2182,7 @@ qemuBuildDriveDevStr(const virDomainDef *def,
static int
qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
+ virQEMUDriverConfigPtr cfg,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
@@ -2255,6 +2261,12 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
virCommandAddArg(cmd, "-drive");
+ if (disk->src &&
+ disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
+ if (cfg->glusterfsDebugLevel)
+ disk->src->debug_level = cfg->glusterfsDebugLevel;
+ }
+
if (!(optstr = qemuBuildDriveStr(disk, driveBoot, qemuCaps)))
return -1;
virCommandAddArg(cmd, optstr);
@@ -9613,7 +9625,7 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
if (qemuBuildHubCommandLine(cmd, def, qemuCaps) < 0)
goto error;
- if (qemuBuildDiskDriveCommandLine(cmd, def, qemuCaps) < 0)
+ if (qemuBuildDiskDriveCommandLine(cmd, cfg, def, qemuCaps) < 0)
goto error;
if (qemuBuildFSDevCommandLine(cmd, def, qemuCaps) < 0)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index dad8334..ff2b58e 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -311,6 +311,7 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
cfg->seccompSandbox = -1;
cfg->logTimestamp = true;
+ cfg->glusterfsDebugLevel = 4;
cfg->stdioLogD = true;
#ifdef DEFAULT_LOADER_NVRAM
@@ -780,6 +781,8 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
goto cleanup;
}
}
+ if (virConfGetValueUInt(conf, "glusterfs_debug_level", &cfg->glusterfsDebugLevel) < 0)
+ goto cleanup;
ret = 0;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index d8232cc..89d046d 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -190,6 +190,7 @@ struct _virQEMUDriverConfig {
virFirmwarePtr *firmwares;
size_t nfirmwares;
+ unsigned int glusterfsDebugLevel;
};
/* Main driver state */
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index 3d09468..9f3add3 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -237,6 +237,8 @@ struct _virStorageSource {
virStorageAuthDefPtr auth;
virStorageEncryptionPtr encryption;
+ unsigned int debug_level;
+
char *driverName;
int format; /* virStorageFileFormat in domain backing chains, but
* pool-specific enum for storage volumes */
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args b/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args
index f560308..deec7a7 100644
--- a/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args
+++ b/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args
@@ -16,9 +16,10 @@ QEMU_AUDIO_DRV=none \
-no-acpi \
-boot c \
-usb \
--drive file=gluster://example.org:6000/Volume1/Image,format=raw,if=virtio \
--drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,format=raw,\
-if=virtio' \
+-drive file=gluster://example.org:6000/Volume1/Image,file.debug=4,format=raw,\
+if=virtio \
+-drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,file.debug=4,\
+format=raw,if=virtio' \
-net none \
-serial none \
-parallel none
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args
index 634ed75..cd5294e 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args
@@ -17,18 +17,18 @@ QEMU_AUDIO_DRV=none \
-no-acpi \
-boot c \
-usb \
--drive file=gluster://example.org:6000/Volume1/Image,format=raw,if=none,\
-id=drive-virtio-disk0 \
+-drive file=gluster://example.org:6000/Volume1/Image,file.debug=4,format=raw,\
+if=none,id=drive-virtio-disk0 \
-device virtio-blk-pci,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,\
id=virtio-disk0 \
--drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,format=raw,\
-if=none,id=drive-virtio-disk1' \
+-drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,file.debug=4,\
+format=raw,if=none,id=drive-virtio-disk1' \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk1,\
id=virtio-disk1 \
-drive file.driver=gluster,file.volume=Volume3,file.path=/Image.qcow2,\
file.server.0.type=tcp,file.server.0.host=example.org,file.server.0.port=6000,\
file.server.1.type=tcp,file.server.1.host=example.org,file.server.1.port=24007,\
-file.server.2.type=unix,file.server.2.socket=/path/to/sock,format=qcow2,\
-if=none,id=drive-virtio-disk2 \
+file.server.2.type=unix,file.server.2.socket=/path/to/sock,file.debug=4,\
+format=qcow2,if=none,id=drive-virtio-disk2 \
-device virtio-blk-pci,bus=pci.0,addr=0x5,drive=drive-virtio-disk2,\
id=virtio-disk2
--
2.7.4
8 years, 7 months
[libvirt] [PATCH 0/8] test driver: Added new functions.
by Tomáš Ryšavý
Added few functions into test driver.
Tomáš Ryšavý (8):
virhostcpu: Expose virHostCPUStatsAssign
test driver: Replaced num by a constant.
test driver: Implement virConnectGetSysinfo.
test driver: Implement virConnectGetType.
test driver: Implement testNodeGetCPUStats
test driver: Implement testNodeGetFreeMemory
test driver: added pages sizes into XML into test driver.
test driver: Implement testNodeGetFreePages.
src/libvirt_private.syms | 1 +
src/test/test_driver.c | 148 +++++++++++++++++++++++++++++++++++++++++++++--
src/util/virhostcpu.c | 2 +-
src/util/virhostcpu.h | 4 ++
4 files changed, 148 insertions(+), 7 deletions(-)
--
2.9.3
8 years, 7 months
[libvirt] [PATCH v4] virsh: use virConnectGetDomainCapabilities with maxvcpus
by Shivaprasad G Bhat
virsh maxvcpus --type kvm output is useless on PPC. Also, in
commit e6806d79 we documented not rely on virConnectGetMaxVcpus
output. Fix the maxvcpus to use virConnectGetDomainCapabilities
now to make it useful. The call is made to use the default emulator
binary and to check for the host machine and arch which is what the
command intends to show anyway.
Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
---
tools/virsh-host.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index 57f0c0e..dbdf23d 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -606,18 +606,46 @@ static bool
cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd)
{
const char *type = NULL;
- int vcpus;
+ int vcpus = -1;
+ char *caps = NULL;
+ const unsigned int flags = 0; /* No flags so far */
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr ctxt = NULL;
virshControlPtr priv = ctl->privData;
if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
return false;
- if ((vcpus = virConnectGetMaxVcpus(priv->conn, type)) < 0)
+ caps = virConnectGetDomainCapabilities(priv->conn, NULL, NULL, NULL, type, flags);
+ if (!caps) {
+ if (last_error && last_error->code != VIR_ERR_NO_SUPPORT)
+ return false;
+
+ vshResetLibvirtError();
+ goto fallback;
+ }
+
+ xml = virXMLParseStringCtxt(caps, _("(domainCapabilities)"), &ctxt);
+ if (!xml) {
+ VIR_FREE(caps);
return false;
+ }
- vshPrint(ctl, "%d\n", vcpus);
+ virXPathInt("string(./vcpu[1]/@max)", ctxt, &vcpus);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+ VIR_FREE(caps);
+ if (vcpus < 0)
+ goto fallback;
+
+ exit:
+ vshPrint(ctl, "%d\n", vcpus);
return true;
+ fallback:
+ if ((vcpus = virConnectGetMaxVcpus(priv->conn, type)) < 0)
+ return false;
+ goto exit;
}
/*
8 years, 7 months
[libvirt] [PATCH] tests: Use fixedcontent variable
by Martin Kletzander
Commit ca32929908bbc94116493ad8915e7cd7ae0f57d5 added function
virTestCompareToFile(), but forgot to use a fixedcontent value for the
actual comparison. That lead to VIR_TEST_DEBUG=1 showing (for some
tests) all the actual output from the first error to the end of the
string due to the difference being an endline in the end.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
Pushed as 'trivial'.
tests/testutils.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/testutils.c b/tests/testutils.c
index 8ea6ab82ad5a..f87628edee68 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -709,7 +709,7 @@ virTestCompareToFile(const char *strcontent,
filecontent)) {
virTestDifferenceFull(stderr,
filecontent, filename,
- strcontent, NULL);
+ fixedcontent, NULL);
goto failure;
}
--
2.10.0
8 years, 7 months
Re: [libvirt] [PATCH 8/8] fspools: docs and tests for fspool directory backend
by Olga Krishtal
Hello again.
Please, drop the commit message for this patch.
Use the following one:
Added XML 2 XML tests for fspool and item.
________________________________
From: Olga Krishtal
Sent: Thursday, September 15, 2016 10:39:01 AM
To: openstack-devel
Cc: Maxim Nestratov; Nikolay Shirokovskiy
Subject: Re: [PATCH 8/8] fspools: docs and tests for fspool directory backend
On 26/08/16 17:17, Olga Krishtal wrote:
Pleas, drop the commit message, test is present for both: item and fspool.
> At the moment only pool test is implemented.
> You need to inplement item test.
>
> Signed-off-by: Olga Krishtal <okrishtal(a)virtuozzo.com>
> ---
> docs/schemas/fsitem.rng | 69 ++++++++++++++
> docs/schemas/fspool.rng | 83 ++++++++++++++++
> tests/fsitemxml2xmltest.c | 105 +++++++++++++++++++++
> .../dir-missing-target-path-invalid.xml | 12 +++
> tests/fspoolxml2xmlin/fspool-dir.xml | 17 ++++
> tests/fspoolxml2xmlout/fspool-dir.xml | 17 ++++
> tests/fspoolxml2xmltest.c | 82 ++++++++++++++++
> 7 files changed, 385 insertions(+)
> create mode 100644 docs/schemas/fsitem.rng
> create mode 100644 docs/schemas/fspool.rng
> create mode 100644 tests/fsitemxml2xmltest.c
> create mode 100644 tests/fspoolschemadata/dir-missing-target-path-invalid.xml
> create mode 100644 tests/fspoolxml2xmlin/fspool-dir.xml
> create mode 100644 tests/fspoolxml2xmlout/fspool-dir.xml
> create mode 100644 tests/fspoolxml2xmltest.c
>
> diff --git a/docs/schemas/fsitem.rng b/docs/schemas/fsitem.rng
> new file mode 100644
> index 0000000..a41659c
> --- /dev/null
> +++ b/docs/schemas/fsitem.rng
> @@ -0,0 +1,69 @@
> +<?xml version="1.0"?>
> +<!-- A Relax NG schema for the libvirt storage volume XML format -->
> +<grammar xmlns="http://relaxng.org/ns/structure/1.0"
> + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
> + <include href='basictypes.rng'/>
> + <start>
> + <ref name='vol'/>
> + </start>
> +
> + <include href='storagecommon.rng'/>
> +
> +
> + <define name='item'>
> + <element name='fsitem'>
> + <optional>
> + <attribute name='type'>
> + <value>dir</value>
> + </attribute>
> + </optional>
> + <interleave>
> + <element name='name'>
> + <ref name='volName'/>
> + </element>
> + <optional>
> + <element name='key'>
> + <text/>
> + </element>
> + </optional>
> + <ref name='sizing'/>
> + <ref name='target'/>
> + </interleave>
> + </element>
> + </define>
> +
> + <define name='sizing'>
> + <interleave>
> + <optional>
> + <element name='capacity'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + <optional>
> + <element name='allocation'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + </interleave>
> + </define>
> +
> + <define name='target'>
> + <element name='target'>
> + <interleave>
> + <optional>
> + <element name='path'>
> + <choice>
> + <data type='anyURI'/>
> + <ref name='absFilePath'/>
> + </choice>
> + </element>
> + </optional>
> + <ref name='permissions'/>
> + <optional>
> + <ref name='fileFormatFeatures'/>
> + </optional>
> + </interleave>
> + </element>
> + </define>
> +
> +</grammar>
> diff --git a/docs/schemas/fspool.rng b/docs/schemas/fspool.rng
> new file mode 100644
> index 0000000..132b65c
> --- /dev/null
> +++ b/docs/schemas/fspool.rng
> @@ -0,0 +1,83 @@
> +<?xml version="1.0"?>
> +<!-- A Relax NG schema for the libvirt storage pool XML format -->
> +<grammar xmlns="http://relaxng.org/ns/structure/1.0"
> + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
> + <include href='basictypes.rng'/>
> + <include href='storagecommon.rng'/>
> + <start>
> + <ref name='pool'/>
> + </start>
> +
> +
> + <define name='fspool'>
> + <element name='fspool'>
> + <choice>
> + <ref name='fspooldir'/>
> + </choice>
> + </element>
> + </define>
> +
> + <define name='fspooldir'>
> + <attribute name='type'>
> + <value>dir</value>
> + </attribute>
> + <interleave>
> + <ref name='commonmetadata'/>
> + <ref name='sizing'/>
> + <ref name='sourcedir'/>
> + <ref name='target'/>
> + </interleave>
> + </define>
> +
> + <define name='commonmetadata'>
> + <interleave>
> + <element name='name'>
> + <ref name='genericName'/>
> + </element>
> + <optional>
> + <element name='uuid'>
> + <ref name='UUID'/>
> + </element>
> + </optional>
> + </interleave>
> + </define>
> +
> + <define name='sizing'>
> + <interleave>
> + <optional>
> + <element name='capacity'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + <optional>
> + <element name='allocation'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + <optional>
> + <element name='available'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + </interleave>
> + </define>
> +
> + <define name='target'>
> + <element name='target'>
> + <interleave>
> + <element name='path'>
> + <ref name='absFilePath'/>
> + </element>
> + <ref name='permissions'/>
> + </interleave>
> + </element>
> + </define>
> +
> + <define name='sourcedir'>
> + <optional>
> + <element name='source'>
> + </element>
> + </optional>
> + </define>
> +
> +</grammar>
> diff --git a/tests/fsitemxml2xmltest.c b/tests/fsitemxml2xmltest.c
> new file mode 100644
> index 0000000..87a24e3
> --- /dev/null
> +++ b/tests/fsitemxml2xmltest.c
> @@ -0,0 +1,105 @@
> +#include <config.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +#include <sys/types.h>
> +#include <fcntl.h>
> +
> +#include "internal.h"
> +#include "testutils.h"
> +#include "storage_conf.h"
> +#include "testutilsqemu.h"
> +#include "virstring.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +static int
> +testCompareXMLToXMLFiles(const char *poolxml, const char *inxml,
> + const char *outxml, unsigned int flags)
> +{
> + char *actual = NULL;
> + int ret = -1;
> + virFSPoolDefPtr pool = NULL;
> + virFSItemDefPtr dev = NULL;
> +
> + if (!(pool = virFSPoolDefParseFile(poolxml)))
> + goto fail;
> +
> + if (!(dev = virFSItemDefParseFile(pool, inxml, flags)))
> + goto fail;
> +
> + if (!(actual = virFSItemDefFormat(pool, dev)))
> + goto fail;
> +
> + if (virTestCompareToFile(actual, outxml) < 0)
> + goto fail;
> +
> + ret = 0;
> +
> + fail:
> + VIR_FREE(actual);
> + virFSPoolDefFree(pool);
> + virFSItemDefFree(dev);
> + return ret;
> +}
> +
> +struct testInfo {
> + const char *pool;
> + const char *name;
> + unsigned int flags;
> +};
> +
> +static int
> +testCompareXMLToXMLHelper(const void *data)
> +{
> + int result = -1;
> + const struct testInfo *info = data;
> + char *poolxml = NULL;
> + char *inxml = NULL;
> + char *outxml = NULL;
> +
> + if (virAsprintf(&poolxml, "%s/storagepoolxml2xmlin/%s.xml",
> + abs_srcdir, info->pool) < 0 ||
> + virAsprintf(&inxml, "%s/storagevolxml2xmlin/%s.xml",
> + abs_srcdir, info->name) < 0 ||
> + virAsprintf(&outxml, "%s/storagevolxml2xmlout/%s.xml",
> + abs_srcdir, info->name) < 0) {
> + goto cleanup;
> + }
> +
> + result = testCompareXMLToXMLFiles(poolxml, inxml, outxml, info->flags);
> +
> + cleanup:
> + VIR_FREE(poolxml);
> + VIR_FREE(inxml);
> + VIR_FREE(outxml);
> +
> + return result;
> +}
> +
> +
> +static int
> +mymain(void)
> +{
> + int ret = 0;
> +
> +#define DO_TEST_FULL(pool, name, flags) \
> + do { \
> + struct testInfo info = { pool, name, flags }; \
> + if (virTestRun("FS Item XML-2-XML " name, \
> + testCompareXMLToXMLHelper, &info) < 0) \
> + ret = -1; \
> + } \
> + while (0);
> +
> +#define DO_TEST(pool, name) DO_TEST_FULL(pool, name, 0)
> +
> + DO_TEST("pool-dir", "vol-file");
> +
> + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> +
> +VIRT_TEST_MAIN(mymain)
> diff --git a/tests/fspoolschemadata/dir-missing-target-path-invalid.xml b/tests/fspoolschemadata/dir-missing-target-path-invalid.xml
> new file mode 100644
> index 0000000..a52bf49
> --- /dev/null
> +++ b/tests/fspoolschemadata/dir-missing-target-path-invalid.xml
> @@ -0,0 +1,12 @@
> +<fspool type='dir'>
> + <name>test</name>
> + <source>
> + </source>
> + <target>
> + <permissions>
> + <mode>0700</mode>
> + <owner>-1</owner>
> + <group>-1</group>
> + </permissions>
> + </target>
> +</fspool>
> diff --git a/tests/fspoolxml2xmlin/fspool-dir.xml b/tests/fspoolxml2xmlin/fspool-dir.xml
> new file mode 100644
> index 0000000..a3a1639
> --- /dev/null
> +++ b/tests/fspoolxml2xmlin/fspool-dir.xml
> @@ -0,0 +1,17 @@
> +<fspool type='dir'>
> + <name>virtfs</name>
> + <uuid>5584ee21-db40-4e98-980e-44802c47b62f</uuid>
> + <capacity unit='bytes'>0</capacity>
> + <allocation unit='bytes'>0</allocation>
> + <available unit='bytes'>0</available>
> + <source>
> + </source>
> + <target>
> + <path>///var/////lib/libvirt/fs//</path>
> + <permissions>
> + <mode>0700</mode>
> + <owner>-1</owner>
> + <group>-1</group>
> + </permissions>
> + </target>
> +</fspool>
> diff --git a/tests/fspoolxml2xmlout/fspool-dir.xml b/tests/fspoolxml2xmlout/fspool-dir.xml
> new file mode 100644
> index 0000000..30aca89
> --- /dev/null
> +++ b/tests/fspoolxml2xmlout/fspool-dir.xml
> @@ -0,0 +1,17 @@
> +<fspool type='dir'>
> + <name>virtfs</name>
> + <uuid> 5584ee21-db40-4e98-980e-44802c47b62f</uuid>
> + <capacity unit='bytes'>0</capacity>
> + <allocation unit='bytes'>0</allocation>
> + <available unit='bytes'>0</available>
> + <source>
> + </source>
> + <target>
> + <path>/var/lib/libvirt/fs</path>
> + <permissions>
> + <mode>0700</mode>
> + <owner>-1</owner>
> + <group>-1</group>
> + </permissions>
> + </target>
> +</fspool>
> diff --git a/tests/fspoolxml2xmltest.c b/tests/fspoolxml2xmltest.c
> new file mode 100644
> index 0000000..b66e959
> --- /dev/null
> +++ b/tests/fspoolxml2xmltest.c
> @@ -0,0 +1,82 @@
> +#include <config.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +#include <sys/types.h>
> +#include <fcntl.h>
> +
> +#include "internal.h"
> +#include "testutils.h"
> +#include "fs_conf.h"
> +#include "testutilsqemu.h"
> +#include "virstring.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +static int
> +testCompareXMLToXMLFiles(const char *inxml, const char *outxml)
> +{
> + char *actual = NULL;
> + int ret = -1;
> + virFSPoolDefPtr dev = NULL;
> +
> + if (!(dev = virFSPoolDefParseFile(inxml)))
> + goto fail;
> +
> + if (!(actual = virFSPoolDefFormat(dev)))
> + goto fail;
> +
> + if (virTestCompareToFile(actual, outxml) < 0)
> + goto fail;
> +
> + ret = 0;
> +
> + fail:
> + VIR_FREE(actual);
> + virFSPoolDefFree(dev);
> + return ret;
> +}
> +
> +static int
> +testCompareXMLToXMLHelper(const void *data)
> +{
> + int result = -1;
> + char *inxml = NULL;
> + char *outxml = NULL;
> +
> + if (virAsprintf(&inxml, "%s/fspoolxml2xmlin/%s.xml",
> + abs_srcdir, (const char*)data) < 0 ||
> + virAsprintf(&outxml, "%s/fspoolxml2xmlout/%s.xml",
> + abs_srcdir, (const char*)data) < 0) {
> + goto cleanup;
> + }
> +
> + result = testCompareXMLToXMLFiles(inxml, outxml);
> +
> + cleanup:
> + VIR_FREE(inxml);
> + VIR_FREE(outxml);
> +
> + return result;
> +}
> +
> +static int
> +mymain(void)
> +{
> + int ret = 0;
> +
> +#define DO_TEST(name) \
> + if (virTestRun("FS Pool XML-2-XML " name, \
> + testCompareXMLToXMLHelper, (name)) < 0) \
> + ret = -1
> +
> + DO_TEST("pool-dir");
> +#endif
> +
> + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> +
> +VIRT_TEST_MAIN(mymain)
8 years, 7 months