/* * test.c: A "mock" hypervisor for use by application unit tests * * Copyright (C) 2006-2014 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 * . * * Daniel Berrange */ #include #include #include #include #include #include #include #include #include #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 "node_device_conf.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" #define VIR_FROM_THIS VIR_FROM_TEST /* Driver specific info to carry with a domain */ struct _testDomainObjPrivate { virVcpuInfoPtr vcpu_infos; unsigned char *cpumaps; }; typedef struct _testDomainObjPrivate testDomainObjPrivate; typedef struct _testDomainObjPrivate *testDomainObjPrivatePtr; #define MAX_CPUS 128 struct _testCell { unsigned long mem; 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 _testConn { virMutex lock; char *path; int nextDomID; virCapsPtr caps; virDomainXMLOptionPtr xmlopt; virNodeInfo nodeInfo; virDomainObjListPtr domains; virNetworkObjList networks; virInterfaceObjList ifaces; bool transaction_running; virInterfaceObjList backupIfaces; virStoragePoolObjList pools; virNodeDeviceObjList devs; int numCells; testCell cells[MAX_CELLS]; size_t numAuths; testAuthPtr auths; virObjectEventStatePtr eventState; }; typedef struct _testConn testConn; typedef struct _testConn *testConnPtr; static testConn defaultConn; static int defaultConnections; static virMutex defaultLock; #define TEST_MODEL "i686" #define TEST_MODEL_WORDSIZE 32 #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 int testConnectClose(virConnectPtr conn); static void testObjectEventQueue(testConnPtr driver, virObjectEventPtr event); static int testOnceInit(void) { return virMutexInit(&defaultLock); } VIR_ONCE_GLOBAL_INIT(test) static void testDriverLock(testConnPtr driver) { virMutexLock(&driver->lock); } static void testDriverUnlock(testConnPtr driver) { virMutexUnlock(&driver->lock); } static void *testDomainObjPrivateAlloc(void) { testDomainObjPrivatePtr priv; if (VIR_ALLOC(priv) < 0) return NULL; return priv; } static void testDomainObjPrivateFree(void *data) { testDomainObjPrivatePtr priv = data; VIR_FREE(priv->vcpu_infos); VIR_FREE(priv->cpumaps); VIR_FREE(priv); } #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 virDomainXMLOptionPtr testBuildXMLConfig(void) { virDomainXMLPrivateDataCallbacks priv = { .alloc = testDomainObjPrivateAlloc, .free = testDomainObjPrivateFree }; /* All our XML extensions are input only, so we only need to parse */ virDomainXMLNamespace ns = { .parse = testDomainDefNamespaceParse, .free = testDomainDefNamespaceFree, }; return virDomainXMLOptionNew(NULL, &priv, &ns); } static virCapsPtr testBuildCapabilities(virConnectPtr conn) { testConnPtr privconn = conn->privateData; virCapsPtr caps; virCapsGuestPtr guest; const char *const guest_types[] = { "hvm", "xen" }; size_t i; if ((caps = virCapabilitiesNew(VIR_ARCH_I686, 0, 0)) == NULL) goto error; if (virCapabilitiesAddHostFeature(caps, "pae") < 0) goto error; if (virCapabilitiesAddHostFeature(caps, "nonpae") < 0) goto error; for (i = 0; i < privconn->numCells; i++) { virCapsHostNUMACellCPUPtr cpu_cells; if (VIR_ALLOC_N(cpu_cells, privconn->cells[i].numCpus) < 0) goto error; memcpy(cpu_cells, privconn->cells[i].cpus, sizeof(*cpu_cells) * privconn->cells[i].numCpus); if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].numCpus, 0, cpu_cells) < 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, "test", NULL, NULL, 0, NULL) == NULL) goto error; if (virCapabilitiesAddGuestFeature(guest, "pae", 1, 1) == NULL) goto error; if (virCapabilitiesAddGuestFeature(guest, "nonpae", 1, 1) == 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 const char *defaultDomainXML = "" " test" " 6695eb01-f6a4-8304-79aa-97f2502e193f" " 8388608" " 2097152" " 2" " " " hvm" " " ""; static const char *defaultNetworkXML = "" " default" " dd8fe884-6c02-601e-7551-cca97df1c5df" " " " " " " " " " " " " " " ""; static const char *defaultInterfaceXML = "" " " " " " " " " " " " " " " ""; static const char *defaultPoolXML = "" " default-pool" " dfe224cb-28fb-8dd0-c4b2-64eb3f0f4566" " " " /default-pool" " " ""; static const char *defaultPoolSourcesLogicalXML = "\n" " \n" " \n" " testvg1\n" " \n" " \n" " \n" " \n" " testvg2\n" " \n" " \n" "\n"; static const char *defaultPoolSourcesNetFSXML = "\n" " \n" " \n" " \n" " \n" " \n" "\n"; static const char *defaultNodeXML = "" " computer" " " " " " Libvirt" " Test driver" " 123456" " 11111111-2222-3333-4444-555555555555" " " " " " Libvirt" " Test Driver" " 01/22/2007" " " " " ""; static const unsigned long long defaultPoolCap = (100 * 1024 * 1024 * 1024ull); static const unsigned long long defaultPoolAlloc = 0; static int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool); static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info); static virDomainObjPtr testDomObjFromDomain(virDomainPtr domain) { virDomainObjPtr vm; testConnPtr driver = domain->conn->privateData; char uuidstr[VIR_UUID_STRING_BUFLEN]; testDriverLock(driver); vm = virDomainObjListFindByUUID(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); } testDriverUnlock(driver); 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; } 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; } /* Helper to update info for a single VCPU */ static int testDomainUpdateVCPU(virDomainObjPtr dom, int vcpu, int maplen, int maxcpu) { testDomainObjPrivatePtr privdata = dom->privateData; virVcpuInfoPtr info = &privdata->vcpu_infos[vcpu]; unsigned char *cpumap = VIR_GET_CPUMAP(privdata->cpumaps, maplen, vcpu); size_t j; bool cpu; memset(info, 0, sizeof(virVcpuInfo)); memset(cpumap, 0, maplen); info->number = vcpu; info->state = VIR_VCPU_RUNNING; info->cpuTime = 5000000; info->cpu = 0; if (dom->def->cpumask) { for (j = 0; j < maxcpu && j < VIR_DOMAIN_CPUMASK_LEN; ++j) { if (virBitmapGetBit(dom->def->cpumask, j, &cpu) < 0) return -1; if (cpu) { VIR_USE_CPU(cpumap, j); info->cpu = j; } } } else { for (j = 0; j < maxcpu; ++j) { if ((j % 3) == 0) { /* Mark of every third CPU as usable */ VIR_USE_CPU(cpumap, j); info->cpu = j; } } } return 0; } /* * Update domain VCPU amount and info * * @conn: virConnectPtr * @dom : domain needing updates * @nvcpus: New amount of vcpus for the domain * @clear_all: If true, rebuild info for ALL vcpus, not just newly added vcpus */ static int testDomainUpdateVCPUs(testConnPtr privconn, virDomainObjPtr dom, int nvcpus, unsigned int clear_all) { testDomainObjPrivatePtr privdata = dom->privateData; size_t i; int ret = -1; int cpumaplen, maxcpu; maxcpu = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo); cpumaplen = VIR_CPU_MAPLEN(maxcpu); if (VIR_REALLOC_N(privdata->vcpu_infos, nvcpus) < 0) goto cleanup; if (VIR_REALLOC_N(privdata->cpumaps, nvcpus * cpumaplen) < 0) goto cleanup; /* Set running VCPU and cpumap state */ if (clear_all) { for (i = 0; i < nvcpus; ++i) if (testDomainUpdateVCPU(dom, i, cpumaplen, maxcpu) < 0) goto cleanup; } else if (nvcpus > dom->def->vcpus) { /* VCPU amount has grown, populate info for the new vcpus */ for (i = dom->def->vcpus; i < nvcpus; ++i) if (testDomainUpdateVCPU(dom, i, cpumaplen, maxcpu) < 0) goto cleanup; } dom->def->vcpus = nvcpus; ret = 0; cleanup: return ret; } static void testDomainShutdownState(virDomainPtr domain, virDomainObjPtr privdom, virDomainShutoffReason reason) { if (privdom->newDef) { virDomainDefFree(privdom->def); privdom->def = privdom->newDef; privdom->newDef = NULL; } virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason); privdom->def->id = -1; if (domain) domain->id = -1; } /* Set up domain runtime state */ static int testDomainStartState(testConnPtr privconn, virDomainObjPtr dom, virDomainRunningReason reason) { int ret = -1; if (testDomainUpdateVCPUs(privconn, dom, dom->def->vcpus, 1) < 0) goto cleanup; virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason); dom->def->id = privconn->nextDomID++; if (virDomainObjSetDefTransient(privconn->caps, privconn->xmlopt, dom, false) < 0) { goto cleanup; } dom->hasManagedSave = false; ret = 0; cleanup: if (ret < 0) testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED); return ret; } /* 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; testConnPtr privconn = &defaultConn; virDomainDefPtr domdef = NULL; virDomainObjPtr domobj = NULL; virNetworkDefPtr netdef = NULL; virNetworkObjPtr netobj = NULL; virInterfaceDefPtr interfacedef = NULL; virInterfaceObjPtr interfaceobj = NULL; virStoragePoolDefPtr pooldef = NULL; virStoragePoolObjPtr poolobj = NULL; virNodeDeviceDefPtr nodedef = NULL; virNodeDeviceObjPtr nodeobj = NULL; virMutexLock(&defaultLock); if (defaultConnections++) { conn->privateData = &defaultConn; virMutexUnlock(&defaultLock); return VIR_DRV_OPEN_SUCCESS; } if (virMutexInit(&privconn->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize mutex")); defaultConnections--; virMutexUnlock(&defaultLock); return VIR_DRV_OPEN_ERROR; } conn->privateData = privconn; if (!(privconn->eventState = virObjectEventStateNew())) goto error; if (!(privconn->domains = virDomainObjListNew())) goto error; memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo)); /* Numa setup */ privconn->numCells = 2; for (u = 0; u < 2; ++u) { privconn->cells[u].numCpus = 8; privconn->cells[u].mem = (u + 1) * 2048 * 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 (!(privconn->xmlopt = testBuildXMLConfig())) goto error; privconn->nextDomID = 1; if (!(domdef = virDomainDefParseString(defaultDomainXML, privconn->caps, privconn->xmlopt, 1 << VIR_DOMAIN_VIRT_TEST, VIR_DOMAIN_XML_INACTIVE))) goto error; if (testDomainGenerateIfnames(domdef) < 0) goto error; if (!(domobj = virDomainObjListAdd(privconn->domains, domdef, privconn->xmlopt, 0, NULL))) goto error; domdef = NULL; domobj->persistent = 1; if (testDomainStartState(privconn, domobj, VIR_DOMAIN_RUNNING_BOOTED) < 0) { virObjectUnlock(domobj); goto error; } virObjectUnlock(domobj); if (!(netdef = virNetworkDefParseString(defaultNetworkXML))) goto error; if (!(netobj = virNetworkAssignDef(&privconn->networks, netdef, false))) { virNetworkDefFree(netdef); goto error; } netobj->active = 1; netobj->persistent = 1; virNetworkObjUnlock(netobj); if (!(interfacedef = virInterfaceDefParseString(defaultInterfaceXML))) goto error; if (!(interfaceobj = virInterfaceAssignDef(&privconn->ifaces, interfacedef))) { virInterfaceDefFree(interfacedef); goto error; } interfaceobj->active = 1; virInterfaceObjUnlock(interfaceobj); if (!(pooldef = virStoragePoolDefParseString(defaultPoolXML))) goto error; if (!(poolobj = virStoragePoolObjAssignDef(&privconn->pools, pooldef))) { virStoragePoolDefFree(pooldef); goto error; } if (testStoragePoolObjSetDefaults(poolobj) == -1) { virStoragePoolObjUnlock(poolobj); goto error; } poolobj->active = 1; virStoragePoolObjUnlock(poolobj); /* Init default node device */ if (!(nodedef = virNodeDeviceDefParseString(defaultNodeXML, 0, NULL))) goto error; if (!(nodeobj = virNodeDeviceAssignDef(&privconn->devs, nodedef))) { virNodeDeviceDefFree(nodedef); goto error; } virNodeDeviceObjUnlock(nodeobj); virMutexUnlock(&defaultLock); return VIR_DRV_OPEN_SUCCESS; error: virObjectUnref(privconn->domains); virNetworkObjListFree(&privconn->networks); virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); virNodeDeviceObjListFree(&privconn->devs); virObjectUnref(privconn->caps); virObjectEventStateFree(privconn->eventState); virMutexDestroy(&privconn->lock); conn->privateData = NULL; virDomainDefFree(domdef); defaultConnections--; virMutexUnlock(&defaultLock); return VIR_DRV_OPEN_ERROR; } 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(testConnPtr 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, 1 << VIR_DOMAIN_VIRT_TEST, 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(testConnPtr 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, 1 << VIR_DOMAIN_VIRT_TEST, VIR_DOMAIN_XML_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(testConnPtr 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, false))) { virNetworkDefFree(def); goto error; } obj->persistent = 1; obj->active = 1; virNetworkObjUnlock(obj); } ret = 0; error: VIR_FREE(nodes); return ret; } static int testParseInterfaces(testConnPtr 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); if (!def) goto error; if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count+1) < 0) 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; pool->def->allocation += def->allocation; pool->def->available = (pool->def->capacity - pool->def->allocation); pool->volumes.objs[pool->volumes.count++] = def; def = NULL; } ret = 0; error: virStorageVolDefFree(def); VIR_FREE(nodes); return ret; } static int testParseStorage(testConnPtr 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(testConnPtr 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(testConnPtr 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; } /* 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; testConnPtr privconn; if (VIR_ALLOC(privconn) < 0) return VIR_DRV_OPEN_ERROR; if (virMutexInit(&privconn->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize mutex")); VIR_FREE(privconn); return VIR_DRV_OPEN_ERROR; } testDriverLock(privconn); conn->privateData = privconn; if (!(privconn->domains = virDomainObjListNew())) goto error; if (!(privconn->caps = testBuildCapabilities(conn))) goto error; if (!(privconn->xmlopt = testBuildXMLConfig())) goto error; if (!(privconn->eventState = virObjectEventStateNew())) goto error; if (!(doc = virXMLParseFileCtxt(file, &ctxt))) { goto error; } if (!xmlStrEqual(ctxt->node->name, BAD_CAST "node")) { virReportError(VIR_ERR_XML_ERROR, "%s", _("Root element is not 'node'")); goto error; } privconn->nextDomID = 1; privconn->numCells = 0; if (VIR_STRDUP(privconn->path, file) < 0) goto error; memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo)); 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; xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); testDriverUnlock(privconn); return 0; error: xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); virObjectUnref(privconn->domains); virNetworkObjListFree(&privconn->networks); virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); VIR_FREE(privconn->path); virObjectEventStateFree(privconn->eventState); testDriverUnlock(privconn); VIR_FREE(privconn); conn->privateData = NULL; return VIR_DRV_OPEN_ERROR; } static int testConnectAuthenticate(virConnectPtr conn, virConnectAuthPtr auth) { testConnPtr 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 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, unsigned int flags) { int ret; virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (testInitialize() < 0) return 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) { testConnPtr privconn = conn->privateData; if (testInitialize() < 0) return -1; if (privconn == &defaultConn) { virMutexLock(&defaultLock); if (--defaultConnections) { virMutexUnlock(&defaultLock); return 0; } } testDriverLock(privconn); virObjectUnref(privconn->caps); virObjectUnref(privconn->xmlopt); virObjectUnref(privconn->domains); virNodeDeviceObjListFree(&privconn->devs); virNetworkObjListFree(&privconn->networks); virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); virObjectEventStateFree(privconn->eventState); VIR_FREE(privconn->path); testDriverUnlock(privconn); virMutexDestroy(&privconn->lock); if (privconn == &defaultConn) virMutexUnlock(&defaultLock); else VIR_FREE(privconn); 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) { testConnPtr privconn = conn->privateData; testDriverLock(privconn); memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo)); testDriverUnlock(privconn); return 0; } static char *testConnectGetCapabilities(virConnectPtr conn) { testConnPtr privconn = conn->privateData; char *xml; testDriverLock(privconn); if ((xml = virCapabilitiesFormatXML(privconn->caps)) == NULL) virReportOOMError(); testDriverUnlock(privconn); return xml; } static int testConnectNumOfDomains(virConnectPtr conn) { testConnPtr privconn = conn->privateData; int count; testDriverLock(privconn); count = virDomainObjListNumOfDomains(privconn->domains, true, NULL, NULL); testDriverUnlock(privconn); return count; } static int testDomainIsActive(virDomainPtr dom) { testConnPtr privconn = dom->conn->privateData; virDomainObjPtr obj; int ret = -1; testDriverLock(privconn); obj = virDomainObjListFindByUUID(privconn->domains, dom->uuid); testDriverUnlock(privconn); if (!obj) { virReportError(VIR_ERR_NO_DOMAIN, NULL); goto cleanup; } ret = virDomainObjIsActive(obj); cleanup: if (obj) virObjectUnlock(obj); return ret; } static int testDomainIsPersistent(virDomainPtr dom) { testConnPtr privconn = dom->conn->privateData; virDomainObjPtr obj; int ret = -1; testDriverLock(privconn); obj = virDomainObjListFindByUUID(privconn->domains, dom->uuid); testDriverUnlock(privconn); if (!obj) { virReportError(VIR_ERR_NO_DOMAIN, NULL); goto cleanup; } ret = obj->persistent; cleanup: if (obj) virObjectUnlock(obj); return ret; } static int testDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED) { return 0; } static virDomainPtr testDomainCreateXML(virConnectPtr conn, const char *xml, unsigned int flags) { testConnPtr privconn = conn->privateData; virDomainPtr ret = NULL; virDomainDefPtr def; virDomainObjPtr dom = NULL; virObjectEventPtr event = NULL; virCheckFlags(0, NULL); testDriverLock(privconn); if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, 1 << VIR_DOMAIN_VIRT_TEST, VIR_DOMAIN_XML_INACTIVE)) == NULL) goto cleanup; if (testDomainGenerateIfnames(def) < 0) goto cleanup; if (!(dom = virDomainObjListAdd(privconn->domains, def, privconn->xmlopt, VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, NULL))) goto cleanup; def = NULL; if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) 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); if (event) testObjectEventQueue(privconn, event); virDomainDefFree(def); testDriverUnlock(privconn); return ret; } static virDomainPtr testDomainLookupByID(virConnectPtr conn, int id) { testConnPtr privconn = conn->privateData; virDomainPtr ret = NULL; virDomainObjPtr dom; testDriverLock(privconn); dom = virDomainObjListFindByID(privconn->domains, id); testDriverUnlock(privconn); if (dom == NULL) { 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) { testConnPtr privconn = conn->privateData; virDomainPtr ret = NULL; virDomainObjPtr dom; testDriverLock(privconn); dom = virDomainObjListFindByUUID(privconn->domains, uuid); testDriverUnlock(privconn); if (dom == NULL) { 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) { testConnPtr privconn = conn->privateData; virDomainPtr ret = NULL; virDomainObjPtr dom; testDriverLock(privconn); dom = virDomainObjListFindByName(privconn->domains, name); testDriverUnlock(privconn); if (dom == NULL) { 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 int testConnectListDomains(virConnectPtr conn, int *ids, int maxids) { testConnPtr privconn = conn->privateData; int n; testDriverLock(privconn); n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids, NULL, NULL); testDriverUnlock(privconn); return n; } static int testDomainDestroy(virDomainPtr domain) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; virObjectEventPtr event = NULL; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); 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); privdom = NULL; } ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); return ret; } static int testDomainResume(virDomainPtr domain) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; virObjectEventPtr event = NULL; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } 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: if (privdom) virObjectUnlock(privdom); if (event) { testDriverLock(privconn); testObjectEventQueue(privconn, event); testDriverUnlock(privconn); } return ret; } static int testDomainSuspend(virDomainPtr domain) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; virObjectEventPtr event = NULL; int ret = -1; int state; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } 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: if (privdom) virObjectUnlock(privdom); if (event) { testDriverLock(privconn); testObjectEventQueue(privconn, event); testDriverUnlock(privconn); } return ret; } static int testDomainShutdownFlags(virDomainPtr domain, unsigned int flags) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; virObjectEventPtr event = NULL; int ret = -1; virCheckFlags(0, -1); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); 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); privdom = NULL; } ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); 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) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; virObjectEventPtr event = NULL; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); 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); privdom = NULL; } } ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); return ret; } static int testDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) { testConnPtr privconn = domain->conn->privateData; struct timeval tv; virDomainObjPtr privdom; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } 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 = privdom->def->mem.max_balloon; info->nrVirtCpu = privdom->def->vcpus; info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainGetState(virDomainPtr domain, int *state, int *reason, unsigned int flags) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; int ret = -1; virCheckFlags(0, -1); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } *state = virDomainObjGetState(privdom, reason); ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } #define TEST_SAVE_MAGIC "TestGuestMagic" static int testDomainSaveFlags(virDomainPtr domain, const char *path, const char *dxml, unsigned int flags) { testConnPtr 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; } testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } xml = virDomainDefFormat(privdom->def, VIR_DOMAIN_XML_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); privdom = NULL; } 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); } if (privdom) virObjectUnlock(privdom); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); 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) { testConnPtr 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; } testDriverLock(privconn); 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, 1 << VIR_DOMAIN_VIRT_TEST, VIR_DOMAIN_XML_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) 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); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); return ret; } static int testDomainRestore(virConnectPtr conn, const char *path) { return testDomainRestoreFlags(conn, path, NULL, 0); } static int testDomainCoreDump(virDomainPtr domain, const char *to, unsigned int flags) { testConnPtr privconn = domain->conn->privateData; int fd = -1; virDomainObjPtr privdom; virObjectEventPtr event = NULL; int ret = -1; virCheckFlags(VIR_DUMP_CRASH, -1); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); 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; } 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); privdom = NULL; } } ret = 0; cleanup: VIR_FORCE_CLOSE(fd); if (privdom) virObjectUnlock(privdom); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); 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) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; unsigned long long ret = 0; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } ret = privdom->def->mem.max_balloon; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } /* XXX validate not over host memory wrt to other domains */ privdom->def->mem.max_balloon = memory; ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainSetMemory(virDomainPtr domain, unsigned long memory) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } if (memory > privdom->def->mem.max_balloon) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } privdom->def->mem.cur_balloon = memory; ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr vm; virDomainDefPtr def; int ret = -1; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM, -1); testDriverLock(privconn); vm = virDomainObjListFindByUUID(privconn->domains, domain->uuid); testDriverUnlock(privconn); if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(domain->uuid, uuidstr); virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (virDomainLiveConfigHelperMethod(privconn->caps, privconn->xmlopt, vm, &flags, &def) < 0) goto cleanup; if (flags & VIR_DOMAIN_AFFECT_LIVE) def = vm->def; ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus; cleanup: if (vm) virObjectUnlock(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) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom = NULL; virDomainDefPtr persistentDef; int ret = -1, maxvcpus; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM, -1); /* At least one of LIVE or CONFIG must be set. MAXIMUM cannot be * mixed with LIVE. */ if ((flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) == 0 || (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_AFFECT_LIVE)) == (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_AFFECT_LIVE)) { virReportError(VIR_ERR_INVALID_ARG, _("invalid flag combination: (0x%x)"), flags); return -1; } if (!nrCpus || (maxvcpus = testConnectGetMaxVcpus(domain->conn, NULL)) < nrCpus) { virReportError(VIR_ERR_INVALID_ARG, _("argument out of range: %d"), nrCpus); return -1; } testDriverLock(privconn); privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } if (!virDomainObjIsActive(privdom) && (flags & VIR_DOMAIN_AFFECT_LIVE)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot hotplug vcpus for an inactive domain")); goto cleanup; } /* We allow more cpus in guest than host, but not more than the * domain's starting limit. */ if (!(flags & (VIR_DOMAIN_VCPU_MAXIMUM)) && privdom->def->maxvcpus < maxvcpus) maxvcpus = privdom->def->maxvcpus; if (nrCpus > maxvcpus) { virReportError(VIR_ERR_INVALID_ARG, _("requested cpu amount exceeds maximum (%d > %d)"), nrCpus, maxvcpus); goto cleanup; } if (!(persistentDef = virDomainObjGetPersistentDef(privconn->caps, privconn->xmlopt, privdom))) goto cleanup; switch (flags) { case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_AFFECT_CONFIG: persistentDef->maxvcpus = nrCpus; if (nrCpus < persistentDef->vcpus) persistentDef->vcpus = nrCpus; ret = 0; break; case VIR_DOMAIN_AFFECT_CONFIG: persistentDef->vcpus = nrCpus; ret = 0; break; case VIR_DOMAIN_AFFECT_LIVE: ret = testDomainUpdateVCPUs(privconn, privdom, nrCpus, 0); break; case VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG: ret = testDomainUpdateVCPUs(privconn, privdom, nrCpus, 0); if (ret == 0) { persistentDef->vcpus = nrCpus; } break; } cleanup: if (privdom) virObjectUnlock(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) { testConnPtr privconn = domain->conn->privateData; testDomainObjPrivatePtr privdomdata; virDomainObjPtr privdom; size_t i; int v, maxcpu, hostcpus; int ret = -1; struct timeval tv; unsigned long long statbase; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } if (!virDomainObjIsActive(privdom)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot list vcpus for an inactive domain")); goto cleanup; } privdomdata = privdom->privateData; 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; /* Clamp to actual number of vcpus */ if (maxinfo > privdom->def->vcpus) maxinfo = privdom->def->vcpus; /* Populate virVcpuInfo structures */ if (info != NULL) { memset(info, 0, sizeof(*info) * maxinfo); for (i = 0; i < maxinfo; i++) { virVcpuInfo privinfo = privdomdata->vcpu_infos[i]; info[i].number = privinfo.number; info[i].state = privinfo.state; info[i].cpu = privinfo.cpu; /* Fake an increasing cpu time value */ info[i].cpuTime = statbase / 10; } } /* Populate cpumaps */ if (cpumaps != NULL) { int privmaplen = VIR_CPU_MAPLEN(hostcpus); memset(cpumaps, 0, maplen * maxinfo); for (v = 0; v < maxinfo; v++) { unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v); for (i = 0; i < maxcpu; i++) { if (VIR_CPU_USABLE(privdomdata->cpumaps, privmaplen, v, i)) { VIR_USE_CPU(cpumap, i); } } } } ret = maxinfo; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainPinVcpu(virDomainPtr domain, unsigned int vcpu, unsigned char *cpumap, int maplen) { testConnPtr privconn = domain->conn->privateData; testDomainObjPrivatePtr privdomdata; virDomainObjPtr privdom; unsigned char *privcpumap; size_t i; int maxcpu, hostcpus, privmaplen; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } if (!virDomainObjIsActive(privdom)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot pin vcpus on an inactive domain")); goto cleanup; } if (vcpu > privdom->def->vcpus) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("requested vcpu is higher than allocated vcpus")); goto cleanup; } privdomdata = privdom->privateData; hostcpus = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo); privmaplen = VIR_CPU_MAPLEN(hostcpus); maxcpu = maplen * 8; if (maxcpu > hostcpus) maxcpu = hostcpus; privcpumap = VIR_GET_CPUMAP(privdomdata->cpumaps, privmaplen, vcpu); memset(privcpumap, 0, privmaplen); for (i = 0; i < maxcpu; i++) { if (VIR_CPU_USABLE(cpumap, maplen, 0, i)) { VIR_USE_CPU(privcpumap, i); } } ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) { testConnPtr privconn = domain->conn->privateData; virDomainDefPtr def; virDomainObjPtr privdom; char *ret = NULL; /* Flags checked by virDomainDefFormat */ testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } def = (flags & VIR_DOMAIN_XML_INACTIVE) && privdom->newDef ? privdom->newDef : privdom->def; ret = virDomainDefFormat(def, flags); cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testConnectNumOfDefinedDomains(virConnectPtr conn) { testConnPtr privconn = conn->privateData; int count; testDriverLock(privconn); count = virDomainObjListNumOfDomains(privconn->domains, false, NULL, NULL); testDriverUnlock(privconn); return count; } static int testConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) { testConnPtr privconn = conn->privateData; int n; testDriverLock(privconn); memset(names, 0, sizeof(*names)*maxnames); n = virDomainObjListGetInactiveNames(privconn->domains, names, maxnames, NULL, NULL); testDriverUnlock(privconn); return n; } static virDomainPtr testDomainDefineXML(virConnectPtr conn, const char *xml) { testConnPtr privconn = conn->privateData; virDomainPtr ret = NULL; virDomainDefPtr def; virDomainObjPtr dom = NULL; virObjectEventPtr event = NULL; virDomainDefPtr oldDef = NULL; testDriverLock(privconn); if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, 1 << VIR_DOMAIN_VIRT_TEST, VIR_DOMAIN_XML_INACTIVE)) == 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); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); return ret; } static char *testDomainGetMetadata(virDomainPtr dom, int type, const char *uri, unsigned int flags) { testConnPtr privconn = dom->conn->privateData; virDomainObjPtr privdom; char *ret = NULL; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, NULL); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, dom->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } ret = virDomainObjGetMetadata(privdom, type, uri, privconn->caps, privconn->xmlopt, flags); cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainSetMetadata(virDomainPtr dom, int type, const char *metadata, const char *key, const char *uri, unsigned int flags) { testConnPtr privconn = dom->conn->privateData; virDomainObjPtr privdom; int ret = -1; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, dom->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri, privconn->caps, privconn->xmlopt, NULL, flags); cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freemems, int startCell, int maxCells) { testConnPtr 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; } static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; virObjectEventPtr event = NULL; int ret = -1; virCheckFlags(0, -1); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); 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: if (privdom) virObjectUnlock(privdom); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); return ret; } static int testDomainCreate(virDomainPtr domain) { return testDomainCreateWithFlags(domain, 0); } static int testDomainUndefineFlags(virDomainPtr domain, unsigned int flags) { testConnPtr 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); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); 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); privdom = NULL; } ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); if (event) testObjectEventQueue(privconn, event); testDriverUnlock(privconn); return ret; } static int testDomainUndefine(virDomainPtr domain) { return testDomainUndefineFlags(domain, 0); } static int testDomainGetAutostart(virDomainPtr domain, int *autostart) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } *autostart = privdom->autostart; ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainSetAutostart(virDomainPtr domain, int autostart) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } privdom->autostart = autostart ? 1 : 0; ret = 0; cleanup: if (privdom) virObjectUnlock(privdom); return ret; } 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) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; int ret = -1; virCheckFlags(0, -1); testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } 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: if (privdom) virObjectUnlock(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) { testConnPtr privconn = domain->conn->privateData; 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; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } for (i = 0; i < nparams; i++) { if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) { /* XXX */ /*privdom->weight = params[i].value.ui;*/ } } ret = 0; cleanup: if (privdom) virObjectUnlock(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, struct _virDomainBlockStats *stats) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; struct timeval tv; unsigned long long statbase; int ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto error; } 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: if (privdom) virObjectUnlock(privdom); return ret; } static int testDomainInterfaceStats(virDomainPtr domain, const char *path, struct _virDomainInterfaceStats *stats) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; struct timeval tv; unsigned long long statbase; size_t i; int found = 0, ret = -1; testDriverLock(privconn); privdom = virDomainObjListFindByName(privconn->domains, domain->name); testDriverUnlock(privconn); if (privdom == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto error; } 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: if (privdom) virObjectUnlock(privdom); return ret; } static virDrvOpenStatus testNetworkOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "Test")) return VIR_DRV_OPEN_DECLINED; conn->networkPrivateData = conn->privateData; return VIR_DRV_OPEN_SUCCESS; } static int testNetworkClose(virConnectPtr conn) { conn->networkPrivateData = NULL; return 0; } static virNetworkPtr testNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { testConnPtr privconn = conn->privateData; virNetworkObjPtr net; virNetworkPtr ret = NULL; testDriverLock(privconn); net = virNetworkFindByUUID(&privconn->networks, uuid); testDriverUnlock(privconn); if (net == NULL) { virReportError(VIR_ERR_NO_NETWORK, NULL); goto cleanup; } ret = virGetNetwork(conn, net->def->name, net->def->uuid); cleanup: if (net) virNetworkObjUnlock(net); return ret; } static virNetworkPtr testNetworkLookupByName(virConnectPtr conn, const char *name) { testConnPtr privconn = conn->privateData; virNetworkObjPtr net; virNetworkPtr ret = NULL; testDriverLock(privconn); net = virNetworkFindByName(&privconn->networks, name); testDriverUnlock(privconn); if (net == NULL) { virReportError(VIR_ERR_NO_NETWORK, NULL); goto cleanup; } ret = virGetNetwork(conn, net->def->name, net->def->uuid); cleanup: if (net) virNetworkObjUnlock(net); return ret; } static int testConnectNumOfNetworks(virConnectPtr conn) { testConnPtr privconn = conn->privateData; int numActive = 0; size_t i; testDriverLock(privconn); for (i = 0; i < privconn->networks.count; i++) { virNetworkObjLock(privconn->networks.objs[i]); if (virNetworkObjIsActive(privconn->networks.objs[i])) numActive++; virNetworkObjUnlock(privconn->networks.objs[i]); } testDriverUnlock(privconn); return numActive; } static int testConnectListNetworks(virConnectPtr conn, char **const names, int nnames) { testConnPtr privconn = conn->privateData; int n = 0; size_t i; testDriverLock(privconn); memset(names, 0, sizeof(*names)*nnames); for (i = 0; i < privconn->networks.count && n < nnames; i++) { virNetworkObjLock(privconn->networks.objs[i]); if (virNetworkObjIsActive(privconn->networks.objs[i]) && VIR_STRDUP(names[n++], privconn->networks.objs[i]->def->name) < 0) { virNetworkObjUnlock(privconn->networks.objs[i]); goto error; } virNetworkObjUnlock(privconn->networks.objs[i]); } testDriverUnlock(privconn); return n; error: for (n = 0; n < nnames; n++) VIR_FREE(names[n]); testDriverUnlock(privconn); return -1; } static int testConnectNumOfDefinedNetworks(virConnectPtr conn) { testConnPtr privconn = conn->privateData; int numInactive = 0; size_t i; testDriverLock(privconn); for (i = 0; i < privconn->networks.count; i++) { virNetworkObjLock(privconn->networks.objs[i]); if (!virNetworkObjIsActive(privconn->networks.objs[i])) numInactive++; virNetworkObjUnlock(privconn->networks.objs[i]); } testDriverUnlock(privconn); return numInactive; } static int testConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) { testConnPtr privconn = conn->privateData; int n = 0; size_t i; testDriverLock(privconn); memset(names, 0, sizeof(*names)*nnames); for (i = 0; i < privconn->networks.count && n < nnames; i++) { virNetworkObjLock(privconn->networks.objs[i]); if (!virNetworkObjIsActive(privconn->networks.objs[i]) && VIR_STRDUP(names[n++], privconn->networks.objs[i]->def->name) < 0) { virNetworkObjUnlock(privconn->networks.objs[i]); goto error; } virNetworkObjUnlock(privconn->networks.objs[i]); } testDriverUnlock(privconn); return n; error: for (n = 0; n < nnames; n++) VIR_FREE(names[n]); testDriverUnlock(privconn); return -1; } static int testConnectListAllNetworks(virConnectPtr conn, virNetworkPtr **nets, unsigned int flags) { testConnPtr privconn = conn->privateData; int ret = -1; virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); testDriverLock(privconn); ret = virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags); testDriverUnlock(privconn); return ret; } static int testNetworkIsActive(virNetworkPtr net) { testConnPtr privconn = net->conn->privateData; virNetworkObjPtr obj; int ret = -1; testDriverLock(privconn); obj = virNetworkFindByUUID(&privconn->networks, net->uuid); testDriverUnlock(privconn); if (!obj) { virReportError(VIR_ERR_NO_NETWORK, NULL); goto cleanup; } ret = virNetworkObjIsActive(obj); cleanup: if (obj) virNetworkObjUnlock(obj); return ret; } static int testNetworkIsPersistent(virNetworkPtr net) { testConnPtr privconn = net->conn->privateData; virNetworkObjPtr obj; int ret = -1; testDriverLock(privconn); obj = virNetworkFindByUUID(&privconn->networks, net->uuid); testDriverUnlock(privconn); if (!obj) { virReportError(VIR_ERR_NO_NETWORK, NULL); goto cleanup; } ret = obj->persistent; cleanup: if (obj) virNetworkObjUnlock(obj); return ret; } static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml) { testConnPtr privconn = conn->privateData; virNetworkDefPtr def; virNetworkObjPtr net = NULL; virNetworkPtr ret = NULL; virObjectEventPtr event = NULL; testDriverLock(privconn); if ((def = virNetworkDefParseString(xml)) == NULL) goto cleanup; if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) 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); if (event) testObjectEventQueue(privconn, event); if (net) virNetworkObjUnlock(net); testDriverUnlock(privconn); return ret; } static virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml) { testConnPtr privconn = conn->privateData; virNetworkDefPtr def; virNetworkObjPtr net = NULL; virNetworkPtr ret = NULL; virObjectEventPtr event = NULL; testDriverLock(privconn); if ((def = virNetworkDefParseString(xml)) == NULL) goto cleanup; if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) goto cleanup; def = NULL; net->persistent = 1; 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); if (event) testObjectEventQueue(privconn, event); if (net) virNetworkObjUnlock(net); testDriverUnlock(privconn); return ret; } static int testNetworkUndefine(virNetworkPtr network) { testConnPtr privconn = network->conn->privateData; virNetworkObjPtr privnet; int ret = -1; virObjectEventPtr event = NULL; testDriverLock(privconn); privnet = virNetworkFindByName(&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); privnet = NULL; ret = 0; cleanup: if (event) testObjectEventQueue(privconn, event); if (privnet) virNetworkObjUnlock(privnet); testDriverUnlock(privconn); return ret; } static int testNetworkUpdate(virNetworkPtr net, unsigned int command, unsigned int section, int parentIndex, const char *xml, unsigned int flags) { testConnPtr privconn = net->conn->privateData; virNetworkObjPtr network = NULL; int isActive, ret = -1; virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG, -1); testDriverLock(privconn); network = virNetworkFindByUUID(&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: testDriverUnlock(privconn); return ret; } static int testNetworkCreate(virNetworkPtr network) { testConnPtr privconn = network->conn->privateData; virNetworkObjPtr privnet; int ret = -1; virObjectEventPtr event = NULL; testDriverLock(privconn); privnet = virNetworkFindByName(&privconn->networks, network->name); testDriverUnlock(privconn); 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: if (event) testObjectEventQueue(privconn, event); if (privnet) virNetworkObjUnlock(privnet); return ret; } static int testNetworkDestroy(virNetworkPtr network) { testConnPtr privconn = network->conn->privateData; virNetworkObjPtr privnet; int ret = -1; virObjectEventPtr event = NULL; testDriverLock(privconn); privnet = virNetworkFindByName(&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); privnet = NULL; } ret = 0; cleanup: if (event) testObjectEventQueue(privconn, event); if (privnet) virNetworkObjUnlock(privnet); testDriverUnlock(privconn); return ret; } static char *testNetworkGetXMLDesc(virNetworkPtr network, unsigned int flags) { testConnPtr privconn = network->conn->privateData; virNetworkObjPtr privnet; char *ret = NULL; virCheckFlags(0, NULL); testDriverLock(privconn); privnet = virNetworkFindByName(&privconn->networks, network->name); testDriverUnlock(privconn); if (privnet == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } ret = virNetworkDefFormat(privnet->def, flags); cleanup: if (privnet) virNetworkObjUnlock(privnet); return ret; } static char *testNetworkGetBridgeName(virNetworkPtr network) { testConnPtr privconn = network->conn->privateData; char *bridge = NULL; virNetworkObjPtr privnet; testDriverLock(privconn); privnet = virNetworkFindByName(&privconn->networks, network->name); testDriverUnlock(privconn); 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: if (privnet) virNetworkObjUnlock(privnet); return bridge; } static int testNetworkGetAutostart(virNetworkPtr network, int *autostart) { testConnPtr privconn = network->conn->privateData; virNetworkObjPtr privnet; int ret = -1; testDriverLock(privconn); privnet = virNetworkFindByName(&privconn->networks, network->name); testDriverUnlock(privconn); if (privnet == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } *autostart = privnet->autostart; ret = 0; cleanup: if (privnet) virNetworkObjUnlock(privnet); return ret; } static int testNetworkSetAutostart(virNetworkPtr network, int autostart) { testConnPtr privconn = network->conn->privateData; virNetworkObjPtr privnet; int ret = -1; testDriverLock(privconn); privnet = virNetworkFindByName(&privconn->networks, network->name); testDriverUnlock(privconn); if (privnet == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } privnet->autostart = autostart ? 1 : 0; ret = 0; cleanup: if (privnet) virNetworkObjUnlock(privnet); return ret; } /* * Physical host interface routines */ static virDrvOpenStatus testInterfaceOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "Test")) return VIR_DRV_OPEN_DECLINED; conn->interfacePrivateData = conn->privateData; return VIR_DRV_OPEN_SUCCESS; } static int testInterfaceClose(virConnectPtr conn) { conn->interfacePrivateData = NULL; return 0; } static int testConnectNumOfInterfaces(virConnectPtr conn) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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 virDrvOpenStatus testStorageOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "Test")) return VIR_DRV_OPEN_DECLINED; conn->storagePrivateData = conn->privateData; return VIR_DRV_OPEN_SUCCESS; } static int testStorageClose(virConnectPtr conn) { conn->storagePrivateData = NULL; return 0; } static virStoragePoolPtr testStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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; } privpool->active = 1; ret = 0; cleanup: 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) { testConnPtr privconn = conn->privateData; virStoragePoolDefPtr def; virStoragePoolObjPtr pool = NULL; virStoragePoolPtr ret = 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; ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid, NULL, NULL); cleanup: virStoragePoolDefFree(def); if (pool) virStoragePoolObjUnlock(pool); testDriverUnlock(privconn); return ret; } static virStoragePoolPtr testStoragePoolDefineXML(virConnectPtr conn, const char *xml, unsigned int flags) { testConnPtr privconn = conn->privateData; virStoragePoolDefPtr def; virStoragePoolObjPtr pool = NULL; virStoragePoolPtr ret = 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; 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); if (pool) virStoragePoolObjUnlock(pool); testDriverUnlock(privconn); return ret; } static int testStoragePoolUndefine(virStoragePoolPtr pool) { testConnPtr privconn = pool->conn->privateData; virStoragePoolObjPtr privpool; int ret = -1; 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; } virStoragePoolObjRemove(&privconn->pools, privpool); ret = 0; cleanup: if (privpool) virStoragePoolObjUnlock(privpool); testDriverUnlock(privconn); return ret; } static int testStoragePoolBuild(virStoragePoolPtr pool, unsigned int flags) { testConnPtr 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) { testConnPtr privconn = pool->conn->privateData; virStoragePoolObjPtr privpool; int ret = -1; 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; if (privpool->configFile == NULL) { virStoragePoolObjRemove(&privconn->pools, privpool); privpool = NULL; } ret = 0; cleanup: if (privpool) virStoragePoolObjUnlock(privpool); testDriverUnlock(privconn); return ret; } static int testStoragePoolDelete(virStoragePoolPtr pool, unsigned int flags) { testConnPtr 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) { testConnPtr 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 not active"), pool->name); goto cleanup; } ret = 0; cleanup: if (privpool) virStoragePoolObjUnlock(privpool); return ret; } static int testStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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); 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->allocation) > privpool->def->capacity) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Not enough free space in pool for volume '%s'"), privvol->name); goto cleanup; } if (VIR_REALLOC_N(privpool->volumes.objs, privpool->volumes.count+1) < 0) 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) goto cleanup; privpool->def->allocation += privvol->allocation; privpool->def->available = (privpool->def->capacity - privpool->def->allocation); privpool->volumes.objs[privpool->volumes.count++] = privvol; 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) { testConnPtr 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); 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->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 (VIR_REALLOC_N(privpool->volumes.objs, privpool->volumes.count+1) < 0) 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) goto cleanup; privpool->def->allocation += privvol->allocation; privpool->def->available = (privpool->def->capacity - privpool->def->allocation); privpool->volumes.objs[privpool->volumes.count++] = privvol; 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) { testConnPtr 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->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); if (i < (privpool->volumes.count - 1)) memmove(privpool->volumes.objs + i, privpool->volumes.objs + i + 1, sizeof(*(privpool->volumes.objs)) * (privpool->volumes.count - (i + 1))); if (VIR_REALLOC_N(privpool->volumes.objs, privpool->volumes.count - 1) < 0) { ; /* Failure to reduce memory allocation isn't fatal */ } 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) { testConnPtr 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->capacity; info->allocation = privvol->allocation; ret = 0; cleanup: if (privpool) virStoragePoolObjUnlock(privpool); return ret; } static char * testStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags) { testConnPtr 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) { testConnPtr 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 virDrvOpenStatus testNodeDeviceOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "Test")) return VIR_DRV_OPEN_DECLINED; conn->nodeDevicePrivateData = conn->privateData; return VIR_DRV_OPEN_SUCCESS; } static int testNodeDeviceClose(virConnectPtr conn) { conn->nodeDevicePrivateData = NULL; return 0; } static int testNodeNumOfDevices(virConnectPtr conn, const char *cap, unsigned int flags) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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, NULL); goto cleanup; } ret = virGetNodeDevice(conn, name); cleanup: if (obj) virNodeDeviceObjUnlock(obj); return ret; } static char * testNodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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) { testConnPtr 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->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) { testConnPtr driver = conn->privateData; virNodeDeviceDefPtr def = NULL; virNodeDeviceObjPtr obj = NULL; char *wwnn = NULL, *wwpn = NULL; int parent_host = -1; virNodeDevicePtr dev = NULL; virNodeDevCapsDefPtr caps; 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' value, since this would also come from * the backend */ caps = def->caps; while (caps) { if (caps->type != VIR_NODE_DEV_CAP_SCSI_HOST) continue; caps->data.scsi_host.host = virRandomBits(10); caps = caps->next; } if (!(obj = virNodeDeviceAssignDef(&driver->devs, def))) { goto cleanup; } virNodeDeviceObjUnlock(obj); dev = virGetNodeDevice(conn, def->name); def = NULL; cleanup: testDriverUnlock(driver); virNodeDeviceDefFree(def); VIR_FREE(wwnn); VIR_FREE(wwpn); return dev; } static int testNodeDeviceDestroy(virNodeDevicePtr dev) { int ret = 0; testConnPtr driver = dev->conn->privateData; virNodeDeviceObjPtr obj = NULL; char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL; int parent_host = -1; testDriverLock(driver); obj = virNodeDeviceFindByName(&driver->devs, dev->name); testDriverUnlock(driver); if (!obj) { virReportError(VIR_ERR_NO_NODE_DEVICE, NULL); 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; } virNodeDeviceObjLock(obj); virNodeDeviceObjRemove(&driver->devs, obj); out: if (obj) virNodeDeviceObjUnlock(obj); 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) { testConnPtr driver = conn->privateData; int ret = 0; testDriverLock(driver); if (virDomainEventStateRegister(conn, driver->eventState, callback, opaque, freecb) < 0) ret = -1; testDriverUnlock(driver); return ret; } static int testConnectDomainEventDeregister(virConnectPtr conn, virConnectDomainEventCallback callback) { testConnPtr driver = conn->privateData; int ret = 0; testDriverLock(driver); if (virDomainEventStateDeregister(conn, driver->eventState, callback) < 0) ret = -1; testDriverUnlock(driver); return ret; } static int testConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback callback, void *opaque, virFreeCallback freecb) { testConnPtr driver = conn->privateData; int ret; testDriverLock(driver); if (virDomainEventStateRegisterID(conn, driver->eventState, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; testDriverUnlock(driver); return ret; } static int testConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID) { testConnPtr driver = conn->privateData; int ret = 0; testDriverLock(driver); if (virObjectEventStateDeregisterID(conn, driver->eventState, callbackID) < 0) ret = -1; testDriverUnlock(driver); return ret; } static int testConnectNetworkEventRegisterAny(virConnectPtr conn, virNetworkPtr net, int eventID, virConnectNetworkEventGenericCallback callback, void *opaque, virFreeCallback freecb) { testConnPtr driver = conn->privateData; int ret; testDriverLock(driver); if (virNetworkEventStateRegisterID(conn, driver->eventState, net, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; testDriverUnlock(driver); return ret; } static int testConnectNetworkEventDeregisterAny(virConnectPtr conn, int callbackID) { testConnPtr driver = conn->privateData; int ret = 0; testDriverLock(driver); if (virObjectEventStateDeregisterID(conn, driver->eventState, callbackID) < 0) ret = -1; testDriverUnlock(driver); return ret; } /* driver must be locked before calling */ static void testObjectEventQueue(testConnPtr driver, virObjectEventPtr event) { virObjectEventStateQueue(driver->eventState, event); } static virDrvOpenStatus testSecretOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "Test")) return VIR_DRV_OPEN_DECLINED; conn->secretPrivateData = conn->privateData; return VIR_DRV_OPEN_SUCCESS; } static int testSecretClose(virConnectPtr conn) { conn->secretPrivateData = NULL; return 0; } static virDrvOpenStatus testNWFilterOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); if (STRNEQ(conn->driver->name, "Test")) return VIR_DRV_OPEN_DECLINED; conn->nwfilterPrivateData = conn->privateData; return VIR_DRV_OPEN_SUCCESS; } static int testNWFilterClose(virConnectPtr conn) { conn->nwfilterPrivateData = NULL; return 0; } static int testConnectListAllDomains(virConnectPtr conn, virDomainPtr **domains, unsigned int flags) { testConnPtr privconn = conn->privateData; int ret; virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); testDriverLock(privconn); ret = virDomainObjListExport(privconn->domains, conn, domains, NULL, flags); testDriverUnlock(privconn); return ret; } static int testNodeGetCPUMap(virConnectPtr conn, unsigned char **cpumap, unsigned int *online, unsigned int flags) { testConnPtr privconn = conn->privateData; int ret = -1; virCheckFlags(0, -1); testDriverLock(privconn); if (cpumap) { if (VIR_ALLOC_N(*cpumap, 1) < 0) goto cleanup; *cpumap[0] = 0x15; } if (online) *online = 3; ret = 8; cleanup: testDriverUnlock(privconn); return ret; } 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) { testConnPtr 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); testDriverLock(privconn); vm = virDomainObjListFindByName(privconn->domains, dom->name); testDriverUnlock(privconn); if (vm == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } 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: if (vm) virObjectUnlock(vm); if (event) { testDriverLock(privconn); testObjectEventQueue(privconn, event); testDriverUnlock(privconn); } return ret; } static int testDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags) { testConnPtr privconn = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; virCheckFlags(0, -1); testDriverLock(privconn); vm = virDomainObjListFindByName(privconn->domains, dom->name); if (vm == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } ret = vm->hasManagedSave; cleanup: if (vm) virObjectUnlock(vm); testDriverUnlock(privconn); return ret; } static int testDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags) { testConnPtr privconn = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; virCheckFlags(0, -1); testDriverLock(privconn); vm = virDomainObjListFindByName(privconn->domains, dom->name); if (vm == NULL) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } vm->hasManagedSave = false; ret = 0; cleanup: if (vm) virObjectUnlock(vm); testDriverUnlock(privconn); return ret; } /* * 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 = -1; virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS | VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1); if (!(vm = testDomObjFromDomain(domain))) goto cleanup; n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags); cleanup: if (vm) virObjectUnlock(vm); return n; } static int testDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen, unsigned int flags) { virDomainObjPtr vm = NULL; int n = -1; virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS | VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1); if (!(vm = testDomObjFromDomain(domain))) goto cleanup; n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen, flags); cleanup: if (vm) virObjectUnlock(vm); return n; } static int testDomainListAllSnapshots(virDomainPtr domain, virDomainSnapshotPtr **snaps, unsigned int flags) { virDomainObjPtr vm = NULL; int n = -1; virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS | VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1); if (!(vm = testDomObjFromDomain(domain))) goto cleanup; n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags); cleanup: if (vm) virObjectUnlock(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))) goto cleanup; if (!(snap = testSnapObjFromSnapshot(vm, snapshot))) goto cleanup; n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen, flags); cleanup: if (vm) virObjectUnlock(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))) goto cleanup; if (!(snap = testSnapObjFromSnapshot(vm, snapshot))) goto cleanup; n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags); cleanup: if (vm) virObjectUnlock(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))) goto cleanup; if (!(snap = testSnapObjFromSnapshot(vm, snapshot))) goto cleanup; n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps, flags); cleanup: if (vm) virObjectUnlock(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))) goto cleanup; if (!(snap = testSnapObjFromName(vm, name))) goto cleanup; snapshot = virGetDomainSnapshot(domain, snap->def->name); cleanup: if (vm) virObjectUnlock(vm); return snapshot; } static int testDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags) { virDomainObjPtr vm; int ret = -1; virCheckFlags(0, -1); if (!(vm = testDomObjFromDomain(domain))) goto cleanup; ret = (vm->current_snapshot != NULL); cleanup: if (vm) virObjectUnlock(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))) goto cleanup; 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: if (vm) virObjectUnlock(vm); return parent; } static virDomainSnapshotPtr testDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags) { virDomainObjPtr vm; virDomainSnapshotPtr snapshot = NULL; virCheckFlags(0, NULL); if (!(vm = testDomObjFromDomain(domain))) goto cleanup; 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: if (vm) virObjectUnlock(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]; virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL); if (!(vm = testDomObjFromSnapshot(snapshot))) goto cleanup; if (!(snap = testSnapObjFromSnapshot(vm, snapshot))) goto cleanup; virUUIDFormat(snapshot->domain->uuid, uuidstr); xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0); cleanup: if (vm) virObjectUnlock(vm); return xml; } static int testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainObjPtr vm = NULL; int ret = -1; virCheckFlags(0, -1); if (!(vm = testDomObjFromSnapshot(snapshot))) goto cleanup; ret = (vm->current_snapshot && STREQ(snapshot->name, vm->current_snapshot->def->name)); cleanup: if (vm) virObjectUnlock(vm); return ret; } static int testDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot, unsigned int flags) { virDomainObjPtr vm = NULL; int ret = -1; virCheckFlags(0, -1); if (!(vm = testDomObjFromSnapshot(snapshot))) goto cleanup; if (!testSnapObjFromSnapshot(vm, snapshot)) goto cleanup; ret = 1; cleanup: if (vm) virObjectUnlock(vm); return ret; } static int testDomainSnapshotAlignDisks(virDomainObjPtr vm, virDomainSnapshotDefPtr def, unsigned int flags) { int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL; int 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) { testConnPtr 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, 1 << VIR_DOMAIN_VIRT_TEST, 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; } virObjectUnlock(vm); } if (event) { testDriverLock(privconn); testObjectEventQueue(privconn, event); testDriverUnlock(privconn); } virDomainSnapshotDefFree(def); return snapshot; } typedef struct _testSnapRemoveData testSnapRemoveData; typedef testSnapRemoveData *testSnapRemoveDataPtr; struct _testSnapRemoveData { virDomainObjPtr vm; bool current; }; static void 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); } typedef struct _testSnapReparentData testSnapReparentData; typedef testSnapReparentData *testSnapReparentDataPtr; struct _testSnapReparentData { virDomainSnapshotObjPtr parent; virDomainObjPtr vm; int err; virDomainSnapshotObjPtr last; }; static void testDomainSnapshotReparentChildren(void *payload, const void *name ATTRIBUTE_UNUSED, void *data) { virDomainSnapshotObjPtr snap = payload; testSnapReparentDataPtr rep = data; if (rep->err < 0) { return; } 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; } if (!snap->sibling) rep->last = snap; } 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: if (vm) virObjectUnlock(vm); return ret; } static int testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags) { testConnPtr 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; testDriverLock(privconn); 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); if (event) 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; if (event) 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); if (event2) testObjectEventQueue(privconn, event2); } else { virObjectUnref(event2); } virObjectUnlock(vm); testDriverUnlock(privconn); return ret; } static virDriver testDriver = { .no = VIR_DRV_TEST, .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 */ .connectGetCapabilities = testConnectGetCapabilities, /* 0.2.1 */ .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 */ .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 */ .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 */ .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 = { "Test", .networkOpen = testNetworkOpen, /* 0.3.2 */ .networkClose = testNetworkClose, /* 0.3.2 */ .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 = { "Test", /* name */ .interfaceOpen = testInterfaceOpen, /* 0.7.0 */ .interfaceClose = testInterfaceClose, /* 0.7.0 */ .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 = { .name = "Test", .storageOpen = testStorageOpen, /* 0.4.1 */ .storageClose = testStorageClose, /* 0.4.1 */ .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 */ .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 = { .name = "Test", .nodeDeviceOpen = testNodeDeviceOpen, /* 0.6.0 */ .nodeDeviceClose = testNodeDeviceClose, /* 0.6.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 virSecretDriver testSecretDriver = { .name = "Test", .secretOpen = testSecretOpen, /* 0.7.1 */ .secretClose = testSecretClose, /* 0.7.1 */ }; static virNWFilterDriver testNWFilterDriver = { .name = "Test", .nwfilterOpen = testNWFilterOpen, /* 0.8.0 */ .nwfilterClose = testNWFilterClose, /* 0.8.0 */ }; /** * testRegister: * * Registers the test driver */ int testRegister(void) { if (virRegisterDriver(&testDriver) < 0) return -1; if (virRegisterNetworkDriver(&testNetworkDriver) < 0) return -1; if (virRegisterInterfaceDriver(&testInterfaceDriver) < 0) return -1; if (virRegisterStorageDriver(&testStorageDriver) < 0) return -1; if (virRegisterNodeDeviceDriver(&testNodeDeviceDriver) < 0) return -1; if (virRegisterSecretDriver(&testSecretDriver) < 0) return -1; if (virRegisterNWFilterDriver(&testNWFilterDriver) < 0) return -1; return 0; }