]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
add XML parsing for qemu/kvm status files
authorGuido Günther <agx@sigxcpu.org>
Sat, 20 Dec 2008 13:09:45 +0000 (13:09 +0000)
committerGuido Günther <agx@sigxcpu.org>
Sat, 20 Dec 2008 13:09:45 +0000 (13:09 +0000)
ChangeLog
src/domain_conf.c
src/domain_conf.h
src/libvirt_sym.version.in
src/qemu_conf.c
src/qemu_conf.h

index 082207e2f71aac7f6306ad87933f6e3167767148..4353fa1e0e50bd3ea36b50de5d74d791e2c57ed3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Sat Dec 20 13:53:14 CET 2008 Guido Günther <agx@sigxcpu.org>
+
+       add XML parsing for qemu/kvm status files
+       * src/domain_conf.c, src/domain_conf.h (virDomainSaveXML): new function
+       * src/domain_conf.c (virDomainSaveConfig): split out XML writing into
+         virDomainSaveXML
+       * src/qemu_conf.c (qemudDomainStatusParseFile): new function to parse
+         status XML
+         (qemudDomainStatusFormat): new function to format status XML
+         (qemudSaveDomainStatus): new function to write status XML, uses
+         virDomainSaveXML
+       * src/libvirt_sym.version.in: add virBufferEscapeString, virDomainSaveXML,
+         virXPathNode symbols
+
 Fri Dec 19 10:41:00 UTC 2008 Richard W.M. Jones <rjones@redhat.com>
 
        * docs/formatdomain.html.in: Fix documentation typo
index eef5226da722ca23243e6589e1a54a2dad94dd2c..5374e1790b68c06d20bfc3d5031ed25929c72a42 100644 (file)
@@ -430,6 +430,7 @@ void virDomainObjFree(virDomainObjPtr dom)
     virDomainDefFree(dom->def);
     virDomainDefFree(dom->newDef);
 
+    VIR_FREE(dom->monitorpath);
     VIR_FREE(dom->vcpupids);
 
     VIR_FREE(dom);
