On 07/28/2016 08:02 AM, Jovanka Gulicoska wrote: > Add nodedev-event support for node device lifecycle events > --- > tools/virsh-nodedev.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++ > tools/virsh.pod | 18 +++++ > 2 files changed, 200 insertions(+) > > diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c > index a715b61..5edcf34 100644 > --- a/tools/virsh-nodedev.c > +++ b/tools/virsh-nodedev.c > @@ -31,6 +31,7 @@ > #include "viralloc.h" > #include "virfile.h" > #include "virstring.h" > +#include "virtime.h" > #include "conf/node_device_conf.h" > > /* > @@ -739,6 +740,181 @@ cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd) > 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 = "node 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; Actually it looks like this is problem, throwing an assert, since the 'device' property isn't registered up above, instead it's called "node device". Plus the property isn't mandatory. So I dropped this patch from my queue, please fix and resend, it can be applied separately. Thanks, Cole > + if (vshCommandOptBool(cmd, "node device")) > + dev = virNodeDeviceLookupByName(priv->conn, device_value); > + 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[] = { > {.name = "nodedev-create", > .handler = cmdNodeDeviceCreate, > @@ -788,5 +964,11 @@ const vshCmdDef nodedevCmds[] = { > .info = info_node_device_reset, > .flags = 0 > }, > + {.name = "nodedev-event", > + .handler = cmdNodeDeviceEvent, > + .opts = opts_node_device_event, > + .info = info_node_device_event, > + .flags = 0 > + }, > {.name = NULL} > }; > diff --git a/tools/virsh.pod b/tools/virsh.pod > index fc6a680..24f2c2b 100644 > --- a/tools/virsh.pod > +++ b/tools/virsh.pod > @@ -2957,6 +2957,24 @@ a node device between guest passthrough or the host. Libvirt will > often do this action implicitly when required, but this command > 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 > > =head1 VIRTUAL NETWORK COMMANDS > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list