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

Jovanka Gulicoska jovanka.gulicoska at gmail.com
Thu Jul 28 12:02:57 UTC 2016


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;
+    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
-- 
2.7.4




More information about the libvir-list mailing list