From ed2a10a1c5863e59396375d8465c16f671c87a7f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 23 Sep 2009 15:23:47 +0100 Subject: [PATCH] Add API for issuing 'migrate' command with exec protocol * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorMigrateToCommand() API * src/qemu/qemu_driver.c: Switch over to using the qemuMonitorMigrateToCommand() API for core dumps and save to file APIs --- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 118 +++++++---------------------------- src/qemu/qemu_monitor_text.c | 63 +++++++++++++++++-- src/qemu/qemu_monitor_text.h | 4 ++ 4 files changed, 86 insertions(+), 100 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a6668f3171..f8598c7649 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -453,6 +453,7 @@ virGetGroupID; virFileFindMountPoint; virFileWaitForDevices; virFileMatchesNameSuffix; +virArgvToString; # usb.h diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d8ba9d1ba6..ef509c93e2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3170,11 +3170,6 @@ static char *qemudEscapeMonitorArg(const char *in) return qemudEscape(in, 0); } -static char *qemudEscapeShellArg(const char *in) -{ - return qemudEscape(in, 1); -} - #define QEMUD_SAVE_MAGIC "LibvirtQemudSave" #define QEMUD_SAVE_VERSION 2 @@ -3217,15 +3212,11 @@ static int qemudDomainSave(virDomainPtr dom, { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm = NULL; - char *command = NULL; - char *info = NULL; int fd = -1; - char *safe_path = NULL; char *xml = NULL; struct qemud_save_header header; int ret = -1; virDomainEventPtr event = NULL; - int internalret; memset(&header, 0, sizeof(header)); memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)); @@ -3305,55 +3296,21 @@ static int qemudDomainSave(virDomainPtr dom, } fd = -1; - /* Migrate to file */ - safe_path = qemudEscapeShellArg(path); - if (!safe_path) { - virReportOOMError(dom->conn); - goto cleanup; - } - - { + if (header.compressed == QEMUD_SAVE_FORMAT_RAW) { + const char *args[] = { "cat", NULL }; + ret = qemuMonitorMigrateToCommand(vm, args, path); + } else { const char *prog = qemudSaveCompressionTypeToString(header.compressed); - const char *args; - - if (prog == NULL) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid compress format %d"), header.compressed); - goto cleanup; - } - - if (STREQ (prog, "raw")) { - prog = "cat"; - args = ""; - } else { - args = "-c"; - } - internalret = virAsprintf(&command, "migrate \"exec:" - "%s %s >> '%s' 2>/dev/null\"", prog, args, - safe_path); + const char *args[] = { + prog, + "-c", + NULL + }; + ret = qemuMonitorMigrateToCommand(vm, args, path); } - if (internalret < 0) { - virReportOOMError(dom->conn); + if (ret < 0) goto cleanup; - } - - if (qemudMonitorCommand(vm, command, &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); - goto cleanup; - } - - DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* If the command isn't supported then qemu prints: - * unknown command: migrate" */ - if (strstr(info, "unknown command:")) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("'migrate' not supported by this qemu")); - goto cleanup; - } /* Shut it down */ qemudShutdownVMDaemon(dom->conn, driver, vm); @@ -3365,15 +3322,11 @@ static int qemudDomainSave(virDomainPtr dom, vm); vm = NULL; } - ret = 0; cleanup: if (fd != -1) close(fd); VIR_FREE(xml); - VIR_FREE(safe_path); - VIR_FREE(command); - VIR_FREE(info); if (ret != 0) unlink(path); if (vm) @@ -3390,11 +3343,12 @@ static int qemudDomainCoreDump(virDomainPtr dom, int flags ATTRIBUTE_UNUSED) { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; - char *command = NULL; - char *info = NULL; - char *safe_path = NULL; int resume = 0, paused = 0; int ret = -1; + const char *args[] = { + "cat", + NULL, + }; qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -3426,43 +3380,9 @@ static int qemudDomainCoreDump(virDomainPtr dom, paused = 1; } - /* Migrate to file */ - safe_path = qemudEscapeShellArg(path); - if (!safe_path) { - virReportOOMError(dom->conn); - goto cleanup; - } - if (virAsprintf(&command, "migrate \"exec:" - "dd of='%s' 2>/dev/null" - "\"", safe_path) == -1) { - virReportOOMError(dom->conn); - command = NULL; - goto cleanup; - } - - if (qemudMonitorCommand(vm, command, &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); - goto cleanup; - } - - DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* If the command isn't supported then qemu prints: - * unknown command: migrate" */ - if (strstr(info, "unknown command:")) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("'migrate' not supported by this qemu")); - goto cleanup; - } - + ret = qemuMonitorMigrateToCommand(vm, args, path); paused = 1; - ret = 0; cleanup: - VIR_FREE(safe_path); - VIR_FREE(command); - VIR_FREE(info); /* Since the monitor is always attached to a pty for libvirt, it will support synchronous operations so we always get here after @@ -6369,6 +6289,11 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn, goto cleanup; } + /* XXX this really should have been a properly well-formed + * URI, but we can't add in tcp:// now without breaking + * compatability with old targets. We at least make the + * new targets accept both syntaxes though. + */ /* Caller frees */ internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port); VIR_FREE(hostname); @@ -6535,6 +6460,7 @@ qemudDomainMigratePerform (virDomainPtr dom, /* Issue the migrate command. */ if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) { + /* HACK: source host generates bogus URIs, so fix them up */ char *tmpuri; if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) { virReportOOMError(dom->conn); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index eadabc5faf..78b5dfec6c 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -118,6 +118,10 @@ static char *qemudEscapeMonitorArg(const char *in) return qemudEscape(in, 0); } +static char *qemudEscapeShellArg(const char *in) +{ + return qemudEscape(in, 1); +} /* Throw away any data available on the monitor * This is done before executing a command, in order @@ -1096,12 +1100,18 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, char *cmd = NULL; char *info = NULL; int ret = -1; + char *safedest = qemudEscapeMonitorArg(dest); - if (virAsprintf(&cmd, "migrate %s", dest) < 0) { + if (!safedest) { virReportOOMError(NULL); return -1; } + if (virAsprintf(&cmd, "migrate \"%s\"", safedest) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + if (qemudMonitorCommand(vm, cmd, &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("unable to start migration to %s"), dest); @@ -1112,8 +1122,15 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, /* Now check for "fail" in the output string */ if (strstr(info, "fail") != NULL) { - qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("migration to '%s' failed: %s"), dest, info); + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("migration to '%s' failed: %s"), dest, info); + goto cleanup; + } + /* If the command isn't supported then qemu prints: + * unknown command: migrate" */ + if (strstr(info, "unknown command:")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, + _("migration to '%s' not supported by this qemu: %s"), dest, info); goto cleanup; } @@ -1121,6 +1138,7 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, ret = 0; cleanup: + VIR_FREE(safedest); VIR_FREE(info); VIR_FREE(cmd); return ret; @@ -1130,7 +1148,7 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, const char *hostname, int port) { - char *uri; + char *uri = NULL; int ret; if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) { @@ -1144,3 +1162,40 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, return ret; } + + +int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, + const char * const *argv, + const char *target) +{ + char *argstr; + char *dest = NULL; + int ret = -1; + char *safe_target = NULL; + + argstr = virArgvToString(argv); + if (!argstr) { + virReportOOMError(NULL); + goto cleanup; + } + + /* Migrate to file */ + safe_target = qemudEscapeShellArg(target); + if (!safe_target) { + virReportOOMError(NULL); + goto cleanup; + } + + if (virAsprintf(&dest, "exec:%s >>%s 2>/dev/null", argstr, safe_target) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + ret = qemuMonitorMigrate(vm, dest); + +cleanup: + VIR_FREE(safe_target); + VIR_FREE(argstr); + VIR_FREE(dest); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index d6f8fd2d94..b43b410974 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -132,4 +132,8 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, const char *hostname, int port); +int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, + const char * const *argv, + const char *target); + #endif /* QEMU_MONITOR_TEXT_H */