This patches provides an implenmentation of the new APIs for Xen which
can convert to/from both XM config format (/etc/xen files), and the
SEXPR format used by XenD. The former is most useful to end users, but
it was easy to add the latter too, so I did. It can be a useful debugging
aid sometimes. For QEMU, it implemnets export of domain XML into the
QEMU argv format.
qemu_conf.c | 25 +++++-------
qemu_conf.h | 3 +
qemu_driver.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
xen_unified.c | 95 +++++++++++++++++++++++++++++++++++++++++++++-
xen_unified.h | 3 +
5 files changed, 228 insertions(+), 17 deletions(-)
Daniel
diff -r f55fa9b69d85 src/qemu_conf.c
--- a/src/qemu_conf.c Wed May 13 13:13:18 2009 +0100
+++ b/src/qemu_conf.c Wed May 13 13:16:50 2009 +0100
@@ -1248,21 +1248,18 @@ int qemudBuildCommandLine(virConnectPtr
case VIR_DOMAIN_NET_TYPE_ETHERNET:
{
- char arg[PATH_MAX];
- if (net->ifname) {
- if (snprintf(arg, PATH_MAX-1,
"tap,ifname=%s,script=%s,vlan=%d",
- net->ifname,
- net->data.ethernet.script,
- vlan) >= (PATH_MAX-1))
- goto error;
- } else {
- if (snprintf(arg, PATH_MAX-1, "tap,script=%s,vlan=%d",
- net->data.ethernet.script,
- vlan) >= (PATH_MAX-1))
- goto error;
- }
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
- ADD_ARG_LIT(arg);
+ virBufferAddLit(&buf, "tap");
+ if (net->ifname)
+ virBufferVSprintf(&buf, ",ifname=%s",
net->ifname);
+ if (net->data.ethernet.script)
+ virBufferVSprintf(&buf, ",script=%s",
net->data.ethernet.script);
+ virBufferVSprintf(&buf, ",vlan=%d", vlan);
+ if (virBufferError(&buf))
+ goto error;
+
+ ADD_ARG(virBufferContentAndReset(&buf));
}
break;
diff -r f55fa9b69d85 src/qemu_conf.h
--- a/src/qemu_conf.h Wed May 13 13:13:18 2009 +0100
+++ b/src/qemu_conf.h Wed May 13 13:16:50 2009 +0100
@@ -106,6 +106,9 @@ struct _qemudDomainStatus {
#define QEMUD_MIGRATION_FIRST_PORT 49152
#define QEMUD_MIGRATION_NUM_PORTS 64
+/* Config type for XML import/export conversions */
+#define QEMU_CONFIG_FORMAT_ARGV "qemu-argv"
+
#define qemudReportError(conn, dom, net, code, fmt...) \
virReportErrorHelper(conn, VIR_FROM_QEMU, code, __FILE__, \
__FUNCTION__, __LINE__, fmt)
diff -r f55fa9b69d85 src/qemu_driver.c
--- a/src/qemu_driver.c Wed May 13 13:13:18 2009 +0100
+++ b/src/qemu_driver.c Wed May 13 13:16:50 2009 +0100
@@ -3423,6 +3423,123 @@ cleanup:
}
+static char *qemuDomainXMLToNative(virConnectPtr conn,
+ const char *format,
+ const char *xmlData,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ struct qemud_driver *driver = conn->privateData;
+ virDomainDefPtr def = NULL;
+ const char *emulator;
+ unsigned int qemuCmdFlags;
+ struct stat sb;
+ const char **retargv = NULL;
+ const char **retenv = NULL;
+ const char **tmp;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *ret = NULL;
+ int i;
+
+ if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
+ _("unsupported config type %s"), format);
+ goto cleanup;
+ }
+
+ def = virDomainDefParseString(conn, driver->caps, xmlData, 0);
+ if (!def)
+ goto cleanup;
+
+ /* Since we're just exporting args, we can't do bridge/network
+ * setups, since libvirt will normally create TAP devices
+ * directly. We convert those configs into generic 'ethernet'
+ * config and assume the user has suitable 'ifup-qemu' scripts
+ */
+ for (i = 0 ; i < def->nnets ; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
+ VIR_FREE(net->data.network.name);
+ net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+ net->data.ethernet.dev = NULL;
+ net->data.ethernet.script = NULL;
+ net->data.ethernet.ipaddr = NULL;
+ } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+ /* Rely on fact that the 'ethernet' and 'bridge'
+ * union structs have members in same place */
+ }
+ }
+ for (i = 0 ; i < def->ngraphics ; i++) {
+ if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
+ def->graphics[i]->data.vnc.autoport)
+ def->graphics[i]->data.vnc.port = 5900;
+ }
+ emulator = def->emulator;
+ if (!emulator)
+ emulator = virDomainDefDefaultEmulator(conn, def, driver->caps);
+ if (!emulator)
+ goto cleanup;
+
+ /* Make sure the binary we are about to try exec'ing exists.
+ * Technically we could catch the exec() failure, but that's
+ * in a sub-process so its hard to feed back a useful error
+ */
+ if (stat(emulator, &sb) < 0) {
+ virReportSystemError(conn, errno,
+ _("Cannot find QEMU binary %s"),
+ emulator);
+ goto cleanup;
+ }
+
+ if (qemudExtractVersionInfo(emulator,
+ NULL,
+ &qemuCmdFlags) < 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Cannot determine QEMU argv syntax %s"),
+ emulator);
+ goto cleanup;
+ }
+
+
+ if (qemudBuildCommandLine(conn, driver, def,
+ qemuCmdFlags,
+ &retargv, &retenv,
+ NULL, NULL, /* Don't want it to create TAP devices */
+ NULL) < 0) {
+ goto cleanup;
+ }
+
+ tmp = retenv;
+ while (*tmp) {
+ virBufferAdd(&buf, *tmp, strlen(*tmp));
+ virBufferAddLit(&buf, " ");
+ tmp++;
+ }
+ tmp = retargv;
+ while (*tmp) {
+ virBufferAdd(&buf, *tmp, strlen(*tmp));
+ virBufferAddLit(&buf, " ");
+ tmp++;
+ }
+
+ if (virBufferError(&buf))
+ goto cleanup;
+
+ ret = virBufferContentAndReset(&buf);
+
+cleanup:
+ for (tmp = retargv ; tmp && *tmp ; tmp++)
+ VIR_FREE(*tmp);
+ VIR_FREE(retargv);
+
+ for (tmp = retenv ; tmp && *tmp ; tmp++)
+ VIR_FREE(*tmp);
+ VIR_FREE(retenv);
+
+ virDomainDefFree(def);
+ return ret;
+}
+
+
static int qemudListDefinedDomains(virConnectPtr conn,
char **const names, int nnames) {
struct qemud_driver *driver = conn->privateData;
@@ -5232,7 +5349,7 @@ static virDriver qemuDriver = {
qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
qemudDomainDumpXML, /* domainDumpXML */
NULL, /* domainXmlFromNative */
- NULL, /* domainXmlToNative */
+ qemuDomainXMLToNative, /* domainXMLToNative */
qemudListDefinedDomains, /* listDefinedDomains */
qemudNumDefinedDomains, /* numOfDefinedDomains */
qemudDomainStart, /* domainCreate */
diff -r f55fa9b69d85 src/xen_unified.c
--- a/src/xen_unified.c Wed May 13 13:13:18 2009 +0100
+++ b/src/xen_unified.c Wed May 13 13:16:50 2009 +0100
@@ -1043,6 +1043,97 @@ xenUnifiedDomainDumpXML (virDomainPtr do
return NULL;
}
+
+static char *
+xenUnifiedDomainXMLFromNative(virConnectPtr conn,
+ const char *format,
+ const char *config,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ virDomainDefPtr def = NULL;
+ char *ret = NULL;
+ virConfPtr conf = NULL;
+ GET_PRIVATE(conn);
+
+ if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
+ STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
+ _("unsupported config type %s"), format);
+ return NULL;
+ }
+
+ if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+ conf = virConfReadMem(config, strlen(config));
+ if (!conf)
+ goto cleanup;
+
+ def = xenXMDomainConfigParse(conn, conf);
+ } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ def = xenDaemonParseSxprString(conn, config, priv->xendConfigVersion);
+ }
+ if (!def)
+ goto cleanup;
+
+ ret = virDomainDefFormat(conn, def, 0);
+
+cleanup:
+ virDomainDefFree(def);
+ return ret;
+}
+
+
+#define MAX_CONFIG_SIZE (1024 * 65)
+static char *
+xenUnifiedDomainXMLToNative(virConnectPtr conn,
+ const char *format,
+ const char *xmlData,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ virDomainDefPtr def = NULL;
+ char *ret = NULL;
+ virConfPtr conf = NULL;
+ GET_PRIVATE(conn);
+
+ if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
+ STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
+ _("unsupported config type %s"), format);
+ goto cleanup;
+ }
+
+ if (!(def = virDomainDefParseString(conn,
+ priv->caps,
+ xmlData,
+ 0)))
+ goto cleanup;
+
+ if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+ int len = MAX_CONFIG_SIZE;
+ conf = xenXMDomainConfigFormat(conn, def);
+ if (!conf)
+ goto cleanup;
+
+ if (VIR_ALLOC_N(ret, len) < 0) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ if (virConfWriteMem(ret, &len, conf) < 0) {
+ VIR_FREE(ret);
+ goto cleanup;
+ }
+ } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ ret = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion);
+ }
+
+cleanup:
+ virDomainDefFree(def);
+ if (conf)
+ virConfFree(conf);
+ return ret;
+}
+
+
static int
xenUnifiedDomainMigratePrepare (virConnectPtr dconn,
char **cookie,
@@ -1580,8 +1671,8 @@ static virDriver xenUnifiedDriver = {
NULL, /* domainGetSecurityLabel */
NULL, /* nodeGetSecurityModel */
xenUnifiedDomainDumpXML, /* domainDumpXML */
- NULL, /* domainXmlFromNative */
- NULL, /* domainXmlToNative */
+ xenUnifiedDomainXMLFromNative, /* domainXmlFromNative */
+ xenUnifiedDomainXMLToNative, /* domainXmlToNative */
xenUnifiedListDefinedDomains, /* listDefinedDomains */
xenUnifiedNumOfDefinedDomains, /* numOfDefinedDomains */
xenUnifiedDomainCreate, /* domainCreate */
diff -r f55fa9b69d85 src/xen_unified.h
--- a/src/xen_unified.h Wed May 13 13:13:18 2009 +0100
+++ b/src/xen_unified.h Wed May 13 13:16:50 2009 +0100
@@ -46,6 +46,9 @@ extern int xenRegister (void);
#define MIN_XEN_GUEST_SIZE 64 /* 64 megabytes */
+#define XEN_CONFIG_FORMAT_XM "xen-xm"
+#define XEN_CONFIG_FORMAT_SEXPR "xen-sxpr"
+
/* _xenUnifiedDriver:
*
* Entry points into the underlying Xen drivers. This structure
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|