If a guest has not completed live migration before timeout, then auto-suspend the guest, where the migration will complete offline. Signed-off-by: Wen Congyang <wency@xxxxxxxxxxxxxx> --- tools/virsh.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 4 +++ 2 files changed, 71 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index fb182a5..99d9c30 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -54,6 +54,7 @@ #include "files.h" #include "event_impl.h" #include "configmake.h" +#include "timer.h" static char *progname; @@ -3358,6 +3359,28 @@ cmdDomuuid(vshControl *ctl, const vshCmd *cmd) /* * "migrate" command */ +static void migrateTimeoutHandler(void *data) +{ + virDomainPtr dom = data; + virDomainInfo info; + unsigned int id; + + id = virDomainGetID(dom); + if (id == ((unsigned int)-1)) + return; + + /* The error reason has been reported in virDomainGetInfo() and + * virDomainSuspend() when it fails. So we do not check the return value. + */ + if (virDomainGetInfo(dom, &info) == 0) { + if (info.state == VIR_DOMAIN_SHUTOFF) + return; + + /* suspend the domain when migration timeouts. */ + virDomainSuspend(dom); + } +} + static const vshCmdInfo info_migrate[] = { {"help", N_("migrate domain to another host")}, {"desc", N_("Migrate domain to another host. Add --live for live migration.")}, @@ -3378,6 +3401,7 @@ static const vshCmdOptDef opts_migrate[] = { {"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, N_("connection URI of the destination host")}, {"migrateuri", VSH_OT_DATA, 0, N_("migration URI, usually can be omitted")}, {"dname", VSH_OT_DATA, 0, N_("rename to new name during migration (if supported)")}, + {"timeout", VSH_OT_INT, 0, N_("force guest to suspend if live migration exceeds timeout (in seconds)")}, {NULL, 0, 0, NULL} }; @@ -3388,6 +3412,8 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) const char *desturi; const char *migrateuri; const char *dname; + long long timeout; + virTimerPtr migratetimer = NULL; int flags = 0, found, ret = FALSE; if (!vshConnectionUsability (ctl, ctl->conn)) @@ -3425,6 +3451,29 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool (cmd, "copy-storage-inc")) flags |= VIR_MIGRATE_NON_SHARED_INC; + timeout = vshCommandOptInt(cmd, "timeout", &found); + if (found) { + if (! flags & VIR_MIGRATE_LIVE) { + vshError(ctl, "%s", _("migrate: Unexpected timeout for offline migration")); + goto done; + } + + if (timeout < 1) { + vshError(ctl, "%s", _("migrate: Invalid timeout")); + goto done; + } + + /* Ensure that we can multiply by 1000 without overflowing. */ + if (timeout > INT_MAX / 1000) { + vshError(ctl, "%s", _("migrate: Timeout is too big")); + goto done; + } + + migratetimer = virTimerNew(migrateTimeoutHandler, (void *)dom); + if (!migratetimer) + goto done; + } + if ((flags & VIR_MIGRATE_PEER2PEER) || vshCommandOptBool (cmd, "direct")) { /* For peer2peer migration or direct migration we only expect one URI @@ -3435,6 +3484,13 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) goto done; } + if (migratetimer) { + if (virSetTimeout(migratetimer, timeout * 1000) < 0) { + vshError(ctl, "%s", _("migrate: failed to add timer")); + goto done; + } + } + if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0) ret = TRUE; } else { @@ -3445,6 +3501,13 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0); if (!dconn) goto done; + if (migratetimer) { + if (virSetTimeout(migratetimer, timeout * 1000) < 0) { + vshError(ctl, "%s", _("migrate: failed to add timer")); + goto done; + } + } + ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0); if (ddom) { virDomainFree(ddom); @@ -3454,6 +3517,10 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) } done: + if (migratetimer) { + virSetTimeout(migratetimer, 0); + virTimerFree(migratetimer); + } if (dom) virDomainFree (dom); return ret; } diff --git a/tools/virsh.pod b/tools/virsh.pod index 9cb6829..f9d6a70 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -490,6 +490,7 @@ type attribute for the <domain> element of XML. =item B<migrate> optional I<--live> I<--p2p> I<--direct> I<--tunnelled> I<--persistent> I<--undefinesource> I<--suspend> I<--copy-storage-all> I<--copy-storage-inc> I<domain-id> I<desturi> I<migrateuri> I<dname> +I<--timeout> Migrate domain to another host. Add I<--live> for live migration; I<--p2p> for peer-2-peer migration; I<--direct> for direct migration; or I<--tunnelled> @@ -505,6 +506,9 @@ I<migrateuri> is the migration URI, which usually can be omitted. I<dname> is used for renaming the domain to new name during migration, which also usually can be omitted. +I<--timeout> forces guest to suspend when live migration exceeds timeout, and +then the migration will complete offline. It can only be used with I<--live>. + =item B<migrate-setmaxdowntime> I<domain-id> I<downtime> Set maximum tolerable downtime for a domain which is being live-migrated to -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list