From 88996de1c32a97fa544144ab7402649f753ee3a3 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 31 Jan 2014 16:52:17 -0700 Subject: [PATCH] qemu: virsh wrapper for qemu events Any new API deserves a good virsh wrapper :) qemu-monitor-event [] [] [--pretty] [--loop] [--timeout ] 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 --- 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 cb6bf63da1..fe15dbfad7 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -7915,6 +7915,135 @@ cleanup: return ret; } +/* + * "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 */ @@ -11550,6 +11679,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 0fb8248a78..791c66f7af 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -3326,12 +3326,15 @@ variables, and defaults to C. =back -=head1 QEMU-SPECIFIC COMMANDS +=head1 HYPERVISOR-SPECIFIC COMMANDS NOTE: Use of the following commands is B 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 @@ -3370,7 +3373,8 @@ and the monitor uses QMP, then the output will be pretty-printed. If more than one argument is provided for I, they are concatenated with a space in between before passing the single command to the monitor. -=item B I [I<--timeout> I | I<--async> | I<--block>] I... +=item B I [I<--timeout> I | I<--async> | +I<--block>] I... Send an arbitrary guest agent command I to domain I through qemu agent. @@ -3380,6 +3384,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 [I] [I<--event> I] [I<--loop>] +[I<--timeout> I] [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 or I. The 'query-events' QMP command can be +used via I 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) to quit immediately. +If I<--timeout> is specified, the command gives up waiting for events +after I 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 I -- /path/to/binary [arg1, [arg2, ...]] Enter the namespace of I and execute the command C -- GitLab