[libvirt] [PATCH v2 8/8] virsh: Introduce nodedev-event command

Cole Robinson crobinso at redhat.com
Fri Jul 29 16:18:02 UTC 2016


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
> 




More information about the libvir-list mailing list