From 3566599a2f19638538c98748e1271d2a7317be00 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 29 Jan 2014 17:14:44 -0700 Subject: [PATCH] qemu: enable monitor event reporting Wire up all the pieces to send arbitrary qemu events to a client using libvirt-qemu.so. If the extra bookkeeping of generating event objects even when no one is listening turns out to be noticeable, we can try to further optimize things by adding a counter for how many connections are using events, and only dump events when the counter is non-zero; but for now, I didn't think it was worth the code complexity. * src/qemu/qemu_driver.c (qemuConnectDomainQemuMonitorEventRegister) (qemuConnectDomainQemuMonitorEventDeregister): New functions. * src/qemu/qemu_monitor.h (qemuMonitorEmitEvent): New prototype. (qemuMonitorDomainEventCallback): New typedef. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONIOProcessEvent): Report events. * src/qemu/qemu_monitor.c (qemuMonitorEmitEvent): New function, to pass events through. * src/qemu/qemu_process.c (qemuProcessHandleEvent): Likewise. Signed-off-by: Eric Blake --- src/qemu/qemu_driver.c | 51 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 ++++++++++ src/qemu/qemu_monitor.h | 13 ++++++++- src/qemu/qemu_monitor_json.c | 21 ++++++++++++++- src/qemu/qemu_process.c | 29 ++++++++++++++++++++ 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 20239f1397..fdc3549775 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16355,6 +16355,55 @@ cleanup: return result; } + +static int +qemuConnectDomainQemuMonitorEventRegister(virConnectPtr conn, + virDomainPtr dom, + const char *event, + virConnectDomainQemuMonitorEventCallback callback, + void *opaque, + virFreeCallback freecb, + unsigned int flags) +{ + virQEMUDriverPtr driver = conn->privateData; + int ret = -1; + + if (virConnectDomainQemuMonitorEventRegisterEnsureACL(conn) < 0) + goto cleanup; + + if (virDomainQemuMonitorEventStateRegisterID(conn, + driver->domainEventState, + dom, event, callback, + opaque, freecb, flags, + &ret) < 0) + ret = -1; + +cleanup: + return ret; +} + + +static int +qemuConnectDomainQemuMonitorEventDeregister(virConnectPtr conn, + int callbackID) +{ + virQEMUDriverPtr driver = conn->privateData; + int ret = -1; + + if (virConnectDomainQemuMonitorEventDeregisterEnsureACL(conn) < 0) + goto cleanup; + + if (virObjectEventStateDeregisterID(conn, driver->domainEventState, + callbackID) < 0) + goto cleanup; + + ret = 0; + +cleanup: + return ret; +} + + static int qemuDomainFSTrim(virDomainPtr dom, const char *mountPoint, @@ -16688,6 +16737,8 @@ static virDriver qemuDriver = { .domainQemuMonitorCommand = qemuDomainQemuMonitorCommand, /* 0.8.3 */ .domainQemuAttach = qemuDomainQemuAttach, /* 0.9.4 */ .domainQemuAgentCommand = qemuDomainQemuAgentCommand, /* 0.10.0 */ + .connectDomainQemuMonitorEventRegister = qemuConnectDomainQemuMonitorEventRegister, /* 1.2.3 */ + .connectDomainQemuMonitorEventDeregister = qemuConnectDomainQemuMonitorEventDeregister, /* 1.2.3 */ .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */ .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */ .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 1783201872..5f8a5f4cbb 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1168,6 +1168,20 @@ int qemuMonitorGetDiskSecret(qemuMonitorPtr mon, } +int +qemuMonitorEmitEvent(qemuMonitorPtr mon, const char *event, + long long seconds, unsigned int micros, + const char *details) +{ + int ret = -1; + VIR_DEBUG("mon=%p event=%s", mon, event); + + QEMU_MONITOR_CALLBACK(mon, ret, domainEvent, mon->vm, event, seconds, + micros, details); + return ret; +} + + int qemuMonitorEmitShutdown(qemuMonitorPtr mon) { int ret = -1; diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 7bb465bea9..f626cc1223 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1,7 +1,7 @@ /* * qemu_monitor.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006-2014 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -90,6 +90,13 @@ typedef int (*qemuMonitorDiskSecretLookupCallback)(qemuMonitorPtr mon, char **secret, size_t *secretLen, void *opaque); +typedef int (*qemuMonitorDomainEventCallback)(qemuMonitorPtr mon, + virDomainObjPtr vm, + const char *event, + long long seconds, + unsigned int micros, + const char *details, + void *opaque); typedef int (*qemuMonitorDomainShutdownCallback)(qemuMonitorPtr mon, virDomainObjPtr vm, void *opaque); @@ -171,6 +178,7 @@ struct _qemuMonitorCallbacks { qemuMonitorEofNotifyCallback eofNotify; qemuMonitorErrorNotifyCallback errorNotify; qemuMonitorDiskSecretLookupCallback diskSecretLookup; + qemuMonitorDomainEventCallback domainEvent; qemuMonitorDomainShutdownCallback domainShutdown; qemuMonitorDomainResetCallback domainReset; qemuMonitorDomainPowerdownCallback domainPowerdown; @@ -236,6 +244,9 @@ int qemuMonitorGetDiskSecret(qemuMonitorPtr mon, char **secret, size_t *secretLen); +int qemuMonitorEmitEvent(qemuMonitorPtr mon, const char *event, + long long seconds, unsigned int micros, + const char *details); int qemuMonitorEmitShutdown(qemuMonitorPtr mon); int qemuMonitorEmitReset(qemuMonitorPtr mon); int qemuMonitorEmitPowerdown(qemuMonitorPtr mon); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index f38793315c..7a6aac0afe 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -129,6 +129,12 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon, { const char *type; qemuEventHandler *handler; + virJSONValuePtr data; + char *details = NULL; + virJSONValuePtr timestamp; + long long seconds = -1; + unsigned int micros = 0; + VIR_DEBUG("mon=%p obj=%p", mon, obj); type = virJSONValueObjectGetString(obj, "event"); @@ -138,10 +144,23 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon, return -1; } + /* Not all events have data; and event reporting is best-effort only */ + if ((data = virJSONValueObjectGet(obj, "data"))) + details = virJSONValueToString(data, false); + if ((timestamp = virJSONValueObjectGet(obj, "timestamp"))) { + virJSONValuePtr elt; + + if ((elt = virJSONValueObjectGet(timestamp, "seconds"))) + ignore_value(virJSONValueGetNumberLong(elt, &seconds)); + if ((elt = virJSONValueObjectGet(timestamp, "microseconds"))) + ignore_value(virJSONValueGetNumberUint(elt, µs)); + } + qemuMonitorEmitEvent(mon, type, seconds, micros, details); + VIR_FREE(details); + handler = bsearch(type, eventHandlers, ARRAY_CARDINALITY(eventHandlers), sizeof(eventHandlers[0]), qemuMonitorEventCompare); if (handler) { - virJSONValuePtr data = virJSONValueObjectGet(obj, "data"); VIR_DEBUG("handle %s handler=%p data=%p", type, handler->handler, data); (handler->handler)(mon, data); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 6c4543f0ef..73de945f35 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -648,6 +648,34 @@ qemuProcessShutdownOrReboot(virQEMUDriverPtr driver, } } + +static int +qemuProcessHandleEvent(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + const char *eventName, + long long seconds, + unsigned int micros, + const char *details, + void *opaque) +{ + virQEMUDriverPtr driver = opaque; + virObjectEventPtr event = NULL; + + VIR_DEBUG("vm=%p", vm); + + virObjectLock(vm); + event = virDomainQemuMonitorEventNew(vm->def->id, vm->def->name, + vm->def->uuid, eventName, + seconds, micros, details); + + virObjectUnlock(vm); + if (event) + qemuDomainEventQueue(driver, event); + + return 0; +} + + static int qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED, virDomainObjPtr vm, @@ -1369,6 +1397,7 @@ static qemuMonitorCallbacks monitorCallbacks = { .eofNotify = qemuProcessHandleMonitorEOF, .errorNotify = qemuProcessHandleMonitorError, .diskSecretLookup = qemuProcessFindVolumeQcowPassphrase, + .domainEvent = qemuProcessHandleEvent, .domainShutdown = qemuProcessHandleShutdown, .domainStop = qemuProcessHandleStop, .domainResume = qemuProcessHandleResume, -- GitLab