mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-26 18:41:17 +00:00
add XML parsing for qemu/kvm status files
This commit is contained in:
parent
f1bd11bf87
commit
b679ebe877
14
ChangeLog
14
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>
|
Fri Dec 19 10:41:00 UTC 2008 Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
|
||||||
* docs/formatdomain.html.in: Fix documentation typo
|
* docs/formatdomain.html.in: Fix documentation typo
|
||||||
|
@ -430,6 +430,7 @@ void virDomainObjFree(virDomainObjPtr dom)
|
|||||||
virDomainDefFree(dom->def);
|
virDomainDefFree(dom->def);
|
||||||
virDomainDefFree(dom->newDef);
|
virDomainDefFree(dom->newDef);
|
||||||
|
|
||||||
|
VIR_FREE(dom->monitorpath);
|
||||||
VIR_FREE(dom->vcpupids);
|
VIR_FREE(dom->vcpupids);
|
||||||
|
|
||||||
VIR_FREE(dom);
|
VIR_FREE(dom);
|
||||||
@ -3243,11 +3244,11 @@ char *virDomainDefFormat(virConnectPtr conn,
|
|||||||
|
|
||||||
#ifndef PROXY
|
#ifndef PROXY
|
||||||
|
|
||||||
int virDomainSaveConfig(virConnectPtr conn,
|
int virDomainSaveXML(virConnectPtr conn,
|
||||||
const char *configDir,
|
const char *configDir,
|
||||||
virDomainDefPtr def)
|
virDomainDefPtr def,
|
||||||
|
const char *xml)
|
||||||
{
|
{
|
||||||
char *xml;
|
|
||||||
char *configFile = NULL;
|
char *configFile = NULL;
|
||||||
int fd = -1, ret = -1;
|
int fd = -1, ret = -1;
|
||||||
size_t towrite;
|
size_t towrite;
|
||||||
@ -3256,11 +3257,6 @@ int virDomainSaveConfig(virConnectPtr conn,
|
|||||||
if ((configFile = virDomainConfigFile(conn, configDir, def->name)) == NULL)
|
if ((configFile = virDomainConfigFile(conn, configDir, def->name)) == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (!(xml = virDomainDefFormat(conn,
|
|
||||||
def,
|
|
||||||
VIR_DOMAIN_XML_SECURE)))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if ((err = virFileMakePath(configDir))) {
|
if ((err = virFileMakePath(configDir))) {
|
||||||
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
_("cannot create config directory %s: %s"),
|
_("cannot create config directory %s: %s"),
|
||||||
@ -3293,12 +3289,30 @@ int virDomainSaveConfig(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(xml);
|
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
close(fd);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,6 +464,7 @@ struct _virDomainObj {
|
|||||||
int stderr_fd;
|
int stderr_fd;
|
||||||
int stderr_watch;
|
int stderr_watch;
|
||||||
int monitor;
|
int monitor;
|
||||||
|
char *monitorpath;
|
||||||
int monitorWatch;
|
int monitorWatch;
|
||||||
int logfile;
|
int logfile;
|
||||||
int pid;
|
int pid;
|
||||||
@ -555,6 +556,11 @@ int virDomainDiskQSort(const void *a, const void *b);
|
|||||||
int virDomainDiskCompare(virDomainDiskDefPtr a,
|
int virDomainDiskCompare(virDomainDiskDefPtr a,
|
||||||
virDomainDiskDefPtr b);
|
virDomainDiskDefPtr b);
|
||||||
|
|
||||||
|
int virDomainSaveXML(virConnectPtr conn,
|
||||||
|
const char *configDir,
|
||||||
|
virDomainDefPtr def,
|
||||||
|
const char *xml);
|
||||||
|
|
||||||
int virDomainSaveConfig(virConnectPtr conn,
|
int virDomainSaveConfig(virConnectPtr conn,
|
||||||
const char *configDir,
|
const char *configDir,
|
||||||
virDomainDefPtr def);
|
virDomainDefPtr def);
|
||||||
|
@ -281,6 +281,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
|
|
||||||
# buf.h
|
# buf.h
|
||||||
virBufferVSprintf;
|
virBufferVSprintf;
|
||||||
|
virBufferEscapeString;
|
||||||
virBufferAdd;
|
virBufferAdd;
|
||||||
virBufferAddChar;
|
virBufferAddChar;
|
||||||
virBufferContentAndReset;
|
virBufferContentAndReset;
|
||||||
@ -360,6 +361,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
virDomainObjFree;
|
virDomainObjFree;
|
||||||
virDomainObjListFree;
|
virDomainObjListFree;
|
||||||
virDomainRemoveInactive;
|
virDomainRemoveInactive;
|
||||||
|
virDomainSaveXML;
|
||||||
virDomainSaveConfig;
|
virDomainSaveConfig;
|
||||||
virDomainSoundDefFree;
|
virDomainSoundDefFree;
|
||||||
virDomainSoundModelTypeFromString;
|
virDomainSoundModelTypeFromString;
|
||||||
@ -601,6 +603,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
|
|
||||||
# xml.h
|
# xml.h
|
||||||
virXPathLong;
|
virXPathLong;
|
||||||
|
virXPathNode;
|
||||||
virXPathNodeSet;
|
virXPathNodeSet;
|
||||||
virXPathString;
|
virXPathString;
|
||||||
virXMLPropString;
|
virXMLPropString;
|
||||||
|
191
src/qemu_conf.c
191
src/qemu_conf.c
@ -49,6 +49,8 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "verify.h"
|
#include "verify.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "xml.h"
|
||||||
|
|
||||||
VIR_ENUM_DECL(virDomainDiskQEMUBus)
|
VIR_ENUM_DECL(virDomainDiskQEMUBus)
|
||||||
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
|
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
|
||||||
@ -1334,3 +1336,192 @@ int qemudBuildCommandLine(virConnectPtr conn,
|
|||||||
#undef ADD_ENV_LIT
|
#undef ADD_ENV_LIT
|
||||||
#undef ADD_ENV_SPACE
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,16 @@ struct qemud_driver {
|
|||||||
int domainEventDispatching;
|
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. */
|
/* Port numbers used for KVM migration. */
|
||||||
#define QEMUD_MIGRATION_FIRST_PORT 49152
|
#define QEMUD_MIGRATION_FIRST_PORT 49152
|
||||||
#define QEMUD_MIGRATION_NUM_PORTS 64
|
#define QEMUD_MIGRATION_NUM_PORTS 64
|
||||||
@ -108,5 +118,12 @@ int qemudBuildCommandLine (virConnectPtr conn,
|
|||||||
const char *migrateFrom);
|
const char *migrateFrom);
|
||||||
|
|
||||||
const char *qemudVirtTypeToString (int type);
|
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 */
|
#endif /* __QEMUD_CONF_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user