]> xenbits.xensource.com Git - libvirt.git/commitdiff
Hook up more test driver methods. Allow HV config to be loaded from extenral XML...
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 16 Aug 2006 16:36:39 +0000 (16:36 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 16 Aug 2006 16:36:39 +0000 (16:36 +0000)
ChangeLog
docs/testdomfc4.xml [new file with mode: 0644]
docs/testdomfv0.xml [new file with mode: 0644]
docs/testnode.xml [new file with mode: 0644]
src/test.c
src/test.h

index 23941691a2e0de52ef257dcd3faef8ec31817385..c30842b868ea2aeab39b9d08018043b74762e73f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Wed Aug 16 11:38:02 EDT 2006 Daniel Berrange <berrange@redhat.com>
+
+       * src/test.c, src/test.h: Allow a hypervisor config to be
+       loaded from an external XML file. Implement drivers for
+       setMemory, setMaxMemory, createLinux, dumpXML, setVcpus.
+       * docs/testnode.xml, docs/testfc4.xml, docs/testfv0.xml:
+       Example config for using with test driver
+       
 Wed Aug 16 11:36:21 EDT 2006 Daniel Berrange <berrange@redhat.com>
        
        * src/xend_internal.c, src/xml.c, src/xml.h: Refactored the 
diff --git a/docs/testdomfc4.xml b/docs/testdomfc4.xml
new file mode 100644 (file)
index 0000000..1fe9114
--- /dev/null
@@ -0,0 +1,25 @@
+<domain type='test'>
+  <name>fc4</name>
+  <uuid>EF86180145B911CB88E3AFBFE5370493</uuid>
+  <os>
+    <type>linux</type>
+    <kernel>/boot/vmlinuz-2.6.15-1.43_FC5guest</kernel>
+    <initrd>/boot/initrd-2.6.15-1.43_FC5guest.img</initrd>
+    <root>/dev/sda1</root>
+    <cmdline> ro selinux=0 3</cmdline>
+  </os>
+  <memory>131072</memory>
+  <vcpu>1</vcpu>
+  <devices>
+    <disk type='file'>
+      <source file='/u/fc4.img'/>
+      <target dev='sda1'/>
+    </disk>
+    <interface type='bridge'>
+      <source bridge='xenbr0'/>
+      <mac address='aa:00:00:00:00:11'/>
+      <script path='/etc/xen/scripts/vif-bridge'/>
+    </interface>
+    <console tty='/dev/pts/5'/>
+  </devices>
+</domain>
diff --git a/docs/testdomfv0.xml b/docs/testdomfv0.xml
new file mode 100644 (file)
index 0000000..157c8ec
--- /dev/null
@@ -0,0 +1,42 @@
+<domain type='test'>
+  <name>fv0</name>
+  <uuid>4dea22b31d52d8f32516782e98ab3fa0</uuid>
+  <os>
+    <type>hvm</type>
+    <loader>/usr/lib/xen/boot/hvmloader</loader>
+    <boot dev='hd'/>
+  </os>
+  <memory>524288</memory>
+  <maxMemory>1524288</maxMemory>
+  <vcpu>4</vcpu>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <features>
+     <pae/>
+     <acpi/>
+     <apic/>
+  </features>
+  <devices>
+    <emulator>/usr/lib/xen/bin/qemu-dm</emulator>
+    <interface type='bridge'>
+      <source bridge='xenbr0'/>
+      <mac address='00:16:3e:5d:c7:9e'/>
+      <script path='vif-bridge'/>
+    </interface>
+    <disk type='file'>
+      <source file='/root/fv0'/>
+      <target dev='hda'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <source file='/root/fc5-x86_64-boot.iso'/>
+      <target dev='hdc'/>
+      <readonly/>
+    </disk>
+    <disk type='file' device='floppy'>
+      <source file='/root/fd.img'/>
+      <target dev='fda'/>
+    </disk>
+    <graphics type='vnc' port='5904'/>
+  </devices>
+</domain>
diff --git a/docs/testnode.xml b/docs/testnode.xml
new file mode 100644 (file)
index 0000000..19b0d4c
--- /dev/null
@@ -0,0 +1,23 @@
+<node>
+<!-- This file gives an example config for the mock 'test' backend 
+     driver to libvirt. This is intended to allow relible unit testing
+     of applications using libvirt. To use this with virsh, run something
+     like:
+
+      virsh -connect test:////path/to/this/dir/testnode.xml nodeinfo
+
+     -->
+  <domain file="testdomfv0.xml"/>
+  <domain file="testdomfc4.xml"/>
+
+  <cpu>
+    <mhz>6000</mhz>
+    <model>i986</model>
+    <active>50</active>
+    <nodes>4</nodes>
+    <sockets>4</sockets>
+    <cores>4</cores>
+    <threads>2</threads>
+  </cpu>
+  <memory>137438953472</memory>
+</node>
index 215d323d5ad669a473aaf677b95d19d8ddb039f3..e66598873fcd442c448d2953e28d8d07ce9984db 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
 #include <libxml/uri.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include "internal.h"
 #include "test.h"
+#include "xml.h"
 
 static virDriver testDriver = {
   VIR_DRV_TEST,
@@ -28,7 +34,7 @@ static virDriver testDriver = {
   testNodeGetInfo, /* nodeGetInfo */
   testListDomains, /* listDomains */
   testNumOfDomains, /* numOfDomains */
-  NULL, /* domainCreateLinux */
+  testDomainCreateLinux, /* domainCreateLinux */
   testLookupDomainByID, /* domainLookupByID */
   testLookupDomainByUUID, /* domainLookupByUUID */
   testLookupDomainByName, /* domainLookupByName */
@@ -42,16 +48,16 @@ static virDriver testDriver = {
   NULL, /* domainGetID */
   NULL, /* domainGetUUID */
   NULL, /* domainGetOSType */
-  NULL, /* domainGetMaxMemory */
+  testGetMaxMemory, /* domainGetMaxMemory */
   testSetMaxMemory, /* domainSetMaxMemory */
-  NULL, /* domainSetMemory */
+  testSetMemory, /* domainSetMemory */
   testGetDomainInfo, /* domainGetInfo */
   NULL, /* domainSave */
   NULL, /* domainRestore */
-  NULL, /* domainSetVcpus */
+  testSetVcpus, /* domainSetVcpus */
   NULL, /* domainPinVcpu */
   NULL, /* domainGetVcpus */
-  NULL, /* domainDumpXML */
+  testDomainDumpXML, /* domainDumpXML */
 };
 
 /* Amount of time it takes to shutdown */
@@ -71,7 +77,10 @@ typedef struct _testDom {
   virDomainKernel kernel;
   virDomainInfo info;
   time_t shutdownStartedAt;
-  virDomainRestart onRestart;
+  virDomainRestart onRestart; /* What to do at end of current shutdown procedure */
+  virDomainRestart onReboot;
+  virDomainRestart onPoweroff;
+  virDomainRestart onCrash;
   int numDevices;
   testDev devices[MAX_DEVICES];
 } testDom;
@@ -80,6 +89,7 @@ typedef struct _testDom {
 
 typedef struct _testCon {
   int active;
+  virNodeInfo nodeInfo;
   int numDomains;
   testDom domains[MAX_DOMAINS];
 } testCon;
@@ -98,8 +108,8 @@ typedef struct _testNode {
    too probably */
 static testNode *node = NULL;
 
-static virNodeInfo nodeInfo = {
-  "i86",
+static const virNodeInfo defaultNodeInfo = {
+  "i686",
   1024*1024*3, /* 3 GB */
   16,
   1400,
@@ -125,6 +135,33 @@ testError(virConnectPtr con,
                  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;
+}
 
 /**
  * testRegister:
@@ -136,13 +173,452 @@ void testRegister(void)
   virRegisterDriver(&testDriver);
 }
 
+static int testLoadDomain(virConnectPtr conn,
+                         int domid,
+                         xmlDocPtr xml) {
+  xmlNodePtr root = NULL;
+  xmlXPathContextPtr ctxt = NULL;
+  xmlXPathObjectPtr obj = NULL;
+  char *name = NULL;
+  unsigned char rawuuid[16];
+  char *dst_uuid;
+  testCon *con;
+  struct timeval tv;
+  unsigned long memory;
+  int nrVirtCpu;
+  char *conv;
+  virDomainRestart onReboot = VIR_DOMAIN_RESTART;
+  virDomainRestart onPoweroff = VIR_DOMAIN_DESTROY;
+  virDomainRestart onCrash = VIR_DOMAIN_RENAME_RESTART;
+
+  if (gettimeofday(&tv, NULL) < 0) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday");
+    return -1;
+  }
+
+  root = xmlDocGetRootElement(xml);
+  if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed root element");
+    goto error;
+  }
+
+  ctxt = xmlXPathNewContext(xml);
+  if (ctxt == NULL) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create xpath context");
+    goto error;
+  }
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "missing name element on domain");
+    goto error;
+  }
+  name = strdup((const char *)obj->stringval);
+  xmlXPathFreeObject(obj);
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "missing uuid element on domain");
+    goto error;
+  }
+  dst_uuid = (char *) &rawuuid[0];
+  if (!(virParseUUID((char **)&dst_uuid, (const char *)obj->stringval))) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed uuid data in domain");
+    goto error;
+  }
+  xmlXPathFreeObject(obj);
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/memory[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "missing memory element on domain");
+    goto error;
+  }
+  memory = strtoll((const char*)obj->stringval, &conv, 10);
+  if (conv == (const char*)obj->stringval) {
+    testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed memory value for domain");
+    goto error;
+  }
+  xmlXPathFreeObject(obj);
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/vcpu[1])", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+      (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    nrVirtCpu = 1;
+  } else {
+    nrVirtCpu = strtoll((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed vcpus value for domain");
+      goto error;
+    }
+  }
+  if (obj)
+    xmlXPathFreeObject(obj);
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/on_reboot[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    if (!(onReboot = testRestartStringToFlag((const char *)obj->stringval))) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed on_reboot value for domain");
+      goto error;
+    }
+  }
+  if (obj)
+    xmlXPathFreeObject(obj);
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/on_poweroff[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    if (!(onReboot = testRestartStringToFlag((const char *)obj->stringval))) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed on_poweroff value for domain");
+      goto error;
+    }
+  }
+  if (obj)
+    xmlXPathFreeObject(obj);
+
+  obj = xmlXPathEval(BAD_CAST "string(/domain/on_crash[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    if (!(onReboot = testRestartStringToFlag((const char *)obj->stringval))) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed on_crash value for domain");
+      goto error;
+    }
+  }
+  if (obj)
+    xmlXPathFreeObject(obj);
+
+  con = &node->connections[conn->handle];
+
+  con->domains[domid].active = 1;
+  strncpy(con->domains[domid].name, name, sizeof(con->domains[domid].name));
+  free(name);
+  name = NULL;
+
+  memmove(con->domains[domid].uuid, rawuuid, 16);
+  con->domains[domid].info.maxMem = memory;
+  con->domains[domid].info.memory = memory;
+  con->domains[domid].info.state = VIR_DOMAIN_RUNNING;
+  con->domains[domid].info.nrVirtCpu = nrVirtCpu;
+  con->domains[domid].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
+
+  con->domains[domid].onReboot = onReboot;
+  con->domains[domid].onPoweroff = onPoweroff;
+  con->domains[domid].onCrash = onCrash;
+
+  return 0;
+
+ error:
+  if (obj)
+    xmlXPathFreeObject(obj);
+  if (name)
+    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(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot parse domain definition");
+    return -1;
+  }
+
+  ret = testLoadDomain(conn, domid, xml);
+
+  xmlFreeDoc(xml);
+
+  return ret;
+}
+
+static int testLoadDomainFromFile(virConnectPtr conn,
+                                 int domid,
+                                 const char *file) {
+  int ret, fd;
+  xmlDocPtr xml;
+
+  if ((fd = open(file, O_RDONLY)) < 0) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot load domain definition");
+    return -1;
+  }
+
+  if (!(xml = xmlReadFd(fd, file, NULL,
+                       XML_PARSE_NOENT | XML_PARSE_NONET |
+                       XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot parse domain definition");
+    close(fd);
+    return -1;
+  }
+  close(fd);
+
+  ret = testLoadDomain(conn, domid, xml);
+
+  xmlFreeDoc(xml);
+
+  return ret;
+}
+
+
+static int testOpenDefault(virConnectPtr conn,
+                          int connid) {
+  int u;
+  struct timeval tv;
+
+  if (gettimeofday(&tv, NULL) < 0) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday");
+    return -1;
+  }
+
+  conn->handle = connid;
+  node->connections[connid].active = 1;
+  memmove(&node->connections[connid].nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+  node->connections[connid].numDomains = 1;
+  node->connections[connid].domains[0].active = 1;
+  strcpy(node->connections[connid].domains[0].name, "Domain-0");
+  for (u = 0 ; u < 16 ; u++) {
+    node->connections[connid].domains[0].uuid[u] = (u * 75)%255;
+  }
+  node->connections[connid].domains[0].info.maxMem = 8192 * 1024;
+  node->connections[connid].domains[0].info.memory = 2048 * 1024;
+  node->connections[connid].domains[0].info.state = VIR_DOMAIN_RUNNING;
+  node->connections[connid].domains[0].info.nrVirtCpu = 2;
+  node->connections[connid].domains[0].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
+  return 0;
+}
+
+
+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 = rindex(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,
+                           int connid,
+                           const char *file) {
+  int fd, i;
+  xmlDocPtr xml;
+  xmlNodePtr root = NULL;
+  xmlXPathContextPtr ctxt = NULL;
+  xmlXPathObjectPtr obj = NULL;
+  virNodeInfoPtr nodeInfo;
+
+  if ((fd = open(file, O_RDONLY)) < 0) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot load host definition");
+    return -1;
+  }
+
+  if (!(xml = xmlReadFd(fd, file, NULL,
+                       XML_PARSE_NOENT | XML_PARSE_NONET |
+                       XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot parse host definition");
+    goto error;
+  }
+  close(fd);
+  fd = -1;
+
+  root = xmlDocGetRootElement(xml);
+  if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "node"))) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "malformed root element");
+    goto error;
+  }
+
+  ctxt = xmlXPathNewContext(xml);
+  if (ctxt == NULL) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create xpath context");
+    goto error;
+  }
+
+  conn->handle = connid;
+  node->connections[connid].active = 1;
+  node->connections[connid].numDomains = 0;
+  memmove(&node->connections[connid].nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+  nodeInfo = &node->connections[connid].nodeInfo;
+  obj = xmlXPathEval(BAD_CAST "string(/node/cpu/nodes[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    char *conv = NULL;
+    nodeInfo->nodes = strtol((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed nodes value for node cpu");
+      goto error;
+    }
+    xmlXPathFreeObject(obj);
+  }
+
+  obj = xmlXPathEval(BAD_CAST "string(/node/cpu/sockets[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    char *conv = NULL;
+    nodeInfo->sockets = strtol((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed sockets value for node cpu");
+      goto error;
+    }
+    xmlXPathFreeObject(obj);
+  }
+
+  obj = xmlXPathEval(BAD_CAST "string(/node/cpu/cores[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    char *conv = NULL;
+    nodeInfo->cores = strtol((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed cores value for node cpu");
+      goto error;
+    }
+    xmlXPathFreeObject(obj);
+  }
+
+  obj = xmlXPathEval(BAD_CAST "string(/node/cpu/threads[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    char *conv = NULL;
+    nodeInfo->threads = strtol((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed threads value for node cpu");
+      goto error;
+    }
+    xmlXPathFreeObject(obj);
+  }
+  nodeInfo->cpus = nodeInfo->cores * nodeInfo->threads * nodeInfo->sockets * nodeInfo->nodes;
+  obj = xmlXPathEval(BAD_CAST "string(/node/cpu/active[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    char *conv = NULL;
+    unsigned int active = strtol((const char*)obj->stringval, &conv, 10);    
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed active value for node cpu");
+      goto error;
+    }
+    if (active < nodeInfo->cpus) {
+      nodeInfo->cpus = active;
+    }
+    xmlXPathFreeObject(obj);
+  }
+  obj = xmlXPathEval(BAD_CAST "string(/node/cpu/mhz[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    char *conv = NULL;
+    nodeInfo->mhz = strtol((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed threads value for node cpu");
+      goto error;
+    }
+    xmlXPathFreeObject(obj);
+  }
+  obj = xmlXPathEval(BAD_CAST "string(/node/cpu/model[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    strncpy(nodeInfo->model, (const char *)obj->stringval, sizeof(nodeInfo->model)-1);
+    nodeInfo->model[sizeof(nodeInfo->model)-1] = '\0';
+    xmlXPathFreeObject(obj);
+  }
+
+  obj = xmlXPathEval(BAD_CAST "string(/node/memory[1])", ctxt);
+  if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+      (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+    char *conv = NULL;
+    nodeInfo->memory = strtol((const char*)obj->stringval, &conv, 10);
+    if (conv == (const char*)obj->stringval) {
+      testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed memory value for node");
+      goto error;
+    }
+    xmlXPathFreeObject(obj);
+  }
+
+  obj = xmlXPathEval(BAD_CAST "/node/domain", ctxt);
+  if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+      (obj->nodesetval == NULL)) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot extract domain list");
+    goto error;
+  }
+
+  for (i = 0 ; i < obj->nodesetval->nodeNr ; i++) {
+    xmlChar *domFile = xmlGetProp(obj->nodesetval->nodeTab[i], BAD_CAST "file");
+    char *absFile = testBuildFilename(file, (const char *)domFile);
+    free(domFile);
+    if (!absFile) {
+      testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot resolve filename");
+      goto error;
+    }
+    if (testLoadDomainFromFile(conn, i, absFile) != 0) {
+      free(absFile);
+      goto error;
+    }
+    free(absFile);
+    node->connections[connid].numDomains++;
+  }
+
+  xmlXPathFreeObject(obj);
+  xmlFreeDoc(xml);
+
+  return 0;
+
+ error:
+  if (node->connections[connid].active) {
+    for (i = 0 ; i <node->connections[connid].numDomains ; i++) {
+      node->connections[connid].domains[i].active = 0;
+    }
+    node->connections[connid].numDomains = 0;
+    node->connections[connid].active = 0;
+  }
+  if (obj)
+    xmlXPathFreeObject(obj);
+  if (xml)
+    xmlFreeDoc(xml);
+  if (fd != -1)
+    close(fd);
+  return -1;
+}
+
+static int getNextConnection(void) {
+  int i;
+  if (node == NULL) {
+    node = calloc(1, sizeof(testNode));
+    if (!node) {
+      testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot allocate memory");
+      return -1;
+    }
+  }
+
+  for (i = 0 ; i < MAX_CONNECTIONS ; i++) {
+    if (!node->connections[i].active) {
+      return i;
+    }
+  }
+  return -1;
+}
 
 int testOpen(virConnectPtr conn,
              const char *name,
              int flags)
 {
   xmlURIPtr uri;
-  int i, j;
+  int ret, connid;
 
   if (!name) {
     return -1;
@@ -157,53 +633,29 @@ int testOpen(virConnectPtr conn,
 
   if (!uri->scheme ||
       strcmp(uri->scheme, "test") ||
-      !uri->path ||
-      strcmp(uri->path, "/default")) {
+      !uri->path) {
     xmlFreeURI(uri);
     return -1;
   }
 
 
-  xmlFreeURI(uri);
-
-  if (node == NULL) {
-    node = calloc(1, sizeof(testNode));
-    if (!node) {
-      testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot allocate memory");
-      return -1;
-    }
+  if ((connid = getNextConnection()) < 0) {
+    testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "too many connections");
+    return -1;
   }
 
-  for (i = 0 ; i < MAX_CONNECTIONS ; i++) {
-    if (!node->connections[i].active) {
-      struct timeval tv;
-
-      if (gettimeofday(&tv, NULL) < 0) {
-       testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday");
-       return -1;
-      }
-
-      conn->handle = i;
-      node->connections[i].active = 1;
-
-      node->connections[i].numDomains = 1;
-      node->connections[i].domains[0].active = 1;
-      strcpy(node->connections[i].domains[0].name, "Domain-0");
-      for (j = 0 ; j < 16 ; j++) {
-       node->connections[i].domains[0].uuid[j] = (j * 75)%255;
-      }
-      node->connections[i].domains[0].info.maxMem = 8192 * 1024;
-      node->connections[i].domains[0].info.memory = 2048 * 1024;
-      node->connections[i].domains[0].info.state = VIR_DOMAIN_RUNNING;
-      node->connections[i].domains[0].info.nrVirtCpu = 2;
-      node->connections[i].domains[0].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
-      return 0;
-    }
+  if (!strcmp(uri->path, "/default")) {
+    ret = testOpenDefault(conn,
+                         connid);
+  } else {
+    ret = testOpenFromFile(conn,
+                          connid,
+                          uri->path);
   }
 
+  xmlFreeURI(uri);
 
-  testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "too make connections");
-  return -1;
+  return (ret);
 }
 
 int testClose(virConnectPtr conn)
@@ -218,14 +670,15 @@ int testClose(virConnectPtr conn)
 int testGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
                    unsigned long *hvVer)
 {
-  *hvVer = 1;
+  *hvVer = 2;
   return 0;
 }
 
-int testNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
+int testNodeGetInfo(virConnectPtr conn,
                     virNodeInfoPtr info)
 {
-  memcpy(info, &nodeInfo, sizeof(nodeInfo));
+  testCon *con = &node->connections[conn->handle];
+  memcpy(info, &con->nodeInfo, sizeof(virNodeInfo));
   return 0;
 }
 
@@ -235,14 +688,58 @@ int testNumOfDomains(virConnectPtr conn)
   return con->numDomains;
 }
 
+virDomainPtr
+testDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
+                     unsigned int flags ATTRIBUTE_UNUSED)
+{
+  testCon *con;
+  int i;
+  virDomainPtr dom;
+
+  if (!VIR_IS_CONNECT(conn)) {
+    testError(conn, NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    return (NULL);
+  }
+  if (xmlDesc == NULL) {
+    testError(conn, NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+    return (NULL);
+  }
+  if (conn->flags & VIR_CONNECT_RO) {
+    testError(conn, NULL, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (NULL);
+  }
+  
+  con = &node->connections[conn->handle];
+
+  for (i = 0 ; i < MAX_DOMAINS ; i++) {
+    if (!con->domains[i].active) {
+      if (testLoadDomainFromDoc(conn, i, xmlDesc) < 0)
+       return NULL;
+      dom = virGetDomain(conn, con->domains[i].name, con->domains[i].uuid);
+      if (dom == NULL) {
+       testError(conn, NULL, VIR_ERR_NO_MEMORY, "allocating domain");
+       return NULL;
+      }
+      con->numDomains++;
+      return dom;
+    }
+  }
+  
+  testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "too many domains");
+  return (NULL);
+}
+
+
 virDomainPtr testLookupDomainByID(virConnectPtr conn,
                                   int id)
 {
   testCon *con = &node->connections[conn->handle];
   virDomainPtr dom;
+
   if (!con->domains[id].active) {
     return NULL;
   }
+
   dom = virGetDomain(conn, con->domains[id].name, con->domains[id].uuid);
   if (dom == NULL) {
     testError(conn, NULL, VIR_ERR_NO_MEMORY, "Allocating domain");
@@ -317,23 +814,56 @@ int testListDomains (virConnectPtr conn,
 
 int testDestroyDomain (virDomainPtr domain)
 {
-  testCon *con = &node->connections[domain->conn->handle];
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+  
+  con = &node->connections[domain->conn->handle];
   con->domains[domain->handle].active = 0;
-  return 0;
+  return (0);
 }
 
 int testResumeDomain (virDomainPtr domain)
 {
-  testCon *con = &node->connections[domain->conn->handle];
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
   con->domains[domain->handle].info.state = VIR_DOMAIN_RUNNING;
   return 0;
 }
 
 int testPauseDomain (virDomainPtr domain)
 {
-  testCon *con = &node->connections[domain->conn->handle];
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
   con->domains[domain->handle].info.state = VIR_DOMAIN_PAUSED;
-  return 0;
+  return (0);
 }
 
 /* We don't do an immediate shutdown. We basically pretend that
@@ -342,27 +872,51 @@ int testPauseDomain (virDomainPtr domain)
    will check to see if shutdown ought to be marked complete. */
 int testShutdownDomain (virDomainPtr domain)
 {
-  testCon *con = &node->connections[domain->conn->handle];
+  testCon *con;
   struct timeval tv;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return (-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
+
   if (gettimeofday(&tv, NULL) < 0) {
     testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday");
-    return -1;
+    return (-1);
   }
 
   con->domains[domain->handle].info.state = VIR_DOMAIN_SHUTDOWN;
   con->domains[domain->handle].onRestart = VIR_DOMAIN_DESTROY;
   con->domains[domain->handle].shutdownStartedAt = tv.tv_sec;
-  return 0;
+  return (0);
 }
 
 /* Similar behaviour as shutdown */
 int testRebootDomain (virDomainPtr domain, virDomainRestart action)
 {
-  testCon *con = &node->connections[domain->conn->handle];
+  testCon *con;
   struct timeval tv;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
+
   if (gettimeofday(&tv, NULL) < 0) {
     testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday");
-    return -1;
+    return (-1);
   }
 
   if (!action)
@@ -371,17 +925,25 @@ int testRebootDomain (virDomainPtr domain, virDomainRestart action)
   con->domains[domain->handle].info.state = VIR_DOMAIN_SHUTDOWN;
   con->domains[domain->handle].onRestart = action;
   con->domains[domain->handle].shutdownStartedAt = tv.tv_sec;
-  return 0;
+  return (0);
 }
 
 int testGetDomainInfo (virDomainPtr domain,
                        virDomainInfoPtr info)
 {
-  testCon *con = &node->connections[domain->conn->handle];
   struct timeval tv;
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
+
   if (gettimeofday(&tv, NULL) < 0) {
     testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday");
-    return -1;
+    return (-1);
   }
 
   /* Check to see if there is an in-progresss shutdown/reboot that
@@ -419,13 +981,129 @@ int testGetDomainInfo (virDomainPtr domain,
     con->domains[domain->handle].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
   }
   memcpy(info, &con->domains[domain->handle].info, sizeof(virDomainInfo));
-  return 0;
+  return (0);
+}
+
+unsigned long testGetMaxMemory(virDomainPtr domain) {
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  
+  con = &node->connections[domain->conn->handle];
+  return con->domains[domain->handle].info.maxMem;
 }
 
 int testSetMaxMemory (virDomainPtr domain,
                       unsigned long memory)
 {
-  testCon *con = &node->connections[domain->conn->handle];
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
+  /* XXX validate not over host memory wrt to other domains */
   con->domains[domain->handle].info.maxMem = memory;
-  return 0;
+  return (0);
+}
+
+int testSetMemory (virDomainPtr domain,
+                  unsigned long memory)
+{
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
+
+  if (memory > con->domains[domain->handle].info.maxMem) {
+    testError(domain->conn, domain, VIR_ERR_INVALID_ARG, "memory over maximum limit");
+    return (-1);
+  }
+
+  con->domains[domain->handle].info.memory = memory;
+  return (0);
+}
+
+int testSetVcpus(virDomainPtr domain,
+                unsigned int nrCpus) {
+  testCon *con;
+
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(-1);
+  }
+  if (domain->conn->flags & VIR_CONNECT_RO) {
+    testError(domain->conn, domain, VIR_ERR_READ_ONLY, __FUNCTION__);
+    return (-1);
+  }
+
+  con = &node->connections[domain->conn->handle];
+
+  /* We allow more cpus in guest than host */
+  if (nrCpus > 32) {
+    testError(domain->conn, domain, VIR_ERR_INVALID_ARG, "too many virtual cpus");
+    return (-1);
+  }
+
+  con->domains[domain->handle].info.nrVirtCpu = nrCpus;
+  return (0);
+}
+
+char * testDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
+{
+  virBufferPtr buf;
+  char *xml;
+  unsigned char *uuid;
+  testCon *con;
+  if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+    testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+             __FUNCTION__);
+    return(NULL);
+  }
+  
+  con = &node->connections[domain->conn->handle];
+  
+  if (!(buf = virBufferNew(4000))) {
+    return (NULL);
+  }
+  
+  virBufferVSprintf(buf, "<domain type='test' id='%d'>\n", domain->handle);
+  virBufferVSprintf(buf, "  <name>%s</name>\n", domain->name);
+  uuid = domain->uuid;
+  virBufferVSprintf(buf,
+                   "  <uuid>%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x</uuid>\n",
+                   uuid[0], uuid[1], uuid[2], uuid[3],
+                   uuid[4], uuid[5], uuid[6], uuid[7],
+                   uuid[8], uuid[9], uuid[10], uuid[11],
+                   uuid[12], uuid[13], uuid[14], uuid[15]);
+  
+  virBufferVSprintf(buf, "  <memory>%d</memory>\n", con->domains[domain->handle].info.maxMem);
+  virBufferVSprintf(buf, "  <vcpu>%d</vcpu>\n", con->domains[domain->handle].info.nrVirtCpu);
+  virBufferVSprintf(buf, "  <on_reboot>%s</on_reboot>\n", testRestartFlagToString(con->domains[domain->handle].onReboot));
+  virBufferVSprintf(buf, "  <on_poweroff>%s</on_poweroff>\n", testRestartFlagToString(con->domains[domain->handle].onPoweroff));
+  virBufferVSprintf(buf, "  <on_crash>%s</on_crash>\n", testRestartFlagToString(con->domains[domain->handle].onCrash));
+  
+  virBufferAdd(buf, "</domain>\n", -1);
+  
+  xml = buf->content;
+  free(buf);
+  return xml;
 }
index ff5d55b9bd91dc93715069919caaf5db30362966..5ec669671565b54cf4535d28b1e7aa28087ccf39 100644 (file)
@@ -30,6 +30,9 @@ int testNumOfDomains(virConnectPtr conn);
 int testListDomains(virConnectPtr conn,
                    int *ids,
                    int maxids);
+virDomainPtr
+testDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
+                     unsigned int flags ATTRIBUTE_UNUSED);
 virDomainPtr testLookupDomainByID(virConnectPtr conn,
                                  int id);
 virDomainPtr testLookupDomainByUUID(virConnectPtr conn,
@@ -44,10 +47,14 @@ int testRebootDomain (virDomainPtr domain,
                      virDomainRestart action);
 int testGetDomainInfo(virDomainPtr domain,
                      virDomainInfoPtr info);
-int testGetDomainID(virDomainPtr domain);
-const char*testGetDomainName(virDomainPtr domain);
+unsigned long testGetMaxMemory(virDomainPtr domain);
 int testSetMaxMemory(virDomainPtr domain,
                     unsigned long memory);
+int testSetMemory(virDomainPtr domain,
+                 unsigned long memory);
+int testSetVcpus(virDomainPtr domain,
+                unsigned int nrCpus);
+char * testDomainDumpXML(virDomainPtr domain, int flags);
 
 #ifdef __cplusplus
 }