/* * test.c: A "mock" hypervisor for use by application unit tests * * Copyright (C) 2006-2008 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Daniel Berrange */ #include #ifdef WITH_TEST #include #include #include #include #include #include #include #include #include #include #include "socketcompat.h" #include "internal.h" #include "test.h" #include "xml.h" #include "buf.h" #include "uuid.h" /* Flags that determine the action to take on a shutdown or crash of a domain */ typedef enum { VIR_DOMAIN_DESTROY = 1, /* destroy the domain */ VIR_DOMAIN_RESTART = 2, /* restart the domain */ VIR_DOMAIN_PRESERVE= 3, /* keep as is, need manual destroy, for debug */ VIR_DOMAIN_RENAME_RESTART= 4/* restart under an new unique name */ } virDomainRestart; struct _testDev { char name[20]; int mode; }; typedef struct _testDev testDev; typedef struct _testDev *testDevPtr; #define MAX_DEVICES 10 struct _testDom { int active; int config; int id; char name[20]; unsigned char uuid[VIR_UUID_BUFLEN]; virDomainInfo info; unsigned int maxVCPUs; virDomainRestart onRestart; /* What to do at end of current shutdown procedure */ virDomainRestart onReboot; virDomainRestart onPoweroff; virDomainRestart onCrash; int numDevices; testDev devices[MAX_DEVICES]; int autostart; unsigned int weight; }; typedef struct _testDom testDom; typedef struct _testDom *testDomPtr; struct _testNet { int active; int config; int running; char name[20]; char bridge[20]; unsigned char uuid[VIR_UUID_BUFLEN]; int forward; char forwardDev[IF_NAMESIZE]; char ipAddress[INET_ADDRSTRLEN]; char ipNetmask[INET_ADDRSTRLEN]; char dhcpStart[INET_ADDRSTRLEN]; char dhcpEnd[INET_ADDRSTRLEN]; int autostart; }; typedef struct _testNet testNet; typedef struct _testNet *testNetPtr; #define MAX_DOMAINS 20 #define MAX_NETWORKS 20 struct _testConn { char path[PATH_MAX]; int nextDomID; virNodeInfo nodeInfo; int numDomains; testDom domains[MAX_DOMAINS]; int numNetworks; testNet networks[MAX_NETWORKS]; }; typedef struct _testConn testConn; typedef struct _testConn *testConnPtr; #define TEST_MODEL "i686" #define TEST_MODEL_WORDSIZE "32" static const virNodeInfo defaultNodeInfo = { TEST_MODEL, 1024*1024*3, /* 3 GB */ 16, 1400, 2, 2, 2, 2, }; #define GET_DOMAIN(dom, ret) \ int domidx; \ testConnPtr privconn; \ testDomPtr privdom; \ \ privconn = (testConnPtr)dom->conn->privateData; \ if ((domidx = getDomainIndex(dom)) < 0) { \ testError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG, \ __FUNCTION__); \ return (ret); \ } \ privdom = &privconn->domains[domidx]; #define GET_NETWORK(net, ret) \ int netidx; \ testConnPtr privconn; \ testNetPtr privnet; \ \ privconn = (testConnPtr)net->conn->privateData; \ if ((netidx = getNetworkIndex(net)) < 0) { \ testError((net)->conn, NULL, (net), VIR_ERR_INVALID_ARG, \ __FUNCTION__); \ return (ret); \ } \ privnet = &privconn->networks[netidx]; #define GET_CONNECTION(conn, ret) \ testConnPtr privconn; \ \ privconn = (testConnPtr)conn->privateData; static void testError(virConnectPtr con, virDomainPtr dom, virNetworkPtr net, virErrorNumber error, const char *info) { const char *errmsg; if (error == VIR_ERR_OK) return; errmsg = __virErrorMsg(error, info); __virRaiseError(con, dom, net, VIR_FROM_TEST, error, VIR_ERR_ERROR, errmsg, info, NULL, 0, 0, errmsg, info, 0); } static int testRestartStringToFlag(const char *str) { if (!strcmp(str, "restart")) { return VIR_DOMAIN_RESTART; } else if (!strcmp(str, "destroy")) { return VIR_DOMAIN_DESTROY; } else if (!strcmp(str, "preserve")) { return VIR_DOMAIN_PRESERVE; } else if (!strcmp(str, "rename-restart")) { return VIR_DOMAIN_RENAME_RESTART; } else { return (0); } } static const char *testRestartFlagToString(int flag) { switch (flag) { case VIR_DOMAIN_RESTART: return "restart"; case VIR_DOMAIN_DESTROY: return "destroy"; case VIR_DOMAIN_PRESERVE: return "preserve"; case VIR_DOMAIN_RENAME_RESTART: return "rename-restart"; } return (NULL); } static int testLoadDomain(virConnectPtr conn, int domid, xmlDocPtr xml) { xmlNodePtr root = NULL; xmlXPathContextPtr ctxt = NULL; char *name = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; struct timeval tv; unsigned long memory = 0; unsigned long maxMem = 0; int nrVirtCpu; char *str; int handle = -1, i, ret; long l; virDomainRestart onReboot = VIR_DOMAIN_RESTART; virDomainRestart onPoweroff = VIR_DOMAIN_DESTROY; virDomainRestart onCrash = VIR_DOMAIN_RENAME_RESTART; GET_CONNECTION(conn, -1); if (gettimeofday(&tv, NULL) < 0) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day")); return (-1); } root = xmlDocGetRootElement(xml); if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain")); goto error; } ctxt = xmlXPathNewContext(xml); if (ctxt == NULL) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("creating xpath context")); goto error; } name = virXPathString("string(/domain/name[1])", ctxt); if (name == NULL) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("domain name")); goto error; } str = virXPathString("string(/domain/uuid[1])", ctxt); if (str == NULL) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain uuid")); goto error; } if (virUUIDParse(str, uuid) < 0) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain uuid")); goto error; } free(str); ret = virXPathLong("string(/domain/memory[1])", ctxt, &l); if (ret != 0) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain memory")); goto error; } maxMem = l; ret = virXPathLong("string(/domain/currentMemory[1])", ctxt, &l); if (ret == -1) { memory = maxMem; } else if (ret == -2) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain current memory")); goto error; } else { memory = l; } ret = virXPathLong("string(/domain/vcpu[1])", ctxt, &l); if (ret == -1) { nrVirtCpu = 1; } else if (ret == -2) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain vcpus")); goto error; } else { nrVirtCpu = l; } str = virXPathString("string(/domain/on_reboot[1])", ctxt); if (str != NULL) { if (!(onReboot = testRestartStringToFlag(str))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain reboot behaviour")); free(str); goto error; } free(str); } str = virXPathString("string(/domain/on_poweroff[1])", ctxt); if (str != NULL) { if (!(onPoweroff = testRestartStringToFlag(str))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain poweroff behaviour")); free(str); goto error; } free(str); } str = virXPathString("string(/domain/on_crash[1])", ctxt); if (str != NULL) { if (!(onCrash = testRestartStringToFlag(str))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain crash behaviour")); free(str); goto error; } free(str); } for (i = 0 ; i < MAX_DOMAINS ; i++) { if (!privconn->domains[i].active) { handle = i; break; } } if (handle < 0) return (-1); privconn->domains[handle].active = 1; privconn->domains[handle].id = domid; strncpy(privconn->domains[handle].name, name, sizeof(privconn->domains[handle].name)-1); privconn->domains[handle].name[sizeof(privconn->domains[handle].name)-1] = '\0'; free(name); name = NULL; if (memory > maxMem) memory = maxMem; memmove(privconn->domains[handle].uuid, uuid, VIR_UUID_BUFLEN); privconn->domains[handle].info.maxMem = maxMem; privconn->domains[handle].info.memory = memory; privconn->domains[handle].info.state = domid < 0 ? VIR_DOMAIN_SHUTOFF : VIR_DOMAIN_RUNNING; privconn->domains[handle].info.nrVirtCpu = nrVirtCpu; privconn->domains[handle].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); privconn->domains[handle].maxVCPUs = nrVirtCpu; privconn->domains[handle].onReboot = onReboot; privconn->domains[handle].onPoweroff = onPoweroff; privconn->domains[handle].onCrash = onCrash; xmlXPathFreeContext(ctxt); return (handle); error: xmlXPathFreeContext(ctxt); free(name); return (-1); } static int testLoadDomainFromDoc(virConnectPtr conn, int domid, const char *doc) { int ret; xmlDocPtr xml; if (!(xml = xmlReadDoc(BAD_CAST doc, "domain.xml", NULL, XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain")); return (-1); } ret = testLoadDomain(conn, domid, xml); xmlFreeDoc(xml); return (ret); } static int testLoadDomainFromFile(virConnectPtr conn, int domid, const char *filename) { int ret, fd; xmlDocPtr xml; if ((fd = open(filename, O_RDONLY)) < 0) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("load domain definition file")); return (-1); } if (!(xml = xmlReadFd(fd, filename, NULL, XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain")); return (-1); } ret = testLoadDomain(conn, domid, xml); xmlFreeDoc(xml); close(fd); return (ret); } static int testLoadNetwork(virConnectPtr conn, xmlDocPtr xml) { xmlNodePtr root = NULL; xmlXPathContextPtr ctxt = NULL; char *name = NULL, *bridge = NULL; unsigned char uuid[VIR_UUID_BUFLEN]; char *str; char *ipaddress = NULL, *ipnetmask = NULL, *dhcpstart = NULL, *dhcpend = NULL; int forward; char *forwardDev = NULL; int handle = -1, i; GET_CONNECTION(conn, -1); root = xmlDocGetRootElement(xml); if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "network"))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("network")); goto error; } ctxt = xmlXPathNewContext(xml); if (ctxt == NULL) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("creating xpath context")); goto error; } name = virXPathString("string(/network/name[1])", ctxt); if (name == NULL) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("network name")); goto error; } bridge = virXPathString("string(/network/bridge[1]/@name)", ctxt); str = virXPathString("string(/network/uuid[1])", ctxt); if (str == NULL) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("network uuid")); goto error; } if (virUUIDParse(str, uuid) < 0) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("network uuid")); goto error; } free(str); forward = virXPathBoolean("count(/network/forward) != 0", ctxt); if (forward < 0) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("network forward")); goto error; } forwardDev = virXPathString("string(/network/forward/@dev)", ctxt); ipaddress = virXPathString("string(/network/ip/@address)", ctxt); if (ipaddress == NULL) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("ip address")); goto error; } ipnetmask = virXPathString("string(/network/ip/@netmask)", ctxt); if (ipnetmask == NULL) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("ip netmask")); goto error; } dhcpstart = virXPathString("string(/network/ip/dhcp/range[1]/@start)", ctxt); if (dhcpstart == NULL) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("ip address")); goto error; } dhcpend = virXPathString("string(/network/ip/dhcp/range[1]/@end)", ctxt); if (dhcpend == NULL) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("ip address")); goto error; } for (i = 0 ; i < MAX_NETWORKS ; i++) { if (!privconn->networks[i].active) { handle = i; break; } } if (handle < 0) return (-1); privconn->networks[handle].active = 1; privconn->networks[handle].running = 1; strncpy(privconn->networks[handle].name, name, sizeof(privconn->networks[handle].name)-1); privconn->networks[handle].name[sizeof(privconn->networks[handle].name)-1] = '\0'; strncpy(privconn->networks[handle].bridge, bridge ? bridge : name, sizeof(privconn->networks[handle].bridge)-1); privconn->networks[handle].bridge[sizeof(privconn->networks[handle].bridge)-1] = '\0'; free(name); name = NULL; if (bridge) { free(bridge); bridge = NULL; } memmove(privconn->networks[handle].uuid, uuid, VIR_UUID_BUFLEN); privconn->networks[handle].forward = forward; if (forwardDev) { strncpy(privconn->networks[handle].forwardDev, forwardDev, sizeof(privconn->networks[handle].forwardDev)-1); privconn->networks[handle].forwardDev[sizeof(privconn->networks[handle].forwardDev)-1] = '\0'; free(forwardDev); } strncpy(privconn->networks[handle].ipAddress, ipaddress, sizeof(privconn->networks[handle].ipAddress)-1); privconn->networks[handle].ipAddress[sizeof(privconn->networks[handle].ipAddress)-1] = '\0'; free(ipaddress); strncpy(privconn->networks[handle].ipNetmask, ipnetmask, sizeof(privconn->networks[handle].ipNetmask)-1); privconn->networks[handle].ipNetmask[sizeof(privconn->networks[handle].ipNetmask)-1] = '\0'; free(ipnetmask); strncpy(privconn->networks[handle].dhcpStart, dhcpstart, sizeof(privconn->networks[handle].dhcpStart)-1); privconn->networks[handle].dhcpStart[sizeof(privconn->networks[handle].dhcpStart)-1] = '\0'; free(dhcpstart); strncpy(privconn->networks[handle].dhcpEnd, dhcpend, sizeof(privconn->networks[handle].dhcpEnd)-1); privconn->networks[handle].dhcpEnd[sizeof(privconn->networks[handle].dhcpEnd)-1] = '\0'; free(dhcpend); xmlXPathFreeContext(ctxt); return (handle); error: xmlXPathFreeContext(ctxt); free (forwardDev); free(ipaddress); free(ipnetmask); free(dhcpstart); free(dhcpend); free(name); return (-1); } static int testLoadNetworkFromDoc(virConnectPtr conn, const char *doc) { int ret; xmlDocPtr xml; if (!(xml = xmlReadDoc(BAD_CAST doc, "network.xml", NULL, XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("network")); return (-1); } ret = testLoadNetwork(conn, xml); xmlFreeDoc(xml); return (ret); } static int testLoadNetworkFromFile(virConnectPtr conn, const char *filename) { int ret, fd; xmlDocPtr xml; if ((fd = open(filename, O_RDONLY)) < 0) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("load network definition file")); return (-1); } if (!(xml = xmlReadFd(fd, filename, NULL, XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("network")); return (-1); } ret = testLoadNetwork(conn, xml); xmlFreeDoc(xml); close(fd); return (ret); } static int testOpenDefault(virConnectPtr conn) { int u; struct timeval tv; testConnPtr privconn = malloc(sizeof(*privconn)); if (!privconn) { testError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "testConn"); return VIR_DRV_OPEN_ERROR; } memset(privconn, 0, sizeof(testConn)); if (gettimeofday(&tv, NULL) < 0) { testError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day")); return VIR_DRV_OPEN_ERROR; } memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo)); strcpy(privconn->path, "/default"); privconn->nextDomID = 1; privconn->numDomains = 1; privconn->domains[0].active = 1; privconn->domains[0].config = 1; privconn->domains[0].id = privconn->nextDomID++; privconn->domains[0].onReboot = VIR_DOMAIN_RESTART; privconn->domains[0].onCrash = VIR_DOMAIN_RESTART; privconn->domains[0].onPoweroff = VIR_DOMAIN_DESTROY; strcpy(privconn->domains[0].name, "test"); for (u = 0 ; u < VIR_UUID_BUFLEN ; u++) { privconn->domains[0].uuid[u] = (u * 75)%255; } privconn->domains[0].info.maxMem = 8192 * 1024; privconn->domains[0].info.memory = 2048 * 1024; privconn->domains[0].info.state = VIR_DOMAIN_RUNNING; privconn->domains[0].info.nrVirtCpu = 2; privconn->domains[0].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); privconn->numNetworks = 1; privconn->networks[0].active = 1; privconn->networks[0].config = 1; privconn->networks[0].running = 1; strcpy(privconn->networks[0].name, "default"); strcpy(privconn->networks[0].bridge, "default"); for (u = 0 ; u < VIR_UUID_BUFLEN ; u++) { privconn->networks[0].uuid[u] = (u * 75)%255; } privconn->networks[0].forward = 1; strcpy(privconn->networks[0].forwardDev, "eth0"); strcpy(privconn->networks[0].ipAddress, "192.168.122.1"); strcpy(privconn->networks[0].ipNetmask, "255.255.255.0"); strcpy(privconn->networks[0].dhcpStart, "192.168.122.128"); strcpy(privconn->networks[0].dhcpEnd, "192.168.122.253"); conn->privateData = privconn; return (VIR_DRV_OPEN_SUCCESS); } static char *testBuildFilename(const char *relativeTo, const char *filename) { char *offset; int baseLen; if (!filename || filename[0] == '\0') return (NULL); if (filename[0] == '/') return strdup(filename); offset = strrchr(relativeTo, '/'); if ((baseLen = (offset-relativeTo+1))) { char *absFile = malloc(baseLen + strlen(filename) + 1); strncpy(absFile, relativeTo, baseLen); absFile[baseLen] = '\0'; strcat(absFile, filename); return absFile; } else { return strdup(filename); } } static int testOpenFromFile(virConnectPtr conn, const char *file) { int fd = -1, i, ret; long l; char *str; xmlDocPtr xml = NULL; xmlNodePtr root = NULL; xmlNodePtr *domains, *networks = NULL; xmlXPathContextPtr ctxt = NULL; virNodeInfoPtr nodeInfo; testConnPtr privconn = malloc(sizeof(*privconn)); if (!privconn) { testError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY, "testConn"); return VIR_DRV_OPEN_ERROR; } if ((fd = open(file, O_RDONLY)) < 0) { testError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("loading host definition file")); goto error; } if (!(xml = xmlReadFd(fd, file, NULL, XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { testError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("host")); goto error; } close(fd); fd = -1; root = xmlDocGetRootElement(xml); if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "node"))) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node")); goto error; } ctxt = xmlXPathNewContext(xml); if (ctxt == NULL) { testError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("creating xpath context")); goto error; } conn->privateData = privconn; privconn->nextDomID = 1; privconn->numDomains = 0; privconn->numNetworks = 0; strncpy(privconn->path, file, PATH_MAX-1); privconn->path[PATH_MAX-1] = '\0'; memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo)); nodeInfo = &privconn->nodeInfo; ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l); if (ret == 0) { nodeInfo->nodes = l; } else if (ret == -2) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu numa nodes")); goto error; } ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l); if (ret == 0) { nodeInfo->sockets = l; } else if (ret == -2) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu sockets")); goto error; } ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l); if (ret == 0) { nodeInfo->cores = l; } else if (ret == -2) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu cores")); goto error; } ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l); if (ret == 0) { nodeInfo->threads = l; } else if (ret == -2) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu threads")); 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) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node active cpu")); goto error; } ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l); if (ret == 0) { nodeInfo->mhz = l; } else if (ret == -2) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu mhz")); goto error; } str = virXPathString("string(/node/cpu/model[1])", ctxt); if (str != NULL) { strncpy(nodeInfo->model, str, sizeof(nodeInfo->model)-1); nodeInfo->model[sizeof(nodeInfo->model)-1] = '\0'; free(str); } ret = virXPathLong("string(/node/memory[1])", ctxt, &l); if (ret == 0) { nodeInfo->memory = l; } else if (ret == -2) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node memory")); goto error; } ret = virXPathNodeSet("/node/domain", ctxt, &domains); if (ret < 0) { testError(NULL, NULL, NULL, VIR_ERR_XML_ERROR, _("node domain list")); goto error; } for (i = 0 ; i < ret ; i++) { xmlChar *domFile = xmlGetProp(domains[i], BAD_CAST "file"); char *absFile = testBuildFilename(file, (const char *)domFile); int domid = privconn->nextDomID++, handle; free(domFile); if (!absFile) { testError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("resolving domain filename")); goto error; } if ((handle = testLoadDomainFromFile(conn, domid, absFile)) < 0) { free(absFile); goto error; } privconn->domains[handle].config = 1; free(absFile); privconn->numDomains++; } if (domains != NULL) { free(domains); domains = NULL; } ret = virXPathNodeSet("/node/network", ctxt, &networks); if (ret > 0) { for (i = 0 ; i < ret ; i++) { xmlChar *netFile = xmlGetProp(networks[i], BAD_CAST "file"); char *absFile = testBuildFilename(file, (const char *)netFile); int handle; free(netFile); if (!absFile) { testError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("resolving network filename")); goto error; } if ((handle = testLoadNetworkFromFile(conn, absFile)) < 0) { free(absFile); goto error; } privconn->networks[handle].config = 1; free(absFile); privconn->numNetworks++; } if (networks != NULL) { free(networks); networks = NULL; } } xmlXPathFreeContext(ctxt); xmlFreeDoc(xml); return (0); error: xmlXPathFreeContext(ctxt); free(domains); free(networks); if (xml) xmlFreeDoc(xml); if (fd != -1) close(fd); free(privconn); conn->privateData = NULL; return VIR_DRV_OPEN_ERROR; } static int getDomainIndex(virDomainPtr domain) { int i; GET_CONNECTION(domain->conn, -1); for (i = 0 ; i < MAX_DOMAINS ; i++) { if (domain->id >= 0) { if (domain->id == privconn->domains[i].id) return (i); } else { if (STREQ(domain->name, privconn->domains[i].name)) return (i); } } return (-1); } static int getNetworkIndex(virNetworkPtr network) { int i; GET_CONNECTION(network->conn, -1); for (i = 0 ; i < MAX_NETWORKS ; i++) { if (STREQ(network->name, privconn->networks[i].name)) return (i); } return (-1); } static int testOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { int ret; if (!uri) return VIR_DRV_OPEN_DECLINED; if (!uri->scheme || strcmp(uri->scheme, "test") != 0) return VIR_DRV_OPEN_DECLINED; /* Remote driver should handle these. */ if (uri->server) return VIR_DRV_OPEN_DECLINED; if (uri->server) return VIR_DRV_OPEN_DECLINED; /* From this point on, the connection is for us. */ if (!uri->path || uri->path[0] == '\0' || (uri->path[0] == '/' && uri->path[1] == '\0')) { testError (NULL, NULL, NULL, VIR_ERR_INVALID_ARG, _("testOpen: supply a path or use test:///default")); return VIR_DRV_OPEN_ERROR; } if (STREQ(uri->path, "/default")) ret = testOpenDefault(conn); else ret = testOpenFromFile(conn, uri->path); return (ret); } static int testClose(virConnectPtr conn) { GET_CONNECTION(conn, -1); free (privconn); conn->privateData = conn; return 0; } static int testGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) { *hvVer = 2; return (0); } static char *testGetHostname (virConnectPtr conn) { int r; char hostname [HOST_NAME_MAX+1], *str; r = gethostname (hostname, HOST_NAME_MAX+1); if (r == -1) { testError (conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, strerror (errno)); return NULL; } str = strdup (hostname); if (str == NULL) { testError (conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, strerror (errno)); return NULL; } return str; } static char * testGetURI (virConnectPtr conn) { char *uri; GET_CONNECTION(conn, NULL); if (asprintf (&uri, "test://%s", privconn->path) == -1) { testError (conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, strerror (errno)); return NULL; } return uri; } static int testGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) { return 32; } static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) { GET_CONNECTION(conn, -1); memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo)); return (0); } static char *testGetCapabilities (virConnectPtr conn) { static char caps[] = "\ \n\ \n\ \n\ " TEST_MODEL "\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ linux\n\ \n\ " TEST_MODEL_WORDSIZE "\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ "; char *caps_copy = strdup (caps); if (!caps_copy) { testError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__); return NULL; } return caps_copy; } static int testNumOfDomains(virConnectPtr conn) { int numActive = 0, i; GET_CONNECTION(conn, -1); for (i = 0 ; i < MAX_DOMAINS ; i++) { if (!privconn->domains[i].active || privconn->domains[i].info.state == VIR_DOMAIN_SHUTOFF) continue; numActive++; } return (numActive); } static virDomainPtr testDomainCreateLinux(virConnectPtr conn, const char *xmlDesc, unsigned int flags ATTRIBUTE_UNUSED) { int domid, handle = -1; virDomainPtr dom; GET_CONNECTION(conn, NULL); if (xmlDesc == NULL) { testError(conn, NULL, NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return (NULL); } if (privconn->numDomains == MAX_DOMAINS) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("too many domains")); return (NULL); } domid = privconn->nextDomID++; if ((handle = testLoadDomainFromDoc(conn, domid, xmlDesc)) < 0) return (NULL); privconn->domains[handle].config = 0; dom = virGetDomain(conn, privconn->domains[handle].name, privconn->domains[handle].uuid); if (dom == NULL) return NULL; privconn->numDomains++; return (dom); } static virDomainPtr testLookupDomainByID(virConnectPtr conn, int id) { virDomainPtr dom; int i, idx = -1; GET_CONNECTION(conn, NULL); for (i = 0 ; i < MAX_DOMAINS ; i++) { if (privconn->domains[i].active && privconn->domains[i].id == id) { idx = i; break; } } if (idx < 0) { testError (conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL); return(NULL); } dom = virGetDomain(conn, privconn->domains[idx].name, privconn->domains[idx].uuid); if (dom == NULL) return NULL; dom->id = id; return (dom); } static virDomainPtr testLookupDomainByUUID(virConnectPtr conn, const unsigned char *uuid) { virDomainPtr dom; int i, idx = -1; GET_CONNECTION(conn, NULL); for (i = 0 ; i < MAX_DOMAINS ; i++) { if (privconn->domains[i].active && memcmp(uuid, privconn->domains[i].uuid, VIR_UUID_BUFLEN) == 0) { idx = i; break; } } if (idx < 0) { testError (conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL); return NULL; } dom = virGetDomain(conn, privconn->domains[idx].name, privconn->domains[idx].uuid); if (dom == NULL) return NULL; dom->id = privconn->domains[idx].id; return dom; } static virDomainPtr testLookupDomainByName(virConnectPtr conn, const char *name) { virDomainPtr dom; int i, idx = -1; GET_CONNECTION(conn, NULL); for (i = 0 ; i < MAX_DOMAINS ; i++) { if (privconn->domains[i].active && strcmp(name, privconn->domains[i].name) == 0) { idx = i; break; } } if (idx < 0) { testError (conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL); return NULL; } dom = virGetDomain(conn, privconn->domains[idx].name, privconn->domains[idx].uuid); if (dom == NULL) return NULL; dom->id = privconn->domains[idx].id; return dom; } static int testListDomains (virConnectPtr conn, int *ids, int maxids) { int n, i; GET_CONNECTION(conn, -1); for (i = 0, n = 0 ; i < MAX_DOMAINS && n < maxids ; i++) { if (privconn->domains[i].active && privconn->domains[i].info.state != VIR_DOMAIN_SHUTOFF) { ids[n++] = privconn->domains[i].id; } } return (n); } static int testDestroyDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); if (privdom->config) { privdom->info.state = VIR_DOMAIN_SHUTOFF; privdom->id = -1; domain->id = -1; } else { privdom->active = 0; } return (0); } static int testResumeDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); if (privdom->info.state != VIR_DOMAIN_PAUSED) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "domain not paused"); return -1; } privdom->info.state = VIR_DOMAIN_RUNNING; return (0); } static int testPauseDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); if (privdom->info.state == VIR_DOMAIN_SHUTOFF || privdom->info.state == VIR_DOMAIN_PAUSED) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "domain not running"); return -1; } privdom->info.state = VIR_DOMAIN_PAUSED; return (0); } static int testShutdownDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); if (privdom->info.state == VIR_DOMAIN_SHUTOFF) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "domain not running"); return -1; } privdom->info.state = VIR_DOMAIN_SHUTOFF; domain->id = -1; privdom->id = -1; return (0); } /* Similar behaviour as shutdown */ static int testRebootDomain (virDomainPtr domain, virDomainRestart action) { GET_DOMAIN(domain, -1); if (!action) action = VIR_DOMAIN_RESTART; privdom->info.state = VIR_DOMAIN_SHUTDOWN; switch (action) { case VIR_DOMAIN_DESTROY: privdom->info.state = VIR_DOMAIN_SHUTOFF; domain->id = -1; privdom->id = -1; break; case VIR_DOMAIN_RESTART: privdom->info.state = VIR_DOMAIN_RUNNING; break; case VIR_DOMAIN_PRESERVE: privdom->info.state = VIR_DOMAIN_SHUTOFF; domain->id = -1; privdom->id = -1; break; case VIR_DOMAIN_RENAME_RESTART: privdom->info.state = VIR_DOMAIN_RUNNING; break; default: privdom->info.state = VIR_DOMAIN_SHUTOFF; domain->id = -1; privdom->id = -1; break; } return (0); } static int testGetDomainInfo (virDomainPtr domain, virDomainInfoPtr info) { struct timeval tv; GET_DOMAIN(domain, -1); if (gettimeofday(&tv, NULL) < 0) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day")); return (-1); } if (privdom->info.state == VIR_DOMAIN_SHUTOFF) { privdom->info.cpuTime = 0; privdom->info.memory = 0; } else { privdom->info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); } memcpy(info, &privdom->info, sizeof(virDomainInfo)); return (0); } static char *testDomainDumpXML(virDomainPtr domain, int flags); #define TEST_SAVE_MAGIC "TestGuestMagic" static int testDomainSave(virDomainPtr domain, const char *path) { char *xml; int fd, len; GET_DOMAIN(domain, -1); xml = testDomainDumpXML(domain, 0); if (xml == NULL) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot allocate space for metadata"); return (-1); } if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot save domain"); return (-1); } len = strlen(xml); if (write(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) != sizeof(TEST_SAVE_MAGIC)) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot write header"); close(fd); return (-1); } if (write(fd, (char*)&len, sizeof(len)) != sizeof(len)) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot write metadata length"); close(fd); return (-1); } if (write(fd, xml, len) != len) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot write metadata"); free(xml); close(fd); return (-1); } free(xml); if (close(fd) < 0) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot save domain data"); close(fd); return (-1); } if (privdom->config) { privdom->info.state = VIR_DOMAIN_SHUTOFF; privdom->id = -1; domain->id = -1; } else { privdom->active = 0; } return 0; } static int testDomainRestore(virConnectPtr conn, const char *path) { char *xml; char magic[15]; int fd, len, ret, domid; GET_CONNECTION(conn, -1); if ((fd = open(path, O_RDONLY)) < 0) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot read domain image"); return (-1); } if (read(fd, magic, sizeof(magic)) != sizeof(magic)) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "incomplete save header"); close(fd); return (-1); } if (memcmp(magic, TEST_SAVE_MAGIC, sizeof(magic))) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "mismatched header magic"); close(fd); return (-1); } if (read(fd, (char*)&len, sizeof(len)) != sizeof(len)) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "failed to read metadata length"); close(fd); return (-1); } if (len < 1 || len > 8192) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "length of metadata out of range"); close(fd); return (-1); } xml = malloc(len+1); if (!xml) { testError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "xml"); close(fd); return (-1); } if (read(fd, xml, len) != len) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "incomplete metdata"); close(fd); return (-1); } xml[len] = '\0'; close(fd); domid = privconn->nextDomID++; ret = testLoadDomainFromDoc(conn, domid, xml); free(xml); return ret < 0 ? -1 : 0; } static int testDomainCoreDump(virDomainPtr domain, const char *to, int flags ATTRIBUTE_UNUSED) { int fd; GET_DOMAIN(domain, -1); if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot save domain core"); return (-1); } if (write(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) != sizeof(TEST_SAVE_MAGIC)) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot write header"); close(fd); return (-1); } if (close(fd) < 0) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "cannot save domain data"); close(fd); return (-1); } if (privdom->config) { privdom->info.state = VIR_DOMAIN_SHUTOFF; privdom->id = -1; domain->id = -1; } else { privdom->active = 0; } return 0; } static char *testGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) { return strdup("linux"); } static unsigned long testGetMaxMemory(virDomainPtr domain) { GET_DOMAIN(domain, -1); return privdom->info.maxMem; } static int testSetMaxMemory(virDomainPtr domain, unsigned long memory) { GET_DOMAIN(domain, -1); /* XXX validate not over host memory wrt to other domains */ privdom->info.maxMem = memory; return (0); } static int testSetMemory(virDomainPtr domain, unsigned long memory) { GET_DOMAIN(domain, -1); if (memory > privdom->info.maxMem) { testError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return (-1); } privdom->info.memory = memory; return (0); } static int testSetVcpus(virDomainPtr domain, unsigned int nrCpus) { GET_DOMAIN(domain, -1); /* We allow more cpus in guest than host */ if (nrCpus > 32) { testError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return (-1); } privdom->info.nrVirtCpu = nrCpus; return (0); } static char *testDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED) { virBufferPtr buf; char *xml; unsigned char *uuid; char uuidstr[VIR_UUID_STRING_BUFLEN]; GET_DOMAIN(domain, NULL); if (!(buf = virBufferNew(4000))) { testError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__); return (NULL); } virBufferVSprintf(buf, "\n", domain->id); virBufferVSprintf(buf, " %s\n", domain->name); uuid = domain->uuid; virUUIDFormat(uuid, uuidstr); virBufferVSprintf(buf, " %s\n", uuidstr); virBufferVSprintf(buf, " %lu\n", privdom->info.maxMem); virBufferVSprintf(buf, " %d\n", privdom->info.nrVirtCpu); virBufferVSprintf(buf, " %s\n", testRestartFlagToString(privdom->onReboot)); virBufferVSprintf(buf, " %s\n", testRestartFlagToString(privdom->onPoweroff)); virBufferVSprintf(buf, " %s\n", testRestartFlagToString(privdom->onCrash)); virBufferAdd(buf, "\n", -1); xml = buf->content; free(buf); return (xml); } static int testNumOfDefinedDomains(virConnectPtr conn) { int numInactive = 0, i; GET_CONNECTION(conn, -1); for (i = 0 ; i < MAX_DOMAINS ; i++) { if (!privconn->domains[i].active || privconn->domains[i].info.state != VIR_DOMAIN_SHUTOFF) continue; numInactive++; } return (numInactive); } static int testListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) { int n = 0, i; GET_CONNECTION(conn, -1); for (i = 0, n = 0 ; i < MAX_DOMAINS && n < maxnames ; i++) { if (privconn->domains[i].active && privconn->domains[i].info.state == VIR_DOMAIN_SHUTOFF) { names[n++] = strdup(privconn->domains[i].name); } } return (n); } static virDomainPtr testDomainDefineXML(virConnectPtr conn, const char *doc) { int handle; xmlDocPtr xml; GET_CONNECTION(conn, NULL); if (!(xml = xmlReadDoc(BAD_CAST doc, "domain.xml", NULL, XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { testError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain")); return (NULL); } handle = testLoadDomain(conn, -1, xml); privconn->domains[handle].config = 1; xmlFreeDoc(xml); if (handle < 0) return (NULL); return virGetDomain(conn, privconn->domains[handle].name, privconn->domains[handle].uuid); } static int testDomainCreate(virDomainPtr domain) { GET_DOMAIN(domain, -1); if (privdom->info.state != VIR_DOMAIN_SHUTOFF) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, _("Domain is already running")); return (-1); } domain->id = privdom->id = privconn->nextDomID++; privdom->info.state = VIR_DOMAIN_RUNNING; return (0); } static int testDomainUndefine(virDomainPtr domain) { GET_DOMAIN(domain, -1); if (privdom->info.state != VIR_DOMAIN_SHUTOFF) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, _("Domain is still running")); return (-1); } privdom->active = 0; return (0); } static int testDomainGetAutostart(virDomainPtr domain, int *autostart) { GET_DOMAIN(domain, -1); *autostart = privdom->autostart; return (0); } static int testDomainSetAutostart(virDomainPtr domain, int autostart) { GET_DOMAIN(domain, -1); privdom->autostart = autostart ? 1 : 0; return (0); } static char *testDomainGetSchedulerType(virDomainPtr domain, int *nparams) { char *type; *nparams = 1; type = strdup("fair"); if (!type) { testError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, "schedular"); return (NULL); } return type; } static int testDomainGetSchedulerParams(virDomainPtr domain, virSchedParameterPtr params, int *nparams) { GET_DOMAIN(domain, -1); if (*nparams != 1) { testError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "nparams"); return (-1); } strcpy(params[0].field, "weight"); params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT; params[0].value.ui = privdom->weight; return 0; } static int testDomainSetSchedulerParams(virDomainPtr domain, virSchedParameterPtr params, int nparams) { GET_DOMAIN(domain, -1); if (nparams != 1) { testError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "nparams"); return (-1); } if (STRNEQ(params[0].field, "weight")) { testError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "field"); return (-1); } if (params[0].type != VIR_DOMAIN_SCHED_FIELD_UINT) { testError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "type"); return (-1); } privdom->weight = params[0].value.ui; return 0; } static virDrvOpenStatus testOpenNetwork(virConnectPtr conn, xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { if (STRNEQ(conn->driver->name, "Test")) return VIR_DRV_OPEN_DECLINED; conn->networkPrivateData = conn->privateData; return VIR_DRV_OPEN_SUCCESS; } static int testCloseNetwork(virConnectPtr conn) { conn->networkPrivateData = NULL; return 0; } static virNetworkPtr testLookupNetworkByUUID(virConnectPtr conn, const unsigned char *uuid) { int i, idx = -1; GET_CONNECTION(conn, NULL); for (i = 0 ; i < MAX_NETWORKS ; i++) { if (privconn->networks[i].active && memcmp(uuid, privconn->networks[i].uuid, VIR_UUID_BUFLEN) == 0) { idx = i; break; } } if (idx < 0) { testError (conn, NULL, NULL, VIR_ERR_NO_NETWORK, NULL); return NULL; } return virGetNetwork(conn, privconn->networks[idx].name, privconn->networks[idx].uuid); } static virNetworkPtr testLookupNetworkByName(virConnectPtr conn, const char *name) { int i, idx = -1; GET_CONNECTION(conn, NULL); for (i = 0 ; i < MAX_NETWORKS ; i++) { if (privconn->networks[i].active && strcmp(name, privconn->networks[i].name) == 0) { idx = i; break; } } if (idx < 0) { testError (conn, NULL, NULL, VIR_ERR_NO_NETWORK, NULL); return NULL; } return virGetNetwork(conn, privconn->networks[idx].name, privconn->networks[idx].uuid); } static int testNumNetworks(virConnectPtr conn) { int numInactive = 0, i; GET_CONNECTION(conn, -1); for (i = 0 ; i < MAX_NETWORKS ; i++) { if (!privconn->networks[i].active || !privconn->networks[i].running) continue; numInactive++; } return (numInactive); } static int testListNetworks(virConnectPtr conn, char **const names, int nnames) { int n = 0, i; GET_CONNECTION(conn, -1); for (i = 0, n = 0 ; i < MAX_NETWORKS && n < nnames ; i++) { if (privconn->networks[i].active && privconn->networks[i].running) { names[n++] = strdup(privconn->networks[i].name); } } return (n); } static int testNumDefinedNetworks(virConnectPtr conn) { int numInactive = 0, i; GET_CONNECTION(conn, -1); for (i = 0 ; i < MAX_NETWORKS ; i++) { if (!privconn->networks[i].active || privconn->networks[i].running) continue; numInactive++; } return (numInactive); } static int testListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) { int n = 0, i; GET_CONNECTION(conn, -1); for (i = 0, n = 0 ; i < MAX_NETWORKS && n < nnames ; i++) { if (privconn->networks[i].active && !privconn->networks[i].running) { names[n++] = strdup(privconn->networks[i].name); } } return (n); } static virNetworkPtr testNetworkCreate(virConnectPtr conn, const char *xml) { int handle = -1; virNetworkPtr net; GET_CONNECTION(conn, NULL); if (xml == NULL) { testError(conn, NULL, NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return (NULL); } if (privconn->numNetworks == MAX_NETWORKS) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("too many networks")); return (NULL); } if ((handle = testLoadNetworkFromDoc(conn, xml)) < 0) return (NULL); privconn->networks[handle].config = 0; net = virGetNetwork(conn, privconn->networks[handle].name, privconn->networks[handle].uuid); if (net == NULL) return NULL; privconn->numNetworks++; return (net); } static virNetworkPtr testNetworkDefine(virConnectPtr conn, const char *xml) { int handle = -1; virNetworkPtr net; GET_CONNECTION(conn, NULL); if (xml == NULL) { testError(conn, NULL, NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return (NULL); } if (privconn->numNetworks == MAX_NETWORKS) { testError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("too many networks")); return (NULL); } if ((handle = testLoadNetworkFromDoc(conn, xml)) < 0) return (NULL); net = virGetNetwork(conn, privconn->networks[handle].name, privconn->networks[handle].uuid); privconn->networks[handle].config = 1; if (net == NULL) return NULL; privconn->numNetworks++; return (net); } static int testNetworkUndefine(virNetworkPtr network) { GET_NETWORK(network, -1); if (privnet->running) { testError(network->conn, NULL, network, VIR_ERR_INTERNAL_ERROR, _("Network is still running")); return (-1); } privnet->active = 0; return (0); } static int testNetworkStart(virNetworkPtr network) { GET_NETWORK(network, -1); if (privnet->running) { testError(network->conn, NULL, network, VIR_ERR_INTERNAL_ERROR, _("Network is already running")); return (-1); } privnet->running = 1; return (0); } static int testNetworkDestroy(virNetworkPtr network) { GET_NETWORK(network, -1); if (privnet->config) { privnet->running = 0; } else { privnet->active = 0; } return (0); } static char *testNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSED) { virBufferPtr buf; char *xml; unsigned char *uuid; char uuidstr[VIR_UUID_STRING_BUFLEN]; GET_NETWORK(network, NULL); if (!(buf = virBufferNew(4000))) { testError(network->conn, NULL, network, VIR_ERR_NO_MEMORY, __FUNCTION__); return (NULL); } virBufferAdd(buf, "\n", -1); virBufferVSprintf(buf, " %s\n", network->name); uuid = network->uuid; virUUIDFormat(uuid, uuidstr); virBufferVSprintf(buf, " %s\n", uuidstr); virBufferVSprintf(buf, " \n", privnet->bridge); if (privnet->forward) { if (privnet->forwardDev[0]) virBufferVSprintf(buf, " \n", privnet->forwardDev); else virBufferAdd(buf, " \n", -1); } virBufferVSprintf(buf, " \n", privnet->ipAddress, privnet->ipNetmask); virBufferAdd(buf, " \n", -1); virBufferVSprintf(buf, " \n", privnet->dhcpStart, privnet->dhcpEnd); virBufferAdd(buf, " \n", -1); virBufferAdd(buf, " \n", -1); virBufferAdd(buf, "\n", -1); xml = buf->content; free(buf); return (xml); } static char *testNetworkGetBridgeName(virNetworkPtr network) { char *bridge; GET_NETWORK(network, NULL); bridge = strdup(privnet->bridge); if (!bridge) { testError(network->conn, NULL, network, VIR_ERR_NO_MEMORY, "network"); return NULL; } return bridge; } static int testNetworkGetAutostart(virNetworkPtr network, int *autostart) { GET_NETWORK(network, -1); *autostart = privnet->autostart; return (0); } static int testNetworkSetAutostart(virNetworkPtr network, int autostart) { GET_NETWORK(network, -1); privnet->autostart = autostart ? 1 : 0; return (0); } static virDriver testDriver = { VIR_DRV_TEST, "Test", LIBVIR_VERSION_NUMBER, testOpen, /* open */ testClose, /* close */ NULL, /* supports_feature */ NULL, /* type */ testGetVersion, /* version */ testGetHostname, /* hostname */ testGetURI, /* URI */ testGetMaxVCPUs, /* getMaxVcpus */ testNodeGetInfo, /* nodeGetInfo */ testGetCapabilities, /* getCapabilities */ testListDomains, /* listDomains */ testNumOfDomains, /* numOfDomains */ testDomainCreateLinux, /* domainCreateLinux */ testLookupDomainByID, /* domainLookupByID */ testLookupDomainByUUID, /* domainLookupByUUID */ testLookupDomainByName, /* domainLookupByName */ testPauseDomain, /* domainSuspend */ testResumeDomain, /* domainResume */ testShutdownDomain, /* domainShutdown */ testRebootDomain, /* domainReboot */ testDestroyDomain, /* domainDestroy */ testGetOSType, /* domainGetOSType */ testGetMaxMemory, /* domainGetMaxMemory */ testSetMaxMemory, /* domainSetMaxMemory */ testSetMemory, /* domainSetMemory */ testGetDomainInfo, /* domainGetInfo */ testDomainSave, /* domainSave */ testDomainRestore, /* domainRestore */ testDomainCoreDump, /* domainCoreDump */ testSetVcpus, /* domainSetVcpus */ NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ testDomainDumpXML, /* domainDumpXML */ testListDefinedDomains, /* listDefinedDomains */ testNumOfDefinedDomains, /* numOfDefinedDomains */ testDomainCreate, /* domainCreate */ testDomainDefineXML, /* domainDefineXML */ testDomainUndefine, /* domainUndefine */ NULL, /* domainAttachDevice */ NULL, /* domainDetachDevice */ testDomainGetAutostart, /* domainGetAutostart */ testDomainSetAutostart, /* domainSetAutostart */ testDomainGetSchedulerType, /* domainGetSchedulerType */ testDomainGetSchedulerParams, /* domainGetSchedulerParameters */ testDomainSetSchedulerParams, /* domainSetSchedulerParameters */ NULL, /* domainMigratePrepare */ NULL, /* domainMigratePerform */ NULL, /* domainMigrateFinish */ NULL, /* domainBlockStats */ NULL, /* domainInterfaceStats */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ }; static virNetworkDriver testNetworkDriver = { "Test", testOpenNetwork, /* open */ testCloseNetwork, /* close */ testNumNetworks, /* numOfNetworks */ testListNetworks, /* listNetworks */ testNumDefinedNetworks, /* numOfDefinedNetworks */ testListDefinedNetworks, /* listDefinedNetworks */ testLookupNetworkByUUID, /* networkLookupByUUID */ testLookupNetworkByName, /* networkLookupByName */ testNetworkCreate, /* networkCreateXML */ testNetworkDefine, /* networkDefineXML */ testNetworkUndefine, /* networkUndefine */ testNetworkStart, /* networkCreate */ testNetworkDestroy, /* networkDestroy */ testNetworkDumpXML, /* networkDumpXML */ testNetworkGetBridgeName, /* networkGetBridgeName */ testNetworkGetAutostart, /* networkGetAutostart */ testNetworkSetAutostart, /* networkSetAutostart */ }; /** * testRegister: * * Registers the test driver */ int testRegister(void) { if (virRegisterDriver(&testDriver) < 0) return -1; if (virRegisterNetworkDriver(&testNetworkDriver) < 0) return -1; return 0; } #endif /* WITH_TEST */ /* * vim: set tabstop=4: * vim: set shiftwidth=4: * vim: set expandtab: */ /* * Local variables: * indent-tabs-mode: nil * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */