]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
qemu: virsh wrapper for qemu events
authorEric Blake <eblake@redhat.com>
Fri, 31 Jan 2014 23:52:17 +0000 (16:52 -0700)
committerEric Blake <eblake@redhat.com>
Thu, 20 Mar 2014 17:25:37 +0000 (11:25 -0600)
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@redhat.com>
tools/virsh-domain.c
tools/virsh.pod

index cb6bf63da12204493c96b18096ccc787f106b37f..fe15dbfad75242a37914574d1dbaa65f8a944c0d 100644 (file)
@@ -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,
index 0fb8248a780f718aece57478aff0d965aa45ad41..791c66f7af31638141a02034a92c9fef80b177b8 100644 (file)
@@ -3326,12 +3326,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
 
@@ -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<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.
@@ -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<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>