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