qemu: virsh wrapper for qemu events

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>
This commit is contained in:
Eric Blake 2014-01-31 16:52:17 -07:00
parent 2629520342
commit 88996de1c3
2 changed files with 158 additions and 4 deletions

View 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,

View 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>