On 07/20/2016 09:50 AM, Jovanka Gulicoska wrote:
Add nodedev-event support for node device lifecycle events
---
tools/virsh-nodedev.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh-nodedev.h | 10 +++
tools/virsh.pod | 18 +++++
3 files changed, 239 insertions(+)
diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c
index a715b61..a48f0bd 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,210 @@ 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}
+};
+
+virNodeDevicePtr
+virshCommandOptNodeDeviceBy(vshControl *ctl, const vshCmd *cmd,
+ const char **name, unsigned int flags)
+{
+ virNodeDevicePtr dev = NULL;
+ const char *n = NULL;
+ const char *optname = "node device";
+ virCheckFlags(VIRSH_BYNAME, NULL);
+ virshControlPtr priv = ctl->privData;
+
+ if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
+ return NULL;
+
+ vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n",
+ cmd->def->name, optname, n);
+
+ if (name)
+ *name = n;
+
+ /* try it by NAME */
+ if (!dev && (flags & VIRSH_BYNAME)) {
+ vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as node device
NAME\n",
+ cmd->def->name, optname);
+ dev = virNodeDeviceLookupByName(priv->conn, n);
+ }
+
+ if (!dev)
+ vshError(ctl, _("failed to get node device '%s'"), n);
+
+ return dev;
+}
+
+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;
+ 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 (vshCommandOptBool(cmd, "node device"))
+ dev = virshCommandOptNodeDevice(ctl, cmd, NULL);
+ 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 +993,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-nodedev.h b/tools/virsh-nodedev.h
index c64f7df..b6b2e02 100644
--- a/tools/virsh-nodedev.h
+++ b/tools/virsh-nodedev.h
@@ -28,6 +28,16 @@
# include "virsh.h"
+virNodeDevicePtr
+virshCommandOptNodeDeviceBy(vshControl *ctl, const vshCmd *cmd,
+ const char **name, unsigned int flags);
+
+/* default is lookup by Name */
+# define virshCommandOptNodeDevice(_ctl, _cmd, _name) \
+ virshCommandOptNodeDeviceBy(_ctl, _cmd, _name, \
+ VIRSH_BYNAME)
+
+
All this OptNodeDevice stuff isn't required... we use that pattern for
doms/pools since there are multiple ways you can specify an object (like name,
or uuid, etc). For nodedev commands, we only accept the nodedev name. So you
can drop all this and just use virNodeDeviceLookupByName like is used for
other commands.
Looks fine otherwise
Thanks,
Cole