[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v5 4/4] force guest to suspend at timeout



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 cn fujitsu com>

---
 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 094870c..4f330f6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -54,6 +54,7 @@
 #include "files.h"
 #include "event.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 9c45a61..6dd5bb3 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]