Functions to read and write vm status in $(statedir)/qemu/<domain>.xml.
Keeps the necessary to reconnect to a running domain state within
<domstate>...</domstate>. I kept most of the code in qemu_config.c for
now. We can easily move it should another hypervisor need to do
something similar.
---
src/domain_conf.c | 36 ++++++---
src/domain_conf.h | 6 ++
src/libvirt_sym.version.in | 2 +
src/qemu_conf.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
src/qemu_conf.h | 17 ++++
5 files changed, 241 insertions(+), 11 deletions(-)
diff --git a/src/domain_conf.c b/src/domain_conf.c
index 32ed59f..1b53c09 100644
--- a/src/domain_conf.c
+++ b/src/domain_conf.c
@@ -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);
@@ -3224,11 +3225,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;
@@ -3237,11 +3238,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"),
@@ -3274,12 +3270,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;
}
diff --git a/src/domain_conf.h b/src/domain_conf.h
index 51cf6d5..d44e2ad 100644
--- a/src/domain_conf.h
+++ b/src/domain_conf.h
@@ -462,6 +462,7 @@ struct _virDomainObj {
int stderr_fd;
int stderr_watch;
int monitor;
+ char *monitorpath;
int monitorWatch;
int logfile;
int pid;
@@ -553,6 +554,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);
diff --git a/src/libvirt_sym.version.in b/src/libvirt_sym.version.in
index 1eff790..e7b352d 100644
--- a/src/libvirt_sym.version.in
+++ b/src/libvirt_sym.version.in
@@ -368,6 +368,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
virDomainObjFree;
virDomainObjListFree;
virDomainRemoveInactive;
+ virDomainSaveXML;
virDomainSaveConfig;
virDomainSoundDefFree;
virDomainSoundModelTypeFromString;
@@ -614,6 +615,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
/* xml.h */
virXPathLong;
+ virXPathNode;
virXPathNodeSet;
virXPathString;
virXMLPropString;
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 218aefa..4cede63 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -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,
@@ -1335,3 +1337,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);
+ virBufferVSprintf(&buf, " <monitor path='%s'/>\n",
vm->monitorpath);
+
+ if (!(config_xml = virDomainDefFormat(conn,
+ vm->def,
+ VIR_DOMAIN_XML_SECURE)))
+ goto cleanup;
+
+ virBufferVSprintf(&buf, "%s", config_xml);
+ virBufferVSprintf(&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;
+}
+
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index ffbd0e7..70d9394 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -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 */
--
1.6.0.2