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
This commit is contained in:
Daniel P. Berrange 2009-09-23 15:23:47 +01:00
parent 81f3edea8f
commit ed2a10a1c5
4 changed files with 86 additions and 100 deletions

View File

@ -453,6 +453,7 @@ virGetGroupID;
virFileFindMountPoint;
virFileWaitForDevices;
virFileMatchesNameSuffix;
virArgvToString;
# usb.h

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */