From d8dbd611077149fea50f417a292bf3c9b0f3f07f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 21 May 2009 14:14:01 +0000 Subject: [PATCH] Basic domain XML conversions for Xen/QEMU drivers --- ChangeLog | 8 +++ src/qemu_conf.c | 25 ++++----- src/qemu_conf.h | 3 ++ src/qemu_driver.c | 129 +++++++++++++++++++++++++++++++++++++++++++++- src/xen_unified.c | 95 +++++++++++++++++++++++++++++++++- src/xen_unified.h | 3 ++ 6 files changed, 246 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc31a9fc1c..72b6b93dc4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Thu May 21 14:59:22 BST 2009 Daniel P. Berrange + + Basic domain XML conversions + * src/qemu_conf.c, src/qemu_conf.h, src/qemu_driver.c: Wire up + API for conversion from XML to native argv + * src/xen_unified.c, src/xen_unified.h: Wire up API for domain + XML conversions to & from native + Thu May 21 14:48:22 BST 2009 Daniel P. Berrange Remote protocol support for domain XML conversion APIs diff --git a/src/qemu_conf.c b/src/qemu_conf.c index bfaab33c8c..d7b5d3258b 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -1251,21 +1251,18 @@ int qemudBuildCommandLine(virConnectPtr conn, 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 --git a/src/qemu_conf.h b/src/qemu_conf.h index c6dc9dfba9..d7e262e082 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -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 --git a/src/qemu_driver.c b/src/qemu_driver.c index 2cac1bf08f..c2b4c1ab5c 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -3422,6 +3422,133 @@ 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); + + memset(net, 0, sizeof *net); + + 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) { + char *brname = net->data.bridge.brname; + char *script = net->data.bridge.script; + char *ipaddr = net->data.bridge.ipaddr; + + memset(net, 0, sizeof *net); + + net->type = VIR_DOMAIN_NET_TYPE_ETHERNET; + net->data.ethernet.dev = brname; + net->data.ethernet.script = script; + net->data.ethernet.ipaddr = ipaddr; + } + } + 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; @@ -5225,7 +5352,7 @@ static virDriver qemuDriver = { qemudNodeGetSecurityModel, /* nodeGetSecurityModel */ qemudDomainDumpXML, /* domainDumpXML */ NULL, /* domainXmlFromNative */ - NULL, /* domainXmlToNative */ + qemuDomainXMLToNative, /* domainXMLToNative */ qemudListDefinedDomains, /* listDefinedDomains */ qemudNumDefinedDomains, /* numOfDefinedDomains */ qemudDomainStart, /* domainCreate */ diff --git a/src/xen_unified.c b/src/xen_unified.c index bd363ffe3b..7ff23b8216 100644 --- a/src/xen_unified.c +++ b/src/xen_unified.c @@ -1043,6 +1043,97 @@ xenUnifiedDomainDumpXML (virDomainPtr dom, int flags) 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 --git a/src/xen_unified.h b/src/xen_unified.h index 6ec19c19ba..9cc877b03a 100644 --- a/src/xen_unified.h +++ b/src/xen_unified.h @@ -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