[libvirt] [PATCH v3 1/2] virsh: add keepalive protocol in virsh

Guannan Ren gren at redhat.com
Tue Jun 12 08:03:49 UTC 2012


Bugzilla:https://bugzilla.redhat.com/show_bug.cgi?id=822839
Add two general virsh options to start keepalive messaging in virsh
By default, virsh doesn't start keepalive.
Under the explicit request of keepalive with the the following options
, virsh will try to start keepalive. The virsh will fail if the keepalive
request cannot be honored.

error: this function is not supported by the connection driver: virConnectSetKeepAlive
error: Failed to connect to the hypervisor

    -i | --keepalive_interval
                            interval time value
    -n | --keepalive_count  number of keepalive message

For non-p2p migration, start keepalive for remote driver to
determine the status of network connection, aborting migrating job
after defined amount of interval time.
---
 tools/virsh.c   |  110 ++++++++++++++++++++++++++++++++++++++++++++++---------
 tools/virsh.pod |   13 ++++++
 2 files changed, 105 insertions(+), 18 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 744b629..33aeb6c 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -251,6 +251,10 @@ typedef struct __vshControl {
     bool readonly;              /* connect readonly (first time only, not
                                  * during explicit connect command)
                                  */
+    unsigned int keepalive_interval;
+                                /* interval time value */
+    unsigned int keepalive_count;
+                                /* keepalive_count value */
     char *logfile;              /* log file name */
     int log_fd;                 /* log file descriptor */
     char *historydir;           /* readline history directory name */
@@ -415,13 +419,14 @@ typedef struct __vshCtrlData {
     vshControl *ctl;
     const vshCmd *cmd;
     int writefd;
+    virConnectPtr dconn;
 } vshCtrlData;
 
 typedef void (*jobWatchTimeoutFunc) (vshControl *ctl, virDomainPtr dom,
                                      void *opaque);
 
 static bool
-vshWatchJob(vshControl *ctl,
+vshWatchJob(vshCtrlData *data,
             virDomainPtr dom,
             bool verbose,
             int pipe_fd,
@@ -628,6 +633,39 @@ vshSetupSignals(void) {
 }
 
 /*
+ * vshConnectOpen:
+ *
+ * A wrapper for virConnectOpenAuth.
+ */
+static virConnectPtr
+vshConnectOpen(const char *name,
+               bool readonly,
+               vshControl *ctl)
+{
+    virConnectPtr conn;
+
+    if (!ctl)
+        return NULL;
+
+    conn = virConnectOpenAuth(name,
+                              virConnectAuthPtrDefault,
+                              readonly ? VIR_CONNECT_RO : 0);
+    if (!conn)
+        return NULL;
+
+    if (ctl->keepalive_interval > 0 && ctl->keepalive_count > 0)
+        if (virConnectSetKeepAlive(conn,
+                                   ctl->keepalive_interval,
+                                   ctl->keepalive_count) < 0) {
+            virshReportError(ctl);
+            virConnectClose(conn);
+            return NULL;
+        }
+
+    return conn;
+}
+
+/*
  * vshReconnect:
  *
  * Reconnect after a disconnect from libvirtd
@@ -643,9 +681,8 @@ vshReconnect(vshControl *ctl)
         virConnectClose(ctl->conn);
     }
 
-    ctl->conn = virConnectOpenAuth(ctl->name,
-                                   virConnectAuthPtrDefault,
-                                   ctl->readonly ? VIR_CONNECT_RO : 0);
+    ctl->conn = vshConnectOpen(ctl->name, ctl->readonly, ctl);
+
     if (!ctl->conn)
         vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
     else if (connected)
@@ -862,8 +899,7 @@ cmdConnect(vshControl *ctl, const vshCmd *cmd)
     ctl->useSnapshotOld = false;
     ctl->readonly = ro;
 
-    ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault,
-                                   ctl->readonly ? VIR_CONNECT_RO : 0);
+    ctl->conn = vshConnectOpen(ctl->name, ctl->readonly, ctl);
 
     if (!ctl->conn)
         vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
@@ -3334,6 +3370,7 @@ cmdSave(vshControl *ctl, const vshCmd *cmd)
     data.ctl = ctl;
     data.cmd = cmd;
     data.writefd = p[1];
+    data.dconn = NULL;
 
     if (virThreadCreate(&workerThread,
                         true,
@@ -3341,7 +3378,7 @@ cmdSave(vshControl *ctl, const vshCmd *cmd)
                         &data) < 0)
         goto cleanup;
 
-    ret = vshWatchJob(ctl, dom, verbose, p[0], 0, NULL, NULL, _("Save"));
+    ret = vshWatchJob(&data, dom, verbose, p[0], 0, NULL, NULL, _("Save"));
 
     virThreadJoin(&workerThread);
 
@@ -3608,6 +3645,7 @@ cmdManagedSave(vshControl *ctl, const vshCmd *cmd)
     data.ctl = ctl;
     data.cmd = cmd;
     data.writefd = p[1];
+    data.dconn = NULL;
 
     if (virThreadCreate(&workerThread,
                         true,
@@ -3615,7 +3653,7 @@ cmdManagedSave(vshControl *ctl, const vshCmd *cmd)
                         &data) < 0)
         goto cleanup;
 
-    ret = vshWatchJob(ctl, dom, verbose, p[0], 0,
+    ret = vshWatchJob(&data, dom, verbose, p[0], 0,
                       NULL, NULL, _("Managedsave"));
 
     virThreadJoin(&workerThread);
@@ -4086,6 +4124,7 @@ cmdDump(vshControl *ctl, const vshCmd *cmd)
     data.ctl = ctl;
     data.cmd = cmd;
     data.writefd = p[1];
+    data.dconn = NULL;
 
     if (virThreadCreate(&workerThread,
                         true,
@@ -4093,7 +4132,7 @@ cmdDump(vshControl *ctl, const vshCmd *cmd)
                         &data) < 0)
         goto cleanup;
 
-    ret = vshWatchJob(ctl, dom, verbose, p[0], 0, NULL, NULL, _("Dump"));
+    ret = vshWatchJob(&data, dom, verbose, p[0], 0, NULL, NULL, _("Dump"));
 
     virThreadJoin(&workerThread);
 
@@ -7210,9 +7249,16 @@ doMigrate (void *opaque)
         virConnectPtr dconn = NULL;
         virDomainPtr ddom = NULL;
 
-        dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
+        dconn = vshConnectOpen(desturi, 0, ctl);
         if (!dconn) goto out;
 
+        if (virConnectIsAlive(dconn) <= 0) {
+            virConnectClose(dconn);
+            goto out;
+        } else {
+            data->dconn = dconn;
+        }
+
         ddom = virDomainMigrate2(dom, dconn, xml, flags, dname, migrateuri, 0);
         if (ddom) {
             virDomainFree(ddom);
@@ -7268,7 +7314,7 @@ vshMigrationTimeout(vshControl *ctl,
 }
 
 static bool
-vshWatchJob(vshControl *ctl,
+vshWatchJob(vshCtrlData *data,
             virDomainPtr dom,
             bool verbose,
             int pipe_fd,
@@ -7286,6 +7332,7 @@ vshWatchJob(vshControl *ctl,
     char retchar;
     bool functionReturn = false;
     sigset_t sigmask, oldsigmask;
+    vshControl *ctl = data->ctl;
 
     sigemptyset(&sigmask);
     sigaddset(&sigmask, SIGINT);
@@ -7329,6 +7376,13 @@ repoll:
             goto cleanup;
         }
 
+       if (data->dconn && virConnectIsAlive(data->dconn) <= 0) {
+            virDomainAbortJob(dom);
+            vshError(ctl, "%s",
+                      _("Lost connection to destination host"));
+            goto cleanup;
+        }
+
         GETTIMEOFDAY(&curr);
         if (timeout && (((int)(curr.tv_sec - start.tv_sec)  * 1000 +
                          (int)(curr.tv_usec - start.tv_usec) / 1000) >
@@ -7402,13 +7456,14 @@ cmdMigrate(vshControl *ctl, const vshCmd *cmd)
     data.ctl = ctl;
     data.cmd = cmd;
     data.writefd = p[1];
+    data.dconn = NULL;
 
     if (virThreadCreate(&workerThread,
                         true,
                         doMigrate,
                         &data) < 0)
         goto cleanup;
-    functionReturn = vshWatchJob(ctl, dom, verbose, p[0], timeout,
+    functionReturn = vshWatchJob(&data, dom, verbose, p[0], timeout,
                                  vshMigrationTimeout, NULL, _("Migration"));
 
     virThreadJoin(&workerThread);
@@ -19658,9 +19713,7 @@ vshInit(vshControl *ctl)
     ctl->eventLoopStarted = true;
 
     if (ctl->name) {
-        ctl->conn = virConnectOpenAuth(ctl->name,
-                                       virConnectAuthPtrDefault,
-                                       ctl->readonly ? VIR_CONNECT_RO : 0);
+        ctl->conn = vshConnectOpen(ctl->name, ctl->readonly, ctl);
 
         /* Connecting to a named connection must succeed, but we delay
          * connecting to the default connection until we need it
@@ -19670,7 +19723,7 @@ vshInit(vshControl *ctl)
          */
         if (!ctl->conn) {
             virshReportError(ctl);
-            vshError(ctl, "%s", _("failed to connect to the hypervisor"));
+            vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
             return false;
         }
     }
@@ -20107,7 +20160,10 @@ vshUsage(void)
                       "    -v                      short version\n"
                       "    -V                      long version\n"
                       "         --version[=TYPE]   version, TYPE is short or long (default short)\n"
-                      "    -e | --escape <char>    set escape sequence for console\n\n"
+                      "    -e | --escape <char>    set escape sequence for console\n"
+                      "    -i | --keepalive_interval\n"
+                      "                            interval time value \n"
+                      "    -n | --keepalive_count  number of keepalive message\n\n"
                       "  commands (non interactive mode):\n\n"), progname, progname);
 
     for (grp = cmdGroups; grp->name; grp++) {
@@ -20284,13 +20340,15 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
         {"readonly", no_argument, NULL, 'r'},
         {"log", required_argument, NULL, 'l'},
         {"escape", required_argument, NULL, 'e'},
+        {"keepalive_interval", required_argument, NULL, 'i'},
+        {"keepalive_count", required_argument, NULL, 'n'},
         {NULL, 0, NULL, 0}
     };
 
     /* Standard (non-command) options. The leading + ensures that no
      * argument reordering takes place, so that command options are
      * not confused with top-level virsh options. */