@@ -3243,11 +3244,11 @@ char *virDomainDefFormat(virConnectPtr conn,
 
 #ifndef PROXY
 
-int virDomainSaveConfig(virConnectPtr conn,
-                        const char *configDir,
-                        virDomainDefPtr def)
+int virDomainSaveXML(virConnectPtr conn,
+                     const char *configDir,
+                     virDomainDefPtr def,
+                     const char *xml)
 {
-    char *xml;
     char *configFile = NULL;
     int fd = -1, ret = -1;
     size_t towrite;
@@ -3256,11 +3257,6 @@ int virDomainSaveConfig(virConnectPtr conn,
     if ((configFile = virDomainConfigFile(conn, configDir, def->name)) == NULL)
         goto cleanup;
 
-    if (!(xml = virDomainDefFormat(conn,
-                                   def,
-                                   VIR_DOMAIN_XML_SECURE)))
-        goto cleanup;
-
     if ((err = virFileMakePath(configDir))) {
         virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
                               _("cannot create config directory %s: %s"),
@@ -3293,12 +3289,30 @@ int virDomainSaveConfig(virConnectPtr conn,
     }
 
     ret = 0;
-
  cleanup:
-    VIR_FREE(xml);
     if (fd != -1)
         close(fd);
+    return ret;
+}
+
+int virDomainSaveConfig(virConnectPtr conn,
+                        const char *configDir,
+                        virDomainDefPtr def)
+{
+    int ret = -1;
+    char *xml;
 
+    if (!(xml = virDomainDefFormat(conn,
+                                   def,
+                                   VIR_DOMAIN_XML_SECURE)))
+        goto cleanup;
+
+    if (virDomainSaveXML(conn, configDir, def, xml))
+        goto cleanup;
+
+    ret = 0;
+cleanup:
+    VIR_FREE(xml);
     return ret;
 }
 
index d8a31743c042041cecaccf79eb3a09cc88f426ed..3ad518b091af394aec61e5856f9b53b5d26c9a95 100644 (file)
@@ -464,6 +464,7 @@ struct _virDomainObj {
     int stderr_fd;
     int stderr_watch;
     int monitor;
+    char *monitorpath;
     int monitorWatch;
     int logfile;
     int pid;
@@ -555,6 +556,11 @@ int virDomainDiskQSort(const void *a, const void *b);
 int virDomainDiskCompare(virDomainDiskDefPtr a,
                          virDomainDiskDefPtr b);
 
+int virDomainSaveXML(virConnectPtr conn,
+                     const char *configDir,
+                     virDomainDefPtr def,
+                     const char *xml);
+
 int virDomainSaveConfig(virConnectPtr conn,
                         const char *configDir,
                         virDomainDefPtr def);
index fa9bc5a7780b7524ec97c1071c328dce92880306..b3812b6fe1d70163d0ac7281caf1eefed1c6c772 100644 (file)
@@ -281,6 +281,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
 
        # buf.h
        virBufferVSprintf;
+       virBufferEscapeString;
        virBufferAdd;
        virBufferAddChar;
        virBufferContentAndReset;
@@ -360,6 +361,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
        virDomainObjFree;
        virDomainObjListFree;
        virDomainRemoveInactive;
+       virDomainSaveXML;
        virDomainSaveConfig;
        virDomainSoundDefFree;
        virDomainSoundModelTypeFromString;
@@ -601,6 +603,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
 
        # xml.h
        virXPathLong;
+       virXPathNode;
        virXPathNodeSet;
        virXPathString;
        virXMLPropString;
index c973adb770d67e2a3a99e4727b14fbe21072f54d..469bf1feb579b338c7d6300313303b2ee24864f0 100644 (file)
@@ -49,6 +49,8 @@
 #include "util.h"
 #include "memory.h"
 #include "verify.h"
+#include "datatypes.h"
+#include "xml.h"
 
 VIR_ENUM_DECL(virDomainDiskQEMUBus)
 VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
@@ -1334,3 +1336,192 @@ int qemudBuildCommandLine(virConnectPtr conn,
 #undef ADD_ENV_LIT
 #undef ADD_ENV_SPACE
 }
+
+
+/* Called from SAX on parsing errors in the XML. */
+static void
+catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+    if (ctxt) {
+        virConnectPtr conn = ctxt->_private;
+
+        if (ctxt->lastError.level == XML_ERR_FATAL &&
+            ctxt->lastError.message != NULL) {
+            qemudReportError (conn, NULL, NULL, VIR_ERR_XML_DETAIL,
+                                  _("at line %d: %s"),
+                                  ctxt->lastError.line,
+                                  ctxt->lastError.message);
+        }
+    }
+}
+
+
+/**
+ * qemudDomainStatusParseFile
+ *
+ * read the last known status of a domain
+ *
+ * Returns 0 on success
+ */
+qemudDomainStatusPtr
+qemudDomainStatusParseFile(virConnectPtr conn,
+                           virCapsPtr caps,
+                           const char *filename, int flags)
+{
+    xmlParserCtxtPtr pctxt = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    xmlDocPtr xml = NULL;
+    xmlNodePtr root, config_root;
+    virDomainDefPtr def = NULL;
+    char *tmp = NULL;
+    long val;
+    qemudDomainStatusPtr status = NULL;
+
+    if (VIR_ALLOC(status) < 0) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
+                         "%s", _("failed to allocate space for vm status"));
+        goto error;
+    }
+
+    /* Set up a parser context so we can catch the details of XML errors. */
+    pctxt = xmlNewParserCtxt ();
+    if (!pctxt || !pctxt->sax)
+        goto error;
+    pctxt->sax->error = catchXMLError;
+    pctxt->_private = conn;
+
+    if (conn) virResetError (&conn->err);
+    xml = xmlCtxtReadFile (pctxt, filename, NULL,
+                           XML_PARSE_NOENT | XML_PARSE_NONET |
+                           XML_PARSE_NOWARNING);
+    if (!xml) {
+        if (conn && conn->err.code == VIR_ERR_NONE)
+              qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR,
+                                   "%s", _("failed to parse xml document"));
+        goto error;
+    }
+
+    if ((root = xmlDocGetRootElement(xml)) == NULL) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("missing root element"));
+        goto error;
+    }
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
+        goto error;
+    }
+
+    if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("incorrect root element"));
+        goto error;
+    }
+
+    ctxt->node = root;
+    if((virXPathLong(conn, "string(./@state)", ctxt, &val)) < 0) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("invalid domain state"));
+        goto error;
+    } else
+        status->state = (int)val;
+
+    if((virXPathLong(conn, "string(./@pid)", ctxt, &val)) < 0) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("invalid pid"));
+        goto error;
+    } else
+        status->pid = (pid_t)val;
+
+    if(!(tmp = virXPathString(conn, "string(./monitor[1]/@path)", ctxt))) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("no monitor path"));
+        goto error;
+    } else
+        status->monitorpath = tmp;
+
+    if(!(config_root = virXPathNode(conn, "./domain", ctxt))) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("no domain config"));
+        goto error;
+    }
+    if(!(def = virDomainDefParseNode(conn, caps, xml, config_root, flags)))
+        goto error;
+    else
+        status->def = def;
+
+cleanup:
+    xmlFreeParserCtxt (pctxt);
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc (xml);
+    return status;
+
+error:
+    VIR_FREE(tmp);
+    VIR_FREE(status);
+    goto cleanup;
+}
+
+
+/**
+ * qemudDomainStatusFormat
+ *
+ * Get the state of a running domain as XML
+ *
+ * Returns xml on success
+ */
+static char*
+qemudDomainStatusFormat(virConnectPtr conn,
+                        virDomainObjPtr vm)
+{
+    char *config_xml = NULL, *xml = NULL;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferVSprintf(&buf, "<domstatus state='%d' pid='%d'>\n", vm->state, vm->pid);
+    virBufferEscapeString(&buf, "  <monitor path='%s'/>\n", vm->monitorpath);
+
+    if (!(config_xml = virDomainDefFormat(conn,
+                                          vm->def,
+                                          VIR_DOMAIN_XML_SECURE)))
+        goto cleanup;
+
+    virBufferAdd(&buf, config_xml, strlen(config_xml));
+    virBufferAddLit(&buf, "</domstatus>\n");
+
+    xml = virBufferContentAndReset(&buf);
+cleanup:
+    VIR_FREE(config_xml);
+    return xml;
+}
+
+
+/**
+ * qemudSaveDomainStatus
+ *
+ * Save the current status of a running domain
+ *
+ * Returns 0 on success
+ */
+int
+qemudSaveDomainStatus(virConnectPtr conn,
+                      struct qemud_driver *driver,
+                      virDomainObjPtr vm)
+{
+    int ret = -1;
+    char *xml = NULL;
+
+    if (!(xml = qemudDomainStatusFormat(conn, vm)))
+        goto cleanup;
+
+    if ((ret = virDomainSaveXML(conn, driver->stateDir, vm->def, xml)))
+        goto cleanup;
+
+    ret = 0;
+cleanup:
+    VIR_FREE(xml);
+    return ret;
+}
+
index ffbd0e7921f0ac33aae0e9c58645dbb9cd00a82f..70d9394e38603b63378e6c608b7fb3bb2bed878a 100644 (file)
@@ -77,6 +77,16 @@ struct qemud_driver {
     int domainEventDispatching;
 };
 
+/* Status needed to reconenct to running VMs */
+typedef struct _qemudDomainStatus qemudDomainStatus;
+typedef qemudDomainStatus *qemudDomainStatusPtr;
+struct _qemudDomainStatus {
+    char *monitorpath;
+    pid_t pid;
+    int state;
+    virDomainDefPtr def;
+};
+
 /* Port numbers used for KVM migration. */
 #define QEMUD_MIGRATION_FIRST_PORT 49152
 #define QEMUD_MIGRATION_NUM_PORTS 64
@@ -108,5 +118,12 @@ int         qemudBuildCommandLine       (virConnectPtr conn,
                                          const char *migrateFrom);
 
 const char *qemudVirtTypeToString       (int type);
+qemudDomainStatusPtr qemudDomainStatusParseFile(virConnectPtr conn,
+                                                virCapsPtr caps,
+                                                const char *filename,
+                                                int flags);
+int qemudSaveDomainStatus(virConnectPtr conn,
+                          struct qemud_driver *driver,
+                          virDomainObjPtr vm);
 
 #endif /* __QEMUD_CONF_H */