virsh: Introduce nodedev-event command

Add nodedev-event support for node device lifecycle events
This commit is contained in:
Jovanka Gulicoska 2016-08-08 21:34:21 +02:00 committed by Cole Robinson
parent 9e5e7f3a5b
commit 5b8643099a
2 changed files with 205 additions and 0 deletions

View File

@ -31,6 +31,7 @@
#include "viralloc.h" #include "viralloc.h"
#include "virfile.h" #include "virfile.h"
#include "virstring.h" #include "virstring.h"
#include "virtime.h"
#include "conf/node_device_conf.h" #include "conf/node_device_conf.h"
/* /*
@ -739,6 +740,186 @@ cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd)
return ret; return ret;
} }
/*
* "nodedev-event" command
*/
VIR_ENUM_DECL(virshNodeDeviceEvent)
VIR_ENUM_IMPL(virshNodeDeviceEvent,
VIR_NODE_DEVICE_EVENT_LAST,
N_("Created"),
N_("Deleted"))
static const char *
virshNodeDeviceEventToString(int event)
{
const char *str = virshNodeDeviceEventTypeToString(event);
return str ? _(str) : _("unknown");
}
struct virshNodeDeviceEventData {
vshControl *ctl;
bool loop;
bool timestamp;
int count;
};
typedef struct virshNodeDeviceEventData virshNodeDeviceEventData;
VIR_ENUM_DECL(virshNodeDeviceEventId)
VIR_ENUM_IMPL(virshNodeDeviceEventId,
VIR_NODE_DEVICE_EVENT_ID_LAST,
"lifecycle")
static void
vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
virNodeDevicePtr dev,
int event,
int detail ATTRIBUTE_UNUSED,
void *opaque)
{
virshNodeDeviceEventData *data = opaque;
if (!data->loop && data->count)
return;
if (data->timestamp) {
char timestamp[VIR_TIME_STRING_BUFLEN];
if (virTimeStringNowRaw(timestamp) < 0)
timestamp[0] = '\0';
vshPrint(data->ctl, _("%s: event 'lifecycle' for node device %s: %s\n"),
timestamp,
virNodeDeviceGetName(dev), virshNodeDeviceEventToString(event));
} else {
vshPrint(data->ctl, _("event 'lifecycle' for node device %s: %s\n"),
virNodeDeviceGetName(dev), virshNodeDeviceEventToString(event));
}
data->count++;
if (!data->loop)
vshEventDone(data->ctl);
}
static const vshCmdInfo info_node_device_event[] = {
{.name = "help",
.data = N_("Node Device Events")
},
{.name = "desc",
.data = N_("List event types, or wait for node device events to occur")
},
{.name = NULL}
};
static const vshCmdOptDef opts_node_device_event[] = {
{.name = "device",
.type = VSH_OT_STRING,
.help = N_("filter by node device name")
},
{.name = "event",
.type = VSH_OT_STRING,
.help = N_("which event type to wait for")
},
{.name = "loop",
.type = VSH_OT_BOOL,
.help = N_("loop until timeout or interrupt, rather than one-shot")
},
{.name = "timeout",
.type = VSH_OT_INT,
.help = N_("timeout seconds")
},
{.name = "list",
.type = VSH_OT_BOOL,
.help = N_("list valid event types")
},
{.name = "timestamp",
.type = VSH_OT_BOOL,
.help = N_("show timestamp for each printed event")
},
{.name = NULL}
};
static bool
cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd)
{
virNodeDevicePtr dev = NULL;
bool ret = false;
int eventId = -1;
int timeout = 0;
virshNodeDeviceEventData data;
const char *eventName = NULL;
const char *device_value = NULL;
int event;
virshControlPtr priv = ctl->privData;
if (vshCommandOptBool(cmd, "list")) {
size_t i;
for (i = 0; i < VIR_NODE_DEVICE_EVENT_ID_LAST; i++)
vshPrint(ctl, "%s\n", virshNodeDeviceEventIdTypeToString(i));
return true;
}
if (vshCommandOptStringReq(ctl, cmd, "event", &eventName) < 0)
return false;
if (!eventName) {
vshError(ctl, "%s", _("either --list or event type is required"));
return false;
}
if ((event = virshNodeDeviceEventIdTypeFromString(eventName)) < 0) {
vshError(ctl, _("unknown event type %s"), eventName);
return false;
}
data.ctl = ctl;
data.loop = vshCommandOptBool(cmd, "loop");
data.timestamp = vshCommandOptBool(cmd, "timestamp");
data.count = 0;
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
return false;
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
return false;
if (device_value) {
if (!(dev = virNodeDeviceLookupByName(priv->conn, device_value))) {
vshError(ctl, "%s '%s'",
_("Could not find matching device"), device_value);
goto cleanup;
}
}
if (vshEventStart(ctl, timeout) < 0)
goto cleanup;
if ((eventId = virConnectNodeDeviceEventRegisterAny(priv->conn, dev, event,
VIR_NODE_DEVICE_EVENT_CALLBACK(vshEventLifecyclePrint),
&data, NULL)) < 0)
goto cleanup;
switch (vshEventWait(ctl)) {
case VSH_EVENT_INTERRUPT:
vshPrint(ctl, "%s", _("event loop interrupted\n"));
break;
case VSH_EVENT_TIMEOUT:
vshPrint(ctl, "%s", _("event loop timed out\n"));
break;
case VSH_EVENT_DONE:
break;
default:
goto cleanup;
}
vshPrint(ctl, _("events received: %d\n"), data.count);
if (data.count)
ret = true;
cleanup:
vshEventCleanup(ctl);
if (eventId >= 0 &&
virConnectNodeDeviceEventDeregisterAny(priv->conn, eventId) < 0)
ret = false;
if (dev)
virNodeDeviceFree(dev);
return ret;
}
const vshCmdDef nodedevCmds[] = { const vshCmdDef nodedevCmds[] = {
{.name = "nodedev-create", {.name = "nodedev-create",
.handler = cmdNodeDeviceCreate, .handler = cmdNodeDeviceCreate,
@ -788,5 +969,11 @@ const vshCmdDef nodedevCmds[] = {
.info = info_node_device_reset, .info = info_node_device_reset,
.flags = 0 .flags = 0
}, },
{.name = "nodedev-event",
.handler = cmdNodeDeviceEvent,
.opts = opts_node_device_event,
.info = info_node_device_event,
.flags = 0
},
{.name = NULL} {.name = NULL}
}; };

View File

@ -2958,6 +2958,24 @@ a node device between guest passthrough or the host. Libvirt will
often do this action implicitly when required, but this command often do this action implicitly when required, but this command
allows an explicit reset when needed. allows an explicit reset when needed.
=item B<nodedev-event> {[I<nodedev>] I<event> [I<--loop>] [I<--timeout>
I<seconds>] [I<--timestamp>] | I<--list>}
Wait for a class of node device events to occur, and print appropriate
details of events as they happen. The events can optionally be filtered
by I<nodedev>. Using I<--list> as the only argument will provide a list
of possible I<event> values known by this client, although the connection
might not allow registering for all these events.
By default, this command is one-shot, and returns success once an event
occurs; you can send SIGINT (usually via C<Ctrl-C>) to quit immediately.
If I<--timeout> is specified, the command gives up waiting for events
after I<seconds> have elapsed. With I<--loop>, the command prints all
events until a timeout or interrupt key.
When I<--timestamp> is used, a human-readable timestamp will be printed
before the event.
=back =back
=head1 VIRTUAL NETWORK COMMANDS =head1 VIRTUAL NETWORK COMMANDS