mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
virsh: add --all flag to 'event' command
Similar to our event-test demo program, it's nice to be able to have a mode where we can sniff all events at once, rather than having to spawn multiple virsh in parallel with one for each event type. (Can I just say our RegisterAny design is lousy? The fact that the majority of our callback pointers have a function signature with the opaque data in a different position, and that we have to cast the function signature before registering it, makes it hard to write a generic callback function; we have to write one for every type of event id. Life would have been easier if we had designed the callback as a fixed signature with a void* and size parameter, and then allowed the caller to downcast the void* to a particular struct for data specific to their callback id, where we could have then had a single function with a switch statement for each event id, and register that one function for all types of events. It would also be nicer if the callback functions knew which callbackID was being used when invoking that callback, so that I could use a common data structure among all registrations instead of having to create an array of one data per callback. But I really don't want to go add yet another event API design.) * tools/virsh-domain.c (cmdEvent): Add --all parameter; convert all callbacks to support shared counter. * tools/virsh.pod (event): Document it. Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
bb4a9a527d
commit
0e16ae404c
@ -10543,8 +10543,9 @@ typedef struct vshEventCallback vshEventCallback;
|
|||||||
struct vshDomEventData {
|
struct vshDomEventData {
|
||||||
vshControl *ctl;
|
vshControl *ctl;
|
||||||
bool loop;
|
bool loop;
|
||||||
int count;
|
int *count;
|
||||||
vshEventCallback *cb;
|
vshEventCallback *cb;
|
||||||
|
int id;
|
||||||
};
|
};
|
||||||
typedef struct vshDomEventData vshDomEventData;
|
typedef struct vshDomEventData vshDomEventData;
|
||||||
|
|
||||||
@ -10555,11 +10556,11 @@ vshEventGenericPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event '%s' for domain %s\n"),
|
vshPrint(data->ctl, _("event '%s' for domain %s\n"),
|
||||||
data->cb->name, virDomainGetName(dom));
|
data->cb->name, virDomainGetName(dom));
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10573,12 +10574,12 @@ vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event 'lifecycle' for domain %s: %s %s\n"),
|
vshPrint(data->ctl, _("event 'lifecycle' for domain %s: %s %s\n"),
|
||||||
virDomainGetName(dom), vshDomainEventToString(event),
|
virDomainGetName(dom), vshDomainEventToString(event),
|
||||||
vshDomainEventDetailToString(event, detail));
|
vshDomainEventDetailToString(event, detail));
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10591,11 +10592,11 @@ vshEventRTCChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event 'rtc-change' for domain %s: %lld\n"),
|
vshPrint(data->ctl, _("event 'rtc-change' for domain %s: %lld\n"),
|
||||||
virDomainGetName(dom), utcoffset);
|
virDomainGetName(dom), utcoffset);
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10608,11 +10609,11 @@ vshEventWatchdogPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event 'watchdog' for domain %s: %s\n"),
|
vshPrint(data->ctl, _("event 'watchdog' for domain %s: %s\n"),
|
||||||
virDomainGetName(dom), vshDomainEventWatchdogToString(action));
|
virDomainGetName(dom), vshDomainEventWatchdogToString(action));
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10627,12 +10628,12 @@ vshEventIOErrorPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event 'io-error' for domain %s: %s (%s) %s\n"),
|
vshPrint(data->ctl, _("event 'io-error' for domain %s: %s (%s) %s\n"),
|
||||||
virDomainGetName(dom), srcPath, devAlias,
|
virDomainGetName(dom), srcPath, devAlias,
|
||||||
vshDomainEventIOErrorToString(action));
|
vshDomainEventIOErrorToString(action));
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10650,7 +10651,7 @@ vshEventGraphicsPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event 'graphics' for domain %s: "
|
vshPrint(data->ctl, _("event 'graphics' for domain %s: "
|
||||||
"%s local[%s %s %s] remote[%s %s %s] %s"),
|
"%s local[%s %s %s] remote[%s %s %s] %s"),
|
||||||
@ -10664,7 +10665,7 @@ vshEventGraphicsPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
vshPrint(data->ctl, " %s=%s", subject->identities[i].type,
|
vshPrint(data->ctl, " %s=%s", subject->identities[i].type,
|
||||||
subject->identities[i].name);
|
subject->identities[i].name);
|
||||||
vshPrint(data->ctl, "\n");
|
vshPrint(data->ctl, "\n");
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10680,13 +10681,13 @@ vshEventIOErrorReasonPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event 'io-error-reason' for domain %s: "
|
vshPrint(data->ctl, _("event 'io-error-reason' for domain %s: "
|
||||||
"%s (%s) %s due to %s\n"),
|
"%s (%s) %s due to %s\n"),
|
||||||
virDomainGetName(dom), srcPath, devAlias,
|
virDomainGetName(dom), srcPath, devAlias,
|
||||||
vshDomainEventIOErrorToString(action), reason);
|
vshDomainEventIOErrorToString(action), reason);
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10701,12 +10702,12 @@ vshEventBlockJobPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl, _("event 'block-job' for domain %s: %s for %s %s\n"),
|
vshPrint(data->ctl, _("event 'block-job' for domain %s: %s for %s %s\n"),
|
||||||
virDomainGetName(dom), vshDomainBlockJobToString(type),
|
virDomainGetName(dom), vshDomainBlockJobToString(type),
|
||||||
disk, vshDomainBlockJobStatusToString(status));
|
disk, vshDomainBlockJobStatusToString(status));
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10722,13 +10723,13 @@ vshEventDiskChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl,
|
vshPrint(data->ctl,
|
||||||
_("event 'disk-change' for domain %s disk %s: %s -> %s: %s\n"),
|
_("event 'disk-change' for domain %s disk %s: %s -> %s: %s\n"),
|
||||||
virDomainGetName(dom), alias, NULLSTR(oldSrc), NULLSTR(newSrc),
|
virDomainGetName(dom), alias, NULLSTR(oldSrc), NULLSTR(newSrc),
|
||||||
vshDomainEventDiskChangeToString(reason));
|
vshDomainEventDiskChangeToString(reason));
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10742,13 +10743,13 @@ vshEventTrayChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl,
|
vshPrint(data->ctl,
|
||||||
_("event 'disk-change' for domain %s disk %s: %s\n"),
|
_("event 'disk-change' for domain %s disk %s: %s\n"),
|
||||||
virDomainGetName(dom), alias,
|
virDomainGetName(dom), alias,
|
||||||
vshDomainEventTrayChangeToString(reason));
|
vshDomainEventTrayChangeToString(reason));
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10772,12 +10773,12 @@ vshEventBalloonChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl,
|
vshPrint(data->ctl,
|
||||||
_("event 'balloon-change' for domain %s: %lluKiB\n"),
|
_("event 'balloon-change' for domain %s: %lluKiB\n"),
|
||||||
virDomainGetName(dom), actual);
|
virDomainGetName(dom), actual);
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10790,12 +10791,12 @@ vshEventDeviceRemovedPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
vshDomEventData *data = opaque;
|
vshDomEventData *data = opaque;
|
||||||
|
|
||||||
if (!data->loop && data->count)
|
if (!data->loop && *data->count)
|
||||||
return;
|
return;
|
||||||
vshPrint(data->ctl,
|
vshPrint(data->ctl,
|
||||||
_("event 'device-removed' for domain %s: %s\n"),
|
_("event 'device-removed' for domain %s: %s\n"),
|
||||||
virDomainGetName(dom), alias);
|
virDomainGetName(dom), alias);
|
||||||
data->count++;
|
(*data->count)++;
|
||||||
if (!data->loop)
|
if (!data->loop)
|
||||||
vshEventDone(data->ctl);
|
vshEventDone(data->ctl);
|
||||||
}
|
}
|
||||||
@ -10853,6 +10854,10 @@ static const vshCmdOptDef opts_event[] = {
|
|||||||
.type = VSH_OT_DATA,
|
.type = VSH_OT_DATA,
|
||||||
.help = N_("which event type to wait for")
|
.help = N_("which event type to wait for")
|
||||||
},
|
},
|
||||||
|
{.name = "all",
|
||||||
|
.type = VSH_OT_BOOL,
|
||||||
|
.help = N_("wait for all events instead of just one type")
|
||||||
|
},
|
||||||
{.name = "loop",
|
{.name = "loop",
|
||||||
.type = VSH_OT_BOOL,
|
.type = VSH_OT_BOOL,
|
||||||
.help = N_("loop until timeout or interrupt, rather than one-shot")
|
.help = N_("loop until timeout or interrupt, rather than one-shot")
|
||||||
@ -10873,11 +10878,14 @@ cmdEvent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
{
|
{
|
||||||
virDomainPtr dom = NULL;
|
virDomainPtr dom = NULL;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
int eventId = -1;
|
|
||||||
int timeout = 0;
|
int timeout = 0;
|
||||||
vshDomEventData data;
|
vshDomEventData *data = NULL;
|
||||||
|
size_t i;
|
||||||
const char *eventName = NULL;
|
const char *eventName = NULL;
|
||||||
int event;
|
int event = -1;
|
||||||
|
bool all = vshCommandOptBool(cmd, "all");
|
||||||
|
bool loop = vshCommandOptBool(cmd, "loop");
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
if (vshCommandOptBool(cmd, "list")) {
|
if (vshCommandOptBool(cmd, "list")) {
|
||||||
for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
|
for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
|
||||||
@ -10887,34 +10895,63 @@ cmdEvent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
|
|
||||||
if (vshCommandOptString(cmd, "event", &eventName) < 0)
|
if (vshCommandOptString(cmd, "event", &eventName) < 0)
|
||||||
return false;
|
return false;
|
||||||
if (!eventName) {
|
if (eventName) {
|
||||||
vshError(ctl, "%s", _("either --list or event type is required"));
|
for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
|
||||||
return false;
|
if (STREQ(eventName, vshEventCallbacks[event].name))
|
||||||
}
|
break;
|
||||||
for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
|
if (event == VIR_DOMAIN_EVENT_ID_LAST) {
|
||||||
if (STREQ(eventName, vshEventCallbacks[event].name))
|
vshError(ctl, _("unknown event type %s"), eventName);
|
||||||
break;
|
return false;
|
||||||
if (event == VIR_DOMAIN_EVENT_ID_LAST) {
|
}
|
||||||
vshError(ctl, _("unknown event type %s"), eventName);
|
} else if (!all) {
|
||||||
|
vshError(ctl, "%s",
|
||||||
|
_("one of --list, --all, or event type is required"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.ctl = ctl;
|
if (all) {
|
||||||
data.loop = vshCommandOptBool(cmd, "loop");
|
if (VIR_ALLOC_N(data, VIR_DOMAIN_EVENT_ID_LAST) < 0)
|
||||||
data.count = 0;
|
goto cleanup;
|
||||||
data.cb = &vshEventCallbacks[event];
|
for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) {
|
||||||
|
data[i].ctl = ctl;
|
||||||
|
data[i].loop = loop;
|
||||||
|
data[i].count = &count;
|
||||||
|
data[i].cb = &vshEventCallbacks[i];
|
||||||
|
data[i].id = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (VIR_ALLOC_N(data, 1) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
data[0].ctl = ctl;
|
||||||
|
data[0].loop = vshCommandOptBool(cmd, "loop");
|
||||||
|
data[0].count = &count;
|
||||||
|
data[0].cb = &vshEventCallbacks[event];
|
||||||
|
data[0].id = -1;
|
||||||
|
}
|
||||||
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
||||||
return false;
|
goto cleanup;
|
||||||
|
|
||||||
if (vshCommandOptBool(cmd, "domain"))
|
if (vshCommandOptBool(cmd, "domain"))
|
||||||
dom = vshCommandOptDomain(ctl, cmd, NULL);
|
dom = vshCommandOptDomain(ctl, cmd, NULL);
|
||||||
if (vshEventStart(ctl, timeout) < 0)
|
if (vshEventStart(ctl, timeout) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if ((eventId = virConnectDomainEventRegisterAny(ctl->conn, dom, event,
|
for (i = 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) {
|
||||||
data.cb->cb,
|
if ((data[i].id = virConnectDomainEventRegisterAny(ctl->conn, dom,
|
||||||
&data, NULL)) < 0)
|
all ? i : event,
|
||||||
goto cleanup;
|
data[i].cb->cb,
|
||||||
|
&data[i],
|
||||||
|
NULL)) < 0) {
|
||||||
|
/* When registering for all events: if the first
|
||||||
|
* registration succeeds, silently ignore failures on all
|
||||||
|
* later registrations on the assumption that the server
|
||||||
|
* is older and didn't know quite as many events. */
|
||||||
|
if (i)
|
||||||
|
vshResetLibvirtError();
|
||||||
|
else
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (vshEventWait(ctl)) {
|
switch (vshEventWait(ctl)) {
|
||||||
case VSH_EVENT_INTERRUPT:
|
case VSH_EVENT_INTERRUPT:
|
||||||
vshPrint(ctl, "%s", _("event loop interrupted\n"));
|
vshPrint(ctl, "%s", _("event loop interrupted\n"));
|
||||||
@ -10927,15 +10964,20 @@ cmdEvent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
default:
|
default:
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
vshPrint(ctl, _("events received: %d\n"), data.count);
|
vshPrint(ctl, _("events received: %d\n"), count);
|
||||||
if (data.count)
|
if (count)
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
vshEventCleanup(ctl);
|
vshEventCleanup(ctl);
|
||||||
if (eventId >= 0 &&
|
if (data) {
|
||||||
virConnectDomainEventDeregisterAny(ctl->conn, eventId) < 0)
|
for (i = 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) {
|
||||||
ret = false;
|
if (data[i].id >= 0 &&
|
||||||
|
virConnectDomainEventDeregisterAny(ctl->conn, data[i].id) < 0)
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
VIR_FREE(data);
|
||||||
|
}
|
||||||
if (dom)
|
if (dom)
|
||||||
virDomainFree(dom);
|
virDomainFree(dom);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1047,14 +1047,16 @@ except that it does some error checking.
|
|||||||
The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment
|
The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment
|
||||||
variables, and defaults to C<vi>.
|
variables, and defaults to C<vi>.
|
||||||
|
|
||||||
=item B<event> {[I<domain>] I<event> [I<--loop>] [I<--timeout> I<seconds>] |
|
=item B<event> {[I<domain>] { I<event> | I<--all> } [I<--loop>]
|
||||||
I<--list>}
|
[I<--timeout> I<seconds>] | I<--list>}
|
||||||
|
|
||||||
Wait for a class of domain events to occur, and print appropriate details
|
Wait for a class of domain events to occur, and print appropriate details
|
||||||
of events as they happen. The events can optionally be filtered by
|
of events as they happen. The events can optionally be filtered by
|
||||||
I<domain>. Using I<--list> as the only argument will provide a list
|
I<domain>. Using I<--list> as the only argument will provide a list
|
||||||
of possible I<event> values known by this client, although the connection
|
of possible I<event> values known by this client, although the connection
|
||||||
might not allow registering for all these events.
|
might not allow registering for all these events. It is also possible
|
||||||
|
to use I<--all> instead of I<event> to register for all possible event
|
||||||
|
types at once.
|
||||||
|
|
||||||
By default, this command is one-shot, and returns success once an event
|
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.
|
occurs; you can send SIGINT (usually via C<Ctrl-C>) to quit immediately.
|
||||||
|
Loading…
Reference in New Issue
Block a user