]> xenbits.xensource.com Git - libvirt.git/commitdiff
Make virsh reconnect when losing connection
authorDaniel Veillard <veillard@redhat.com>
Fri, 5 Mar 2010 09:59:52 +0000 (10:59 +0100)
committerDaniel Veillard <veillard@redhat.com>
Wed, 10 Mar 2010 16:03:07 +0000 (17:03 +0100)
When the daemon libvirtd restarts, a connected virsh gets a SIGPIPE
and dies. This change the behaviour to try to reconnect if the
signal was received or command error indicated a connection or RPC
failure. Note that the failing command is not restarted.

* tools/virsh.c: catch SIGPIPE signals as well as connection related
  failures, add some automatic reconnection code and appropriate error
  messages.

tools/virsh.c

index b5b7ef48407e0313c0e71460391f419559c057e9..a47edd57eaead92baa27ea3b16d1cf9bd5bf090c 100644 (file)
@@ -30,6 +30,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <inttypes.h>
+#include <signal.h>
 
 #include <libxml/parser.h>
 #include <libxml/tree.h>
@@ -397,6 +398,60 @@ out:
     last_error = NULL;
 }
 
+/*
+ * Detection of disconnections and automatic reconnection support
+ */
+static int disconnected = 0; /* we may have been disconnected */
+
+/*
+ * vshCatchDisconnect:
+ *
+ * We get here when a SIGPIPE is being raised, we can't do much in the
+ * handler, just save the fact it was raised
+ */
+static void vshCatchDisconnect(int sig, siginfo_t * siginfo,
+                               void* context ATTRIBUTE_UNUSED) {
+    if ((sig == SIGPIPE) || (siginfo->si_signo == SIGPIPE))
+        disconnected++;
+}
+
+/*
+ * vshSetupSignals:
+ *
+ * Catch SIGPIPE signals which may arise when disconnection
+ * from libvirtd occurs
+ */
+static int
+vshSetupSignals(void) {
+    struct sigaction sig_action;
+
+    sig_action.sa_sigaction = vshCatchDisconnect;
+    sig_action.sa_flags = SA_SIGINFO;
+    sigemptyset(&sig_action.sa_mask);
+
+    sigaction(SIGPIPE, &sig_action, NULL);
+}
+
+/*
+ * vshReconnect:
+ *
+ * Reconnect after an
+ *
+ */
+static int
+vshReconnect(vshControl *ctl) {
+    if (ctl->conn != NULL)
+        virConnectClose(ctl->conn);
+
+    ctl->conn = virConnectOpenAuth(ctl->name,
+                                   virConnectAuthPtrDefault,
+                                   ctl->readonly ? VIR_CONNECT_RO : 0);
+    if (!ctl->conn)
+        vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
+    else
+        vshError(ctl, "%s", _("Reconnected to the hypervisor"));
+    disconnected = 0;
+}
 
 /* ---------------
  * Commands
@@ -8334,6 +8389,9 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
     while (cmd) {
         struct timeval before, after;
 
+        if ((ctl->conn == NULL) || (disconnected != 0))
+            vshReconnect(ctl);
+
         if (ctl->timing)
             GETTIMEOFDAY(&before);
 
@@ -8345,6 +8403,17 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
         if (ret == FALSE)
             virshReportError(ctl);
 
+        /* try to automatically catch disconnections */
+        if ((ret == FALSE) &&
+            ((disconnected != 0) ||
+             ((last_error != NULL) &&
+              (((last_error->code == VIR_ERR_SYSTEM_ERROR) &&
+                (last_error->domain == VIR_FROM_REMOTE)) ||
+               (last_error->code == VIR_ERR_RPC) ||
+               (last_error->code == VIR_ERR_NO_CONNECT) ||
+               (last_error->code == VIR_ERR_INVALID_CONN)))))
+            vshReconnect(ctl);
+
         if (STREQ(cmd->def->name, "quit"))        /* hack ... */
             return ret;
 
@@ -8675,9 +8744,11 @@ vshError(vshControl *ctl, const char *format, ...)
 {
     va_list ap;
 
-    va_start(ap, format);
-    vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
-    va_end(ap);
+    if (ctl != NULL) {
+        va_start(ap, format);
+        vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
+        va_end(ap);
+    }
 
     fputs(_("error: "), stderr);
 
@@ -8753,6 +8824,9 @@ vshInit(vshControl *ctl)
     /* set up the library error handler */
     virSetErrorFunc(NULL, virshErrorHandler);
 
+    /* set up the signals handlers to catch disconnections */
+    vshSetupSignals();
+
     ctl->conn = virConnectOpenAuth(ctl->name,
                                    virConnectAuthPtrDefault,
                                    ctl->readonly ? VIR_CONNECT_RO : 0);