Any new API deserves a good virsh wrapper :) qemu-monitor-event [<domain>] [<event>] [--pretty] [--loop] [--timeout <number>] Very similar to the previous work on 'virsh event'. For an example session: $ virsh -c qemu:///system qemu-monitor-event --event SHUTDOWN& $ virsh -c qemu:///system start f18-live Domain f18-live started $ virsh -c qemu:///system destroy f18-live Domain f18-live destroyed event SHUTDOWN at 1391212552.026544 for domain f18-live: (null) events received: 1 [1]+ Done virsh -c qemu:///system qemu-monitor-event --event SHUTDOWN $ * tools/virsh-domain.c (cmdQemuMonitorEvent): New command. * tools/virsh.pod (qemu-monitor-event): Document it. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- tools/virsh-domain.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 27 +++++++++-- 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 1d3c5f0..a5808d8 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -7912,6 +7912,135 @@ cleanup: } /* + * "qemu-monitor-event" command + */ + +struct vshQemuEventData { + vshControl *ctl; + bool loop; + bool pretty; + int count; +}; +typedef struct vshQemuEventData vshQemuEventData; + +static void +vshEventPrint(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, + const char *event, long long seconds, unsigned int micros, + const char *details, void *opaque) +{ + vshQemuEventData *data = opaque; + virJSONValuePtr pretty = NULL; + char *str = NULL; + + if (!data->loop && data->count) + return; + if (data->pretty && details) { + pretty = virJSONValueFromString(details); + if (pretty && (str = virJSONValueToString(pretty, true))) + details = str; + } + vshPrint(data->ctl, "event %s at %lld.%06u for domain %s: %s\n", + event, seconds, micros, virDomainGetName(dom), NULLSTR(details)); + data->count++; + if (!data->loop) + vshEventDone(data->ctl); + + VIR_FREE(str); +} + +static const vshCmdInfo info_qemu_monitor_event[] = { + {.name = "help", + .data = N_("QEMU Monitor Events") + }, + {.name = "desc", + .data = N_("Listen for QEMU Monitor Events") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_qemu_monitor_event[] = { + {.name = "domain", + .type = VSH_OT_DATA, + .help = N_("filter by domain name, id or uuid") + }, + {.name = "event", + .type = VSH_OT_DATA, + .help = N_("filter by event name") + }, + {.name = "pretty", + .type = VSH_OT_BOOL, + .help = N_("pretty-print any JSON output") + }, + {.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 = NULL} +}; + +static bool +cmdQemuMonitorEvent(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + unsigned int flags = 0; + int eventId = -1; + int timeout = 0; + const char *event = NULL; + vshQemuEventData data; + + data.ctl = ctl; + data.loop = vshCommandOptBool(cmd, "loop"); + data.pretty = vshCommandOptBool(cmd, "pretty"); + data.count = 0; + if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) + return false; + if (vshCommandOptString(cmd, "event", &event) < 0) + return false; + + if (vshCommandOptBool(cmd, "domain")) + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (vshEventStart(ctl, timeout) < 0) + goto cleanup; + + if ((eventId = virConnectDomainQemuMonitorEventRegister(ctl->conn, dom, + event, + vshEventPrint, + &data, NULL, + flags)) < 0) + goto cleanup; + switch (vshEventWait(ctl)) { + case VSH_EVENT_INTERRUPT: + vshPrint(ctl, _("event loop interrupted\n")); + break; + case VSH_EVENT_TIMEOUT: + vshPrint(ctl, _("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 && + virConnectDomainQemuMonitorEventDeregister(ctl->conn, eventId) < 0) + ret = false; + if (dom) + virDomainFree(dom); + + return ret; +} + +/* * "qemu-attach" command */ static const vshCmdInfo info_qemu_attach[] = { @@ -11546,6 +11675,12 @@ const vshCmdDef domManagementCmds[] = { .info = info_qemu_monitor_command, .flags = 0 }, + {.name = "qemu-monitor-event", + .handler = cmdQemuMonitorEvent, + .opts = opts_qemu_monitor_event, + .info = info_qemu_monitor_event, + .flags = 0 + }, {.name = "qemu-agent-command", .handler = cmdQemuAgentCommand, .opts = opts_qemu_agent_command, diff --git a/tools/virsh.pod b/tools/virsh.pod index cefce1b..35acd96 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -3311,12 +3311,15 @@ variables, and defaults to C<vi>. =back -=head1 QEMU-SPECIFIC COMMANDS +=head1 HYPERVISOR-SPECIFIC COMMANDS NOTE: Use of the following commands is B<strongly> discouraged. They can cause libvirt to become confused and do the wrong thing on subsequent -operations. Once you have used this command, please do not report -problems to the libvirt developers; the reports will be ignored. +operations. Once you have used these commands, please do not report +problems to the libvirt developers; the reports will be ignored. If +you find that these commands are the only way to accomplish something, +then it is better to request that the feature be added as a first-class +citizen in the regular libvirt library. =over 4 @@ -3355,7 +3358,8 @@ and the monitor uses QMP, then the output will be pretty-printed. If more than one argument is provided for I<command>, they are concatenated with a space in between before passing the single command to the monitor. -=item B<qemu-agent-command> I<domain> [I<--timeout> I<seconds> | I<--async> | I<--block>] I<command>... +=item B<qemu-agent-command> I<domain> [I<--timeout> I<seconds> | I<--async> | +I<--block>] I<command>... Send an arbitrary guest agent command I<command> to domain I<domain> through qemu agent. @@ -3365,6 +3369,21 @@ When I<--aysnc> is given, the command waits for timeout whether success or failed. And when I<--block> is given, the command waits forever with blocking timeout. +=item B<qemu-monitor-event> [I<domain>] [I<--event> I<event-name>] [I<--loop>] +[I<--timeout> I<seconds>] [I<--pretty>] + +Wait for arbitrary QEMU monitor events to occur, and print out the +details of events as they happen. The events can optionally be filtered +by I<domain> or I<event-name>. The 'query-events' QMP command can be +used via I<qemu-monitor-command> to learn what events are supported. + +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. If I<--pretty> is specified, +any JSON event details are pretty-printed for better legibility. + =item B<lxc-enter-namespace> I<domain> -- /path/to/binary [arg1, [arg2, ...]] Enter the namespace of I<domain> and execute the command C</path/to/binary> -- 1.8.5.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list