-    while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:", opt, NULL)) != -1) {
+    while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:i:n:", opt, NULL)) != -1) {
         switch (arg) {
         case 'd':
             if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) {
@@ -20339,6 +20397,20 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
                 exit(EXIT_FAILURE);
             }
             break;
+        case 'i':
+            if (virStrToLong_ui(optarg, NULL, 10, &ctl->keepalive_interval) < 0) {
+                vshError(ctl,
+                         "%s", _("option -i takes a non-negative numeric argument"));
+                exit(EXIT_FAILURE);
+            }
+            break;
+        case 'n':
+            if (virStrToLong_ui(optarg, NULL, 10, &ctl->keepalive_count) < 0) {
+                vshError(ctl,
+                         "%s", _("option -n takes a non-negative numeric argument"));
+                exit(EXIT_FAILURE);
+            }
+            break;
         default:
             vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
             exit(EXIT_FAILURE);
@@ -20370,6 +20442,8 @@ main(int argc, char **argv)
     ctl->log_fd = -1;           /* Initialize log file descriptor */
     ctl->debug = VSH_DEBUG_DEFAULT;
     ctl->escapeChar = CTRL_CLOSE_BRACKET;
+    ctl->keepalive_interval = -1;
+    ctl->keepalive_count = 0;
 
 
     if (!setlocale(LC_ALL, "")) {
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 6553825..faa97a2 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -98,6 +98,19 @@ Set alternative escape sequence for I<console> command. By default,
 telnet's B<^]> is used. Allowed characters when using hat notation are:
 alphabetic character, @, [, ], \, ^, _.
 
+=item B<-i>, B<--keepalive_interval> I<second>
+
+Use together with I<--keepalive_count> to start keepalive messaging between
+libvirt client and server. A keepalive message will be sent to a libvirt server
+after I<--keepalive_interval> seconds of inactivity to check if server is still
+responding. I<seconds> with 0 value has the same effect as without using this
+option.
+
+=item B<-n>, B<--keepalive_count> I<number>
+The maximum number of keepalive messages that are allowed to be sent to libvirt
+server without getting any response before the connection is considered broken.
+I<number> with 0 value has the same effect as without using this option.
+
 =back
 
 =head1 NOTES
-- 
1.7.7.5




More information about the libvir-list mailing list