mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
virsh: Introduce nodedev-event command
Add nodedev-event support for node device lifecycle events
This commit is contained in:
parent
9e5e7f3a5b
commit
5b8643099a
@ -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}
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user