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

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

--- tools/virsh.c | 82 +++++++++++++++++++++++++++--------------------------- tools/virsh.pod | 61 +++++++++++++++++++++-------------------- 2 files changed, 72 insertions(+), 71 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 33aeb6c..4da5e1a 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -20151,19 +20151,19 @@ vshUsage(void) "\n%s [options]... <command> [args...]\n\n" " options:\n" " -c | --connect=URI hypervisor connection URI\n" - " -r | --readonly connect readonly\n" " -d | --debug=NUM debug level [0-4]\n" + " -e | --escape <char> set escape sequence for console\n" " -h | --help this help\n" + " -i | --keepalive_interval\n" + " interval time value \n" + " -l | --log=FILE output logging to file\n" + " -n | --keepalive_count number of keepalive message\n\n" " -q | --quiet quiet mode\n" + " -r | --readonly connect readonly\n" " -t | --timing print timing information\n" - " -l | --log=FILE output logging to file\n" " -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" - " -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++) { @@ -20331,59 +20331,34 @@ vshParseArgv(vshControl *ctl, int argc, char **argv) { int arg, len; struct option opt[] = { + {"connect", required_argument, NULL, 'c'}, {"debug", required_argument, NULL, 'd'}, + {"escape", required_argument, NULL, 'e'}, {"help", no_argument, NULL, 'h'}, + {"keepalive_count", required_argument, NULL, 'n'}, + {"keepalive_interval", required_argument, NULL, 'i'}, + {"log", required_argument, NULL, 'l'}, {"quiet", no_argument, NULL, 'q'}, + {"readonly", no_argument, NULL, 'r'}, {"timing", no_argument, NULL, 't'}, {"version", optional_argument, NULL, 'v'}, - {"connect", required_argument, NULL, 'c'}, - {"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:i:n:", opt, NULL)) != -1) { + while ((arg = getopt_long(argc, argv, "+c:d:e:hi:l:n:qrtvV", opt, NULL)) != -1) { switch (arg) { + case 'c': + ctl->name = vshStrdup(ctl, optarg); + break; case 'd': if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) { vshError(ctl, "%s", _("option -d takes a numeric argument")); exit(EXIT_FAILURE); } break; - case 'h': - vshUsage(); - exit(EXIT_SUCCESS); - break; - case 'q': - ctl->quiet = true; - break; - case 't': - ctl->timing = true; - break; - case 'c': - ctl->name = vshStrdup(ctl, optarg); - break; - case 'v': - if (STRNEQ_NULLABLE(optarg, "long")) { - puts(VERSION); - exit(EXIT_SUCCESS); - } - /* fall through */ - case 'V': - vshShowVersion(ctl); - exit(EXIT_SUCCESS); - case 'r': - ctl->readonly = true; - break; - case 'l': - ctl->logfile = vshStrdup(ctl, optarg); - break; case 'e': len = strlen(optarg); @@ -20397,6 +20372,10 @@ vshParseArgv(vshControl *ctl, int argc, char **argv) exit(EXIT_FAILURE); } break; + case 'h': + vshUsage(); + exit(EXIT_SUCCESS); + break; case 'i': if (virStrToLong_ui(optarg, NULL, 10, &ctl->keepalive_interval) < 0) { vshError(ctl, @@ -20404,6 +20383,9 @@ vshParseArgv(vshControl *ctl, int argc, char **argv) exit(EXIT_FAILURE); } break; + case 'l': + ctl->logfile = vshStrdup(ctl, optarg); + break; case 'n': if (virStrToLong_ui(optarg, NULL, 10, &ctl->keepalive_count) < 0) { vshError(ctl, @@ -20411,6 +20393,24 @@ vshParseArgv(vshControl *ctl, int argc, char **argv) exit(EXIT_FAILURE); } break; + case 'q': + ctl->quiet = true; + break; + case 'r': + ctl->readonly = true; + break; + case 't': + ctl->timing = true; + break; + case 'v': + if (STRNEQ_NULLABLE(optarg, "long")) { + puts(VERSION); + exit(EXIT_SUCCESS); + } + /* fall through */ + case 'V': + vshShowVersion(ctl); + exit(EXIT_SUCCESS); default: vshError(ctl, _("unsupported option '-%c'. See --help."), arg); exit(EXIT_FAILURE); diff --git a/tools/virsh.pod b/tools/virsh.pod index faa97a2..656f6f0 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -49,21 +49,6 @@ The B<virsh> program understands the following I<OPTIONS>. =over 4 -=item B<-h>, B<--help> - -Ignore all other arguments, and behave as if the B<help> command were -given instead. - -=item B<-v>, B<--version[=short]> - -Ignore all other arguments, and prints the version of the libvirt library -virsh is coming from - -=item B<-V>, B<--version=long> - -Ignore all other arguments, and prints the version of the libvirt library -virsh is coming from and which options and driver are compiled in. - =item B<-c>, B<--connect> I<URI> Connect to the specified I<URI>, as if by the B<connect> command, @@ -75,10 +60,35 @@ Enable debug messages at integer I<LEVEL> and above. I<LEVEL> can range from 0 to 4 (default). See the documentation of B<VIRSH_DEBUG> environment variable below for the description of each I<LEVEL>. +=item B<-e>, B<--escape> I<string> + +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<-h>, B<--help> + +Ignore all other arguments, and behave as if the B<help> command were +given instead. + +=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<-l>, B<--log> I<FILE> Output logging details to I<FILE>. +=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. + =item B<-q>, B<--quiet> Avoid extra informational messages. @@ -92,24 +102,15 @@ option of the B<connect> command. Output elapsed time information for each command. -=item B<-e>, B<--escape> I<string> - -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<-v>, B<--version[=short]> -=item B<-i>, B<--keepalive_interval> I<second> +Ignore all other arguments, and prints the version of the libvirt library +virsh is coming from -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<-V>, B<--version=long> -=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. +Ignore all other arguments, and prints the version of the libvirt library +virsh is coming from and which options and driver are compiled in. =back -- 1.7.7.5
participants (1)
-
Guannan Ren