From 8613273458f3df4ac9fb4eadd0fcd504fe72ced0 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 18 Mar 2010 15:25:38 +0000 Subject: [PATCH] Add support for an explicit guest reboot event The reboot event is not a normal lifecycle event, since the virtual machine on the host does not change state. Rather the guest OS is resetting the virtual CPUs. ie, the QEMU process does not restart. Thus, this does not belong in the current lifecycle events callback. This introduces a new event type VIR_DOMAIN_EVENT_ID_REBOOT It takes no parameters, besides the virDomainPtr, so it can use the generic callback signature. * daemon/remote.c: Dispatch reboot events to client * examples/domain-events/events-c/event-test.c: Watch for reboot events * include/libvirt/libvirt.h.in: Define new reboot event ID * src/conf/domain_event.c, src/conf/domain_event.h, src/libvirt_private.syms: Extend API to handle reboot events * src/qemu/qemu_driver.c: Connect to the QEMU monitor event for reboots and emit a libvirt reboot event * src/remote/remote_driver.c: Receive and dispatch reboot events to application * src/remote/remote_protocol.x: Wire protocol definition for reboot events --- daemon/remote.c | 30 ++++++++++++++++++- daemon/remote_dispatch_table.h | 5 ++++ examples/domain-events/events-c/event-test.c | 20 ++++++++++++- include/libvirt/libvirt.h.in | 1 + src/conf/domain_event.c | 16 ++++++++++ src/conf/domain_event.h | 3 ++ src/libvirt_private.syms | 2 ++ src/qemu/qemu_driver.c | 23 +++++++++++++++ src/remote/remote_driver.c | 31 ++++++++++++++++++++ src/remote/remote_protocol.c | 9 ++++++ src/remote/remote_protocol.h | 8 +++++ src/remote/remote_protocol.x | 6 +++- 12 files changed, 151 insertions(+), 3 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index aa42d8234a..284e47cf8b 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -129,9 +129,37 @@ static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED, return 0; } +static int remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + void *opaque) +{ + struct qemud_client *client = opaque; + remote_domain_event_reboot_msg data; -static virConnectDomainEventGenericCallback domainEventCallbacks[VIR_DOMAIN_EVENT_ID_LAST] = { + if (!client) + return -1; + + REMOTE_DEBUG("Relaying domain reboot event %s %d", dom->name, dom->id); + + virMutexLock(&client->lock); + + /* build return data */ + memset(&data, 0, sizeof data); + make_nonnull_domain (&data.dom, dom); + + remoteDispatchDomainEventSend (client, + REMOTE_PROC_DOMAIN_EVENT_REBOOT, + (xdrproc_t)xdr_remote_domain_event_reboot_msg, &data); + + virMutexUnlock(&client->lock); + + return 0; +} + + +static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), }; verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index 8bbaf6181a..13a853cd5e 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -847,3 +847,8 @@ .args_filter = (xdrproc_t) xdr_remote_domain_events_deregister_any_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* Async event DomainEventReboot => 169 */ + .fn = NULL, + .args_filter = (xdrproc_t) xdr_void, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c index ed00fb859c..c7da0c0fe8 100644 --- a/examples/domain-events/events-c/event-test.c +++ b/examples/domain-events/events-c/event-test.c @@ -172,6 +172,16 @@ static int myDomainEventCallback2(virConnectPtr conn ATTRIBUTE_UNUSED, return 0; } +static int myDomainEventRebootCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) rebooted\n", __func__, virDomainGetName(dom), + virDomainGetID(dom)); + + return 0; +} + static void myFreeFunc(void *opaque) { char *str = opaque; @@ -289,6 +299,7 @@ int main(int argc, char **argv) int sts; int callback1ret = -1; int callback2ret = -1; + int callback3ret = -1; struct sigaction action_stop = { .sa_handler = stop @@ -326,9 +337,15 @@ int main(int argc, char **argv) VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2), strdup("callback 2"), myFreeFunc); + callback3ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_REBOOT, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRebootCallback), + strdup("callback reboot"), myFreeFunc); if ((callback1ret != -1) && - (callback2ret != -1)) { + (callback2ret != -1) && + (callback3ret != -1)) { while(run) { struct pollfd pfd = { .fd = h_fd, .events = h_event, @@ -366,6 +383,7 @@ int main(int argc, char **argv) DEBUG0("Deregistering event handlers"); virConnectDomainEventDeregister(dconn, myDomainEventCallback1); virConnectDomainEventDeregisterAny(dconn, callback2ret); + virConnectDomainEventDeregisterAny(dconn, callback3ret); } diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 35c3891a2c..39970da4b1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1874,6 +1874,7 @@ typedef void (*virConnectDomainEventGenericCallback)(virConnectPtr conn, typedef enum { VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0, /* virConnectDomainEventCallback */ + VIR_DOMAIN_EVENT_ID_REBOOT = 1, /* virConnectDomainEventGenericCallback */ /* * NB: this enum value will increase over time as new events are diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index d739332113..57fd851651 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -523,6 +523,17 @@ virDomainEventPtr virDomainEventNewFromDef(virDomainDefPtr def, int type, int de return virDomainEventNew(def->id, def->name, def->uuid, type, detail); } +virDomainEventPtr virDomainEventRebootNewFromDom(virDomainPtr dom) +{ + return virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_REBOOT, + dom->id, dom->name, dom->uuid); +} +virDomainEventPtr virDomainEventRebootNewFromObj(virDomainObjPtr obj) +{ + return virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_REBOOT, + obj->def->id, obj->def->name, obj->def->uuid); +} + /** * virDomainEventQueueFree: * @queue: pointer to the queue @@ -628,6 +639,11 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn, cbopaque); break; + case VIR_DOMAIN_EVENT_ID_REBOOT: + (cb)(conn, dom, + cbopaque); + break; + default: VIR_WARN("Unexpected event ID %d", event->eventID); break; diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index db5ad5b94c..7fb0928d27 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -112,6 +112,9 @@ virDomainEventPtr virDomainEventNewFromDom(virDomainPtr dom, int type, int detai virDomainEventPtr virDomainEventNewFromObj(virDomainObjPtr obj, int type, int detail); virDomainEventPtr virDomainEventNewFromDef(virDomainDefPtr def, int type, int detail); +virDomainEventPtr virDomainEventRebootNewFromDom(virDomainPtr dom); +virDomainEventPtr virDomainEventRebootNewFromObj(virDomainObjPtr obj); + int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue, virDomainEventPtr event); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 19918e5a70..471ea1b41a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -214,6 +214,8 @@ virDomainEventNew; virDomainEventNewFromDom; virDomainEventNewFromObj; virDomainEventNewFromDef; +virDomainEventRebootNewFromDom; +virDomainEventRebootNewFromObj; virDomainEventFree; virDomainEventDispatchDefaultFunc; virDomainEventDispatch; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index cfd82da17d..6ab170a777 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -864,9 +864,32 @@ cleanup: return ret; } + +static int +qemuHandleDomainReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm) +{ + struct qemud_driver *driver = qemu_driver; + virDomainEventPtr event; + + virDomainObjLock(vm); + event = virDomainEventRebootNewFromObj(vm); + virDomainObjUnlock(vm); + + if (event) { + qemuDriverLock(driver); + qemuDomainEventQueue(driver, event); + qemuDriverUnlock(driver); + } + + return 0; +} + + static qemuMonitorCallbacks monitorCallbacks = { .eofNotify = qemuHandleMonitorEOF, .diskSecretLookup = findVolumeQcowPassphrase, + .domainReset = qemuHandleDomainReset, }; static int diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 085e45fd88..17d61138d6 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6913,6 +6913,33 @@ remoteDomainReadEventLifecycle(virConnectPtr conn, XDR *xdr) } +static virDomainEventPtr +remoteDomainReadEventReboot(virConnectPtr conn, XDR *xdr) +{ + remote_domain_event_reboot_msg msg; + virDomainPtr dom; + virDomainEventPtr event = NULL; + memset (&msg, 0, sizeof msg); + + /* unmarshall parameters, and process it*/ + if (! xdr_remote_domain_event_reboot_msg(xdr, &msg) ) { + error (conn, VIR_ERR_RPC, + _("unable to demarshall reboot event")); + return NULL; + } + + dom = get_nonnull_domain(conn,msg.dom); + if (!dom) + return NULL; + + event = virDomainEventRebootNewFromDom(dom); + xdr_free ((xdrproc_t) &xdr_remote_domain_event_reboot_msg, (char *) &msg); + + virDomainFree(dom); + return event; +} + + static virDrvOpenStatus ATTRIBUTE_NONNULL (1) remoteSecretOpen (virConnectPtr conn, virConnectAuthPtr auth, @@ -8456,6 +8483,10 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, event = remoteDomainReadEventLifecycle(conn, xdr); break; + case REMOTE_PROC_DOMAIN_EVENT_REBOOT: + event = remoteDomainReadEventReboot(conn, xdr); + break; + default: DEBUG("Unexpected event proc %d", hdr->proc); break; diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 9aaecccdf0..af56c259e4 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -3050,6 +3050,15 @@ xdr_remote_domain_events_deregister_any_args (XDR *xdrs, remote_domain_events_de return TRUE; } +bool_t +xdr_remote_domain_event_reboot_msg (XDR *xdrs, remote_domain_event_reboot_msg *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + return TRUE; +} + bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index 59cdc7bdd8..8266294f8b 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -1727,6 +1727,11 @@ struct remote_domain_events_deregister_any_args { int eventID; }; typedef struct remote_domain_events_deregister_any_args remote_domain_events_deregister_any_args; + +struct remote_domain_event_reboot_msg { + remote_nonnull_domain dom; +}; +typedef struct remote_domain_event_reboot_msg remote_domain_event_reboot_msg; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -1899,6 +1904,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 166, REMOTE_PROC_DOMAIN_EVENTS_REGISTER_ANY = 167, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER_ANY = 168, + REMOTE_PROC_DOMAIN_EVENT_REBOOT = 169, }; typedef enum remote_procedure remote_procedure; @@ -2212,6 +2218,7 @@ extern bool_t xdr_remote_domain_abort_job_args (XDR *, remote_domain_abort_job_ extern bool_t xdr_remote_domain_migrate_set_max_downtime_args (XDR *, remote_domain_migrate_set_max_downtime_args*); extern bool_t xdr_remote_domain_events_register_any_args (XDR *, remote_domain_events_register_any_args*); extern bool_t xdr_remote_domain_events_deregister_any_args (XDR *, remote_domain_events_deregister_any_args*); +extern bool_t xdr_remote_domain_event_reboot_msg (XDR *, remote_domain_event_reboot_msg*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -2499,6 +2506,7 @@ extern bool_t xdr_remote_domain_abort_job_args (); extern bool_t xdr_remote_domain_migrate_set_max_downtime_args (); extern bool_t xdr_remote_domain_events_register_any_args (); extern bool_t xdr_remote_domain_events_deregister_any_args (); +extern bool_t xdr_remote_domain_event_reboot_msg (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 12fe67c9a3..0419e7b326 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1536,6 +1536,9 @@ struct remote_domain_events_deregister_any_args { int eventID; }; +struct remote_domain_event_reboot_msg { + remote_nonnull_domain dom; +}; /*----- Protocol. -----*/ @@ -1727,7 +1730,8 @@ enum remote_procedure { REMOTE_PROC_STORAGE_VOL_WIPE = 165, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 166, REMOTE_PROC_DOMAIN_EVENTS_REGISTER_ANY = 167, - REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER_ANY = 168 + REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER_ANY = 168, + REMOTE_PROC_DOMAIN_EVENT_REBOOT = 169 /* * Notice how the entries are grouped in sets of 10 ?