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@xxxxxxxxx> --- 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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list