
On Wed, Apr 21, 2010 at 12:01:18PM -0400, Chris Lalancette wrote:
Implement the qemu hooks for XML namespace data. This allows us to specify a qemu XML namespace, and then specify:
<qemu:commandline> <qemu:arg>arg</qemu:arg> <qemu:env name='name' value='value'/> </qemu:commandline>
Now I see it, it looks a little odd to use the element content for qemu:arg, while having an element attributes for qemu:env. Since changing qemu:env to use content isn't practical, I think we could do this instead <qemu:arg value='blah'/>
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index b2820f0..ab0a4a4 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -158,6 +158,17 @@ struct qemud_driver { typedef struct _qemuDomainPCIAddressSet qemuDomainPCIAddressSet; typedef qemuDomainPCIAddressSet *qemuDomainPCIAddressSetPtr;
+typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef; +typedef qemuDomainCmdlineDef *qemuDomainCmdlineDefPtr; +struct _qemuDomainCmdlineDef { + unsigned int num_extra; + char **extra;
Lets call these 'num_args' and 'args' instead.
+ + unsigned int num_env; + char **env_name; + char **env_value; +}; + /* Port numbers used for KVM migration. */ # define QEMUD_MIGRATION_FIRST_PORT 49152 # define QEMUD_MIGRATION_NUM_PORTS 64 diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5f4adfd..0b297a7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -47,6 +47,8 @@ #include <sys/ioctl.h> #include <sys/un.h>
+#include <libxml/xpathInternals.h> + #ifdef __linux__ # include <sys/vfs.h> # ifndef NFS_SUPER_MAGIC @@ -88,6 +90,9 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
+#define QEMU_NAMESPACE_HREF "http://libvirt.org/schemas/domain/qemu/1.0" + + /* Only 1 job is allowed at any time * A job includes *all* monitor commands, even those just querying * information, not merely actions */ @@ -526,6 +531,144 @@ static void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, virD } }
+static void qemuDomainDefNamespaceFree(void *nsdata) +{ + qemuDomainCmdlineDefPtr cmd = nsdata; + int i; + + if (!cmd) + return; + + for (i = 0; i < cmd->num_extra; i++) + VIR_FREE(cmd->extra[i]); + for (i = 0; i < cmd->num_env; i++) { + VIR_FREE(cmd->env_name[i]); + VIR_FREE(cmd->env_value[i]); + } + VIR_FREE(cmd->extra); + VIR_FREE(cmd->env_name); + VIR_FREE(cmd->env_value); + VIR_FREE(cmd); +} + +static int qemuDomainDefNamespaceParse(xmlDocPtr xml, + xmlNodePtr root, + xmlXPathContextPtr ctxt, + void **data) +{ + qemuDomainCmdlineDefPtr cmd = NULL; + xmlNsPtr ns; + xmlNodePtr *nodes = NULL; + int n, i; + xmlNodePtr oldnode; + + ns = xmlSearchNs(xml, root, BAD_CAST "qemu"); + if (!ns) + /* this is fine; it just means there was no qemu namespace listed */ + return 0; + + if (STRNEQ((const char *)ns->href, QEMU_NAMESPACE_HREF)) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("Found namespace '%s' doesn't match expected '%s'"), + ns->href, QEMU_NAMESPACE_HREF); + return -1; + } + + if (xmlXPathRegisterNs(ctxt, ns->prefix, ns->href) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to register xml namespace '%s'"), ns->href); + return -1; + } + + if (VIR_ALLOC(cmd) < 0) { + virReportOOMError(); + return -1; + } + + /* first handle the extra command-line arguments */ + n = virXPathNodeSet("./qemu:commandline/qemu:arg", ctxt, &nodes); + if (n < 0) + /* virXPathNodeSet already set the error */ + goto error; + + if (n && VIR_ALLOC_N(cmd->extra, n) < 0) { + virReportOOMError(); + goto error; + } + + for (i = 0; i < n; i++) { + oldnode = ctxt->node; + ctxt->node = nodes[i]; + cmd->extra[cmd->num_extra] = virXPathString("string(.)", ctxt); + if (cmd->extra[cmd->num_extra] == NULL) + goto error; + cmd->num_extra++; + ctxt->node = oldnode; + } + + /* now handle the extra environment variables */ + n = virXPathNodeSet("./qemu:commandline/qemu:env", ctxt, &nodes); + if (n < 0) + /* virXPathNodeSet already set the error */ + goto error; + + if (n && VIR_ALLOC_N(cmd->env_name, n) < 0) { + virReportOOMError(); + goto error; + } + + if (n && VIR_ALLOC_N(cmd->env_value, n) < 0) { + virReportOOMError(); + goto error; + } + + for (i = 0; i < n; i++) { + oldnode = ctxt->node; + ctxt->node = nodes[i]; + cmd->env_name[cmd->num_env] = virXPathString("string(./@name)", ctxt); + if (cmd->env_name[cmd->num_env] == NULL) + goto error; + cmd->env_value[cmd->num_env] = virXPathString("string(./@value)", ctxt); + /* a NULL value for command is allowed, since it might be empty */ + cmd->num_env++; + ctxt->node = oldnode; + }
Using xpath for getting immediate attributes is somewhat overkill. You can just avoid touching ctxt at all, and use virXMLPropString(nodes[i], "name"); virXMLPropString(nodes[i], "value");
+static int qemuDomainDefNamespaceFormatXML(virBufferPtr buf, + void *nsdata) +{ + qemuDomainCmdlineDefPtr cmd = nsdata; + int i; + + if (cmd->num_extra || cmd->num_env) + virBufferAddLit(buf, " <qemu:commandline>\n"); + for (i = 0; i < cmd->num_extra; i++) + virBufferVSprintf(buf, " <qemu:arg>%s</qemu:arg>\n", cmd->extra[i]); + for (i = 0; i < cmd->num_env; i++) { + virBufferVSprintf(buf, " <qemu:env name='%s'", cmd->env_name[i]); + if (cmd->env_value[i]) + virBufferVSprintf(buf, " value='%s'", cmd->env_value[i]); + virBufferAddLit(buf, "/>\n"); + }
Should use escaping for all the attributes here
+ if (cmd->num_extra || cmd->num_env) + virBufferAddLit(buf, " </qemu:commandline>\n"); + + return 0; +} + +static const char *qemuDomainDefNamespaceHref(void) +{ + return "xmlns:qemu='" QEMU_NAMESPACE_HREF "'"; +}
static int qemuCgroupControllerActive(struct qemud_driver *driver, int controller) @@ -1316,6 +1459,14 @@ qemuCreateCapabilities(virCapsPtr oldcaps, caps->privateDataXMLFormat = qemuDomainObjPrivateXMLFormat; caps->privateDataXMLParse = qemuDomainObjPrivateXMLParse;
+ /* Domain Namespace XML parser hooks */ + if (VIR_ALLOC(caps->ns) < 0) + goto no_memory; + + caps->ns->parse = qemuDomainDefNamespaceParse; + caps->ns->free = qemuDomainDefNamespaceFree; + caps->ns->format = qemuDomainDefNamespaceFormatXML; + caps->ns->href = qemuDomainDefNamespaceHref;
Could avoid needing to allocate this, by just statically declaring the callback table. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|