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 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list