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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list