mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
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:
parent
81f3edea8f
commit
ed2a10a1c5
@ -453,6 +453,7 @@ virGetGroupID;
|
|||||||
virFileFindMountPoint;
|
virFileFindMountPoint;
|
||||||
virFileWaitForDevices;
|
virFileWaitForDevices;
|
||||||
virFileMatchesNameSuffix;
|
virFileMatchesNameSuffix;
|
||||||
|
virArgvToString;
|
||||||
|
|
||||||
|
|
||||||
# usb.h
|
# usb.h
|
||||||
|
@ -3170,11 +3170,6 @@ static char *qemudEscapeMonitorArg(const char *in)
|
|||||||
return qemudEscape(in, 0);
|
return qemudEscape(in, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *qemudEscapeShellArg(const char *in)
|
|
||||||
{
|
|
||||||
return qemudEscape(in, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
|
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
|
||||||
#define QEMUD_SAVE_VERSION 2
|
#define QEMUD_SAVE_VERSION 2
|
||||||
|
|
||||||
@ -3217,15 +3212,11 @@ static int qemudDomainSave(virDomainPtr dom,
|
|||||||
{
|
{
|
||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
virDomainObjPtr vm = NULL;
|
virDomainObjPtr vm = NULL;
|
||||||
char *command = NULL;
|
|
||||||
char *info = NULL;
|
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
char *safe_path = NULL;
|
|
||||||
char *xml = NULL;
|
char *xml = NULL;
|
||||||
struct qemud_save_header header;
|
struct qemud_save_header header;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
virDomainEventPtr event = NULL;
|
virDomainEventPtr event = NULL;
|
||||||
int internalret;
|
|
||||||
|
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
|
memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
|
||||||
@ -3305,55 +3296,21 @@ static int qemudDomainSave(virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
fd = -1;
|
fd = -1;
|
||||||
|
|
||||||
/* Migrate to file */
|
if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
|
||||||
safe_path = qemudEscapeShellArg(path);
|
const char *args[] = { "cat", NULL };
|
||||||
if (!safe_path) {
|
ret = qemuMonitorMigrateToCommand(vm, args, path);
|
||||||
virReportOOMError(dom->conn);
|
} else {
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const char *prog = qemudSaveCompressionTypeToString(header.compressed);
|
const char *prog = qemudSaveCompressionTypeToString(header.compressed);
|
||||||
const char *args;
|
const char *args[] = {
|
||||||
|
prog,
|
||||||
if (prog == NULL) {
|
"-c",
|
||||||
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
NULL
|
||||||
_("Invalid compress format %d"), header.compressed);
|
};
|
||||||
goto cleanup;
|
ret = qemuMonitorMigrateToCommand(vm, args, path);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (internalret < 0) {
|
if (ret < 0)
|
||||||
virReportOOMError(dom->conn);
|
|
||||||
goto cleanup;
|
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 */
|
/* Shut it down */
|
||||||
qemudShutdownVMDaemon(dom->conn, driver, vm);
|
qemudShutdownVMDaemon(dom->conn, driver, vm);
|
||||||
@ -3365,15 +3322,11 @@ static int qemudDomainSave(virDomainPtr dom,
|
|||||||
vm);
|
vm);
|
||||||
vm = NULL;
|
vm = NULL;
|
||||||
}
|
}
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
VIR_FREE(xml);
|
VIR_FREE(xml);
|
||||||
VIR_FREE(safe_path);
|
|
||||||
VIR_FREE(command);
|
|
||||||
VIR_FREE(info);
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
unlink(path);
|
unlink(path);
|
||||||
if (vm)
|
if (vm)
|
||||||
@ -3390,11 +3343,12 @@ static int qemudDomainCoreDump(virDomainPtr dom,
|
|||||||
int flags ATTRIBUTE_UNUSED) {
|
int flags ATTRIBUTE_UNUSED) {
|
||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
char *command = NULL;
|
|
||||||
char *info = NULL;
|
|
||||||
char *safe_path = NULL;
|
|
||||||
int resume = 0, paused = 0;
|
int resume = 0, paused = 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
const char *args[] = {
|
||||||
|
"cat",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
||||||
@ -3426,43 +3380,9 @@ static int qemudDomainCoreDump(virDomainPtr dom,
|
|||||||
paused = 1;
|
paused = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Migrate to file */
|
ret = qemuMonitorMigrateToCommand(vm, args, path);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
paused = 1;
|
paused = 1;
|
||||||
ret = 0;
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(safe_path);
|
|
||||||
VIR_FREE(command);
|
|
||||||
VIR_FREE(info);
|
|
||||||
|
|
||||||
/* Since the monitor is always attached to a pty for libvirt, it
|
/* Since the monitor is always attached to a pty for libvirt, it
|
||||||
will support synchronous operations so we always get here after
|
will support synchronous operations so we always get here after
|
||||||
@ -6369,6 +6289,11 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
|
|||||||
goto cleanup;
|
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 */
|
/* Caller frees */
|
||||||
internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
|
internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
|
||||||
VIR_FREE(hostname);
|
VIR_FREE(hostname);
|
||||||
@ -6535,6 +6460,7 @@ qemudDomainMigratePerform (virDomainPtr dom,
|
|||||||
|
|
||||||
/* Issue the migrate command. */
|
/* Issue the migrate command. */
|
||||||
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
|
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
|
||||||
|
/* HACK: source host generates bogus URIs, so fix them up */
|
||||||
char *tmpuri;
|
char *tmpuri;
|
||||||
if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) {
|
if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) {
|
||||||
virReportOOMError(dom->conn);
|
virReportOOMError(dom->conn);
|
||||||
|
@ -118,6 +118,10 @@ static char *qemudEscapeMonitorArg(const char *in)
|
|||||||
return qemudEscape(in, 0);
|
return qemudEscape(in, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *qemudEscapeShellArg(const char *in)
|
||||||
|
{
|
||||||
|
return qemudEscape(in, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Throw away any data available on the monitor
|
/* Throw away any data available on the monitor
|
||||||
* This is done before executing a command, in order
|
* This is done before executing a command, in order
|
||||||
@ -1096,12 +1100,18 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm,
|
|||||||
char *cmd = NULL;
|
char *cmd = NULL;
|
||||||
char *info = NULL;
|
char *info = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
char *safedest = qemudEscapeMonitorArg(dest);
|
||||||
|
|
||||||
if (virAsprintf(&cmd, "migrate %s", dest) < 0) {
|
if (!safedest) {
|
||||||
virReportOOMError(NULL);
|
virReportOOMError(NULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virAsprintf(&cmd, "migrate \"%s\"", safedest) < 0) {
|
||||||
|
virReportOOMError(NULL);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (qemudMonitorCommand(vm, cmd, &info) < 0) {
|
if (qemudMonitorCommand(vm, cmd, &info) < 0) {
|
||||||
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
_("unable to start migration to %s"), dest);
|
_("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 */
|
/* Now check for "fail" in the output string */
|
||||||
if (strstr(info, "fail") != NULL) {
|
if (strstr(info, "fail") != NULL) {
|
||||||
qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
||||||
_("migration to '%s' failed: %s"), dest, info);
|
_("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;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1121,6 +1138,7 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm,
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
VIR_FREE(safedest);
|
||||||
VIR_FREE(info);
|
VIR_FREE(info);
|
||||||
VIR_FREE(cmd);
|
VIR_FREE(cmd);
|
||||||
return ret;
|
return ret;
|
||||||
@ -1130,7 +1148,7 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm,
|
|||||||
const char *hostname,
|
const char *hostname,
|
||||||
int port)
|
int port)
|
||||||
{
|
{
|
||||||
char *uri;
|
char *uri = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) {
|
if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) {
|
||||||
@ -1144,3 +1162,40 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm,
|
|||||||
|
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
@ -132,4 +132,8 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm,
|
|||||||
const char *hostname,
|
const char *hostname,
|
||||||
int port);
|
int port);
|
||||||
|
|
||||||
|
int qemuMonitorMigrateToCommand(const virDomainObjPtr vm,
|
||||||
|
const char * const *argv,
|
||||||
|
const char *target);
|
||||||
|
|
||||||
#endif /* QEMU_MONITOR_TEXT_H */
|
#endif /* QEMU_MONITOR_TEXT_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user