mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
qemu: allow filtering events by regex
When listening for a subset of monitor events, it can be tedious to register for each event name in series; nicer is to register for multiple events in one go. Implement a flag to use regex interpretation of the event filter. While at it, prove how much I hate the shift key, by adding a way to filter for 'shutdown' instead of 'SHUTDOWN'. :) * include/libvirt/libvirt-qemu.h (virConnectDomainQemuMonitorEventRegisterFlags): New enum. * src/libvirt-qemu.c (virConnectDomainQemuMonitorEventRegister): Document flags. * tools/virsh-domain.c (cmdQemuMonitorEvent): Expose them. * tools/virsh.pod (qemu-monitor-event): Document this. * src/conf/domain_event.c (virDomainQemuMonitorEventStateRegisterID): Add flags. (virDomainQemuMonitorEventFilter): Handle regex, and optimize client side. (virDomainQemuMonitorEventCleanup): Clean up regex. Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
d0ba8dd764
commit
43b17dd444
@ -76,6 +76,16 @@ typedef void (*virConnectDomainQemuMonitorEventCallback)(virConnectPtr conn,
|
||||
const char *details,
|
||||
void *opaque);
|
||||
|
||||
|
||||
typedef enum {
|
||||
/* Event filter is a regex rather than a literal string */
|
||||
VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX = (1 << 0),
|
||||
|
||||
/* Event filter is case insensitive */
|
||||
VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE = (1 << 1),
|
||||
} virConnectDomainQemuMonitorEventRegisterFlags;
|
||||
|
||||
|
||||
int virConnectDomainQemuMonitorEventRegister(virConnectPtr conn,
|
||||
virDomainPtr dom,
|
||||
const char *event,
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
#include "domain_event.h"
|
||||
#include "object_event.h"
|
||||
#include "object_event_private.h"
|
||||
@ -1390,6 +1392,8 @@ error:
|
||||
* deregisters. */
|
||||
struct virDomainQemuMonitorEventData {
|
||||
char *event;
|
||||
regex_t regex;
|
||||
unsigned int flags;
|
||||
void *opaque;
|
||||
virFreeCallback freecb;
|
||||
};
|
||||
@ -1609,6 +1613,12 @@ virDomainQemuMonitorEventFilter(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
|
||||
monitorEvent = (virDomainQemuMonitorEventPtr) event;
|
||||
|
||||
if (data->flags == -1)
|
||||
return true;
|
||||
if (data->flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX)
|
||||
return regexec(&data->regex, monitorEvent->event, 0, NULL, 0) == 0;
|
||||
if (data->flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE)
|
||||
return STRCASEEQ(monitorEvent->event, data->event);
|
||||
return STREQ(monitorEvent->event, data->event);
|
||||
}
|
||||
|
||||
@ -1619,6 +1629,8 @@ virDomainQemuMonitorEventCleanup(void *opaque)
|
||||
virDomainQemuMonitorEventData *data = opaque;
|
||||
|
||||
VIR_FREE(data->event);
|
||||
if (data->flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX)
|
||||
regfree(&data->regex);
|
||||
if (data->freecb)
|
||||
(data->freecb)(data->opaque);
|
||||
VIR_FREE(data);
|
||||
@ -1634,7 +1646,8 @@ virDomainQemuMonitorEventCleanup(void *opaque)
|
||||
* @cb: function to invoke when event occurs
|
||||
* @opaque: data blob to pass to callback
|
||||
* @freecb: callback to free @opaque
|
||||
* @flags: -1 for client, or set of registration flags on server
|
||||
* @flags: -1 for client, valid virConnectDomainQemuMonitorEventRegisterFlags
|
||||
* for server
|
||||
* @callbackID: filled with callback ID
|
||||
*
|
||||
* Register the function @cb with connection @conn, from @state, for
|
||||
@ -1660,12 +1673,34 @@ virDomainQemuMonitorEventStateRegisterID(virConnectPtr conn,
|
||||
return -1;
|
||||
|
||||
if (flags != -1)
|
||||
virCheckFlags(0, -1);
|
||||
virCheckFlags(VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX |
|
||||
VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE,
|
||||
-1);
|
||||
if (VIR_ALLOC(data) < 0)
|
||||
return -1;
|
||||
if (VIR_STRDUP(data->event, event) < 0) {
|
||||
VIR_FREE(data);
|
||||
return -1;
|
||||
data->flags = flags;
|
||||
if (flags != -1) {
|
||||
int rflags = REG_NOSUB;
|
||||
|
||||
if (flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE)
|
||||
rflags |= REG_ICASE;
|
||||
if (flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX) {
|
||||
int err = regcomp(&data->regex, event, rflags);
|
||||
|
||||
if (err) {
|
||||
char error[100];
|
||||
regerror(err, &data->regex, error, sizeof(error));
|
||||
virReportError(VIR_ERR_INVALID_ARG,
|
||||
_("failed to compile regex '%s': %s"),
|
||||
event, error);
|
||||
regfree(&data->regex);
|
||||
VIR_FREE(data);
|
||||
return -1;
|
||||
}
|
||||
} else if (VIR_STRDUP(data->event, event) < 0) {
|
||||
VIR_FREE(data);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
data->opaque = opaque;
|
||||
data->freecb = freecb;
|
||||
|
@ -227,7 +227,7 @@ error:
|
||||
* @cb: callback to the function handling monitor events
|
||||
* @opaque: opaque data to pass on to the callback
|
||||
* @freecb: optional function to deallocate opaque when not used anymore
|
||||
* @flags: extra flags; not used yet, so callers should always pass 0
|
||||
* @flags: bitwise-OR of virConnectDomainQemuMonitorEventRegisterFlags
|
||||
*
|
||||
* This API is QEMU specific, so it will only work with hypervisor
|
||||
* connections to the QEMU driver.
|
||||
@ -242,9 +242,12 @@ error:
|
||||
* is non-NULL, then only the specific domain will be monitored.
|
||||
*
|
||||
* If @event is NULL, then all monitor events will be reported. If @event is
|
||||
* non-NULL, then only the specific monitor event will be reported. @flags
|
||||
* is currently unused, but in the future may support a flag for passing
|
||||
* @event as a glob instead of a literal name to match a category of events.
|
||||
* non-NULL, then only specific monitor events will be reported. @flags
|
||||
* controls how the filtering is performed: 0 requests an exact match, while
|
||||
* VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX states that @event
|
||||
* is a basic regular expression. Additionally, including
|
||||
* VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE lets @event match
|
||||
* case-insensitively.
|
||||
*
|
||||
* The virDomainPtr object handle passed into the callback upon delivery
|
||||
* of an event is only valid for the duration of execution of the callback.
|
||||
|
@ -7983,6 +7983,14 @@ static const vshCmdOptDef opts_qemu_monitor_event[] = {
|
||||
.type = VSH_OT_INT,
|
||||
.help = N_("timeout seconds")
|
||||
},
|
||||
{.name = "regex",
|
||||
.type = VSH_OT_BOOL,
|
||||
.help = N_("treat event as a regex rather than literal filter")
|
||||
},
|
||||
{.name = "no-case",
|
||||
.type = VSH_OT_BOOL,
|
||||
.help = N_("treat event case-insensitively")
|
||||
},
|
||||
{.name = NULL}
|
||||
};
|
||||
|
||||
@ -7997,6 +8005,11 @@ cmdQemuMonitorEvent(vshControl *ctl, const vshCmd *cmd)
|
||||
const char *event = NULL;
|
||||
vshQemuEventData data;
|
||||
|
||||
if (vshCommandOptBool(cmd, "regex"))
|
||||
flags |= VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX;
|
||||
if (vshCommandOptBool(cmd, "no-case"))
|
||||
flags |= VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE;
|
||||
|
||||
data.ctl = ctl;
|
||||
data.loop = vshCommandOptBool(cmd, "loop");
|
||||
data.pretty = vshCommandOptBool(cmd, "pretty");
|
||||
|
@ -3385,12 +3385,15 @@ 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>]
|
||||
[I<--timeout> I<seconds>] [I<--pretty>] [I<--regex>] [I<--no-case>]
|
||||
|
||||
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.
|
||||
If I<--regex> is used, I<event-name> is a basic regular expression
|
||||
instead of a literal string. If I<--no-case> is used, I<event-name>
|
||||
will match case-insensitively.
|
||||
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user