From 4421e257dd29ccf5144984d902819828c4b90268 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Wed, 19 Jun 2013 15:27:29 +0200 Subject: [PATCH] Add VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED event --- daemon/remote.c | 32 ++++++++++ include/libvirt/libvirt.h.in | 18 ++++++ python/libvirt-override-virConnect.py | 9 +++ python/libvirt-override.c | 52 +++++++++++++++- src/conf/domain_event.c | 85 +++++++++++++++++++++------ src/conf/domain_event.h | 5 ++ src/libvirt_private.syms | 2 + src/remote/remote_driver.c | 32 ++++++++++ src/remote/remote_protocol.x | 13 +++- src/remote_protocol-structs | 5 ++ 10 files changed, 233 insertions(+), 20 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index a1b571c6dc..03d55578f5 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -600,6 +600,37 @@ static int remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn ATTRIBUTE_UNUS return 0; } +static int +remoteRelayDomainEventDeviceRemoved(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *devAlias, + void *opaque) +{ + virNetServerClientPtr client = opaque; + remote_domain_event_device_removed_msg data; + + if (!client) + return -1; + + VIR_DEBUG("Relaying domain device removed event %s %d %s", + dom->name, dom->id, devAlias); + + /* build return data */ + memset(&data, 0, sizeof(data)); + + if (VIR_STRDUP(data.devAlias, devAlias) < 0) + return -1; + + make_nonnull_domain(&data.dom, dom); + + remoteDispatchDomainEventSend(client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED, + (xdrproc_t)xdr_remote_domain_event_device_removed_msg, + &data); + + return 0; +} + static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), @@ -617,6 +648,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved), }; verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 01dc3a7302..c0eb25bdc7 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4864,6 +4864,23 @@ typedef void (*virConnectDomainEventPMSuspendDiskCallback)(virConnectPtr conn, int reason, void *opaque); +/** + * virConnectDomainEventDeviceRemovedCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @devAlias: device alias + * @opaque: application specified data + * + * This callback occurs when a device is removed from the domain. + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED with virConnectDomainEventRegisterAny() + */ +typedef void (*virConnectDomainEventDeviceRemovedCallback)(virConnectPtr conn, + virDomainPtr dom, + const char *devAlias, + void *opaque); + /** * VIR_DOMAIN_EVENT_CALLBACK: @@ -4890,6 +4907,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_PMSUSPEND = 12, /* virConnectDomainEventPMSuspendCallback */ VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE = 13, /* virConnectDomainEventBalloonChangeCallback */ VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK = 14, /* virConnectDomainEventPMSuspendDiskCallback */ + VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED = 15, /* virConnectDomainEventDeviceRemovedCallback */ #ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index a0f579d56e..044faa01d0 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -179,6 +179,15 @@ cb(self, virDomain(self, _obj=dom), reason, opaque) return 0 + def _dispatchDomainEventDeviceRemovedCallback(self, dom, devAlias, cbData): + """Dispatches event to python user domain device removed event callbacks + """ + cb = cbData["cb"] + opaque = cbData["opaque"] + + cb(self, virDomain(self, _obj=dom), devAlias, opaque) + return 0 + def domainEventDeregisterAny(self, callbackID): """Removes a Domain Event Callback. De-registering for a domain callback will disable delivery of this event type """ diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 0a108877fb..d16b9a2f96 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -6225,6 +6225,51 @@ libvirt_virConnectDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_ return ret; } +static int +libvirt_virConnectDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *devAlias, + void *opaque) +{ + PyObject *pyobj_cbData = (PyObject*)opaque; + PyObject *pyobj_dom; + PyObject *pyobj_ret; + PyObject *pyobj_conn; + PyObject *dictKey; + int ret = -1; + + LIBVIRT_ENSURE_THREAD_STATE; + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + + pyobj_dom = libvirt_virDomainPtrWrap(dom); + Py_INCREF(pyobj_cbData); + + dictKey = libvirt_constcharPtrWrap("conn"); + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + + /* Call the Callback Dispatcher */ + pyobj_ret = PyObject_CallMethod(pyobj_conn, + (char*)"_dispatchDomainEventDeviceRemovedCallback", + (char*)"OsO", + pyobj_dom, devAlias, pyobj_cbData); + + Py_DECREF(pyobj_cbData); + Py_DECREF(pyobj_dom); + + if (!pyobj_ret) { + DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); + PyErr_Print(); + } else { + Py_DECREF(pyobj_ret); + ret = 0; + } + + LIBVIRT_RELEASE_THREAD_STATE; + return ret; +} + static PyObject * libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self, PyObject * args) @@ -6254,7 +6299,7 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self, else dom = PyvirDomain_Get(pyobj_dom); - switch (eventID) { + switch ((virDomainEventID) eventID) { case VIR_DOMAIN_EVENT_ID_LIFECYCLE: cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventLifecycleCallback); break; @@ -6300,6 +6345,11 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self, case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK: cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventPMSuspendDiskCallback); break; + case VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED: + cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventDeviceRemovedCallback); + + case VIR_DOMAIN_EVENT_ID_LAST: + break; } if (!cb) { diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index fde24be677..640463c258 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -122,6 +122,9 @@ struct _virDomainEvent { /* In unit of 1024 bytes */ unsigned long long actual; } balloonChange; + struct { + char *devAlias; + } deviceRemoved; } data; }; @@ -1157,6 +1160,44 @@ virDomainEventPtr virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj, return ev; } +static virDomainEventPtr +virDomainEventDeviceRemovedNew(int id, + const char *name, + unsigned char *uuid, + const char *devAlias) +{ + virDomainEventPtr ev = + virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, + id, name, uuid); + + if (ev) { + if (VIR_STRDUP(ev->data.deviceRemoved.devAlias, devAlias) < 0) + goto error; + } + + return ev; + +error: + virDomainEventFree(ev); + return NULL; +} + +virDomainEventPtr +virDomainEventDeviceRemovedNewFromObj(virDomainObjPtr obj, + const char *devAlias) +{ + return virDomainEventDeviceRemovedNew(obj->def->id, obj->def->name, + obj->def->uuid, devAlias); +} + +virDomainEventPtr +virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom, + const char *devAlias) +{ + return virDomainEventDeviceRemovedNew(dom->id, dom->name, dom->uuid, + devAlias); +} + /** * virDomainEventQueuePush: * @evtQueue: the dom event queue @@ -1204,30 +1245,30 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, return; dom->id = event->dom.id; - switch (event->eventID) { + switch ((virDomainEventID) event->eventID) { case VIR_DOMAIN_EVENT_ID_LIFECYCLE: ((virConnectDomainEventCallback)cb)(conn, dom, event->data.lifecycle.type, event->data.lifecycle.detail, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_REBOOT: (cb)(conn, dom, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_RTC_CHANGE: ((virConnectDomainEventRTCChangeCallback)cb)(conn, dom, event->data.rtcChange.offset, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_WATCHDOG: ((virConnectDomainEventWatchdogCallback)cb)(conn, dom, event->data.watchdog.action, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_IO_ERROR: ((virConnectDomainEventIOErrorCallback)cb)(conn, dom, @@ -1235,7 +1276,7 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, event->data.ioError.devAlias, event->data.ioError.action, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON: ((virConnectDomainEventIOErrorReasonCallback)cb)(conn, dom, @@ -1244,7 +1285,7 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, event->data.ioError.action, event->data.ioError.reason, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_GRAPHICS: ((virConnectDomainEventGraphicsCallback)cb)(conn, dom, @@ -1254,12 +1295,12 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, event->data.graphics.authScheme, event->data.graphics.subject, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR: (cb)(conn, dom, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_BLOCK_JOB: ((virConnectDomainEventBlockJobCallback)cb)(conn, dom, @@ -1267,7 +1308,7 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, event->data.blockJob.type, event->data.blockJob.status, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_DISK_CHANGE: ((virConnectDomainEventDiskChangeCallback)cb)(conn, dom, @@ -1276,38 +1317,46 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, event->data.diskChange.devAlias, event->data.diskChange.reason, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_TRAY_CHANGE: ((virConnectDomainEventTrayChangeCallback)cb)(conn, dom, event->data.trayChange.devAlias, event->data.trayChange.reason, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_PMWAKEUP: ((virConnectDomainEventPMWakeupCallback)cb)(conn, dom, 0, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_PMSUSPEND: ((virConnectDomainEventPMSuspendCallback)cb)(conn, dom, 0, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE: ((virConnectDomainEventBalloonChangeCallback)cb)(conn, dom, event->data.balloonChange.actual, cbopaque); - break; + goto cleanup; case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK: ((virConnectDomainEventPMSuspendDiskCallback)cb)(conn, dom, 0, cbopaque); - break; + goto cleanup; - default: - VIR_WARN("Unexpected event ID %d", event->eventID); + case VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED: + ((virConnectDomainEventDeviceRemovedCallback)cb)(conn, dom, + event->data.deviceRemoved.devAlias, + cbopaque); + goto cleanup; + + case VIR_DOMAIN_EVENT_ID_LAST: break; } + VIR_WARN("Unexpected event ID %d", event->eventID); + +cleanup: virDomainFree(dom); } diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index 5f64a474c5..f6b957d596 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -132,6 +132,11 @@ virDomainEventPtr virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj, uns virDomainEventPtr virDomainEventPMSuspendDiskNewFromObj(virDomainObjPtr obj); virDomainEventPtr virDomainEventPMSuspendDiskNewFromDom(virDomainPtr dom); +virDomainEventPtr virDomainEventDeviceRemovedNewFromObj(virDomainObjPtr obj, + const char *devAlias); +virDomainEventPtr virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom, + const char *devAlias); + void virDomainEventFree(virDomainEventPtr event); void virDomainEventStateFree(virDomainEventStatePtr state); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ba9db26fd3..78a56db029 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -408,6 +408,8 @@ virDomainEventBlockJobNewFromDom; virDomainEventBlockJobNewFromObj; virDomainEventControlErrorNewFromDom; virDomainEventControlErrorNewFromObj; +virDomainEventDeviceRemovedNewFromDom; +virDomainEventDeviceRemovedNewFromObj; virDomainEventDiskChangeNewFromDom; virDomainEventDiskChangeNewFromObj; virDomainEventFree; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index eb06bfdf6b..f828eef3a1 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -268,6 +268,11 @@ remoteDomainBuildEventPMSuspendDisk(virNetClientProgramPtr prog, virNetClientPtr client, void *evdata, void *opaque); +static void +remoteDomainBuildEventDeviceRemoved(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); + static virNetClientProgramEvent remoteDomainEvents[] = { { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE, remoteDomainBuildEventRTCChange, @@ -329,6 +334,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = { remoteDomainBuildEventPMSuspendDisk, sizeof(remote_domain_event_pmsuspend_disk_msg), (xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg }, + { REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED, + remoteDomainBuildEventDeviceRemoved, + sizeof(remote_domain_event_device_removed_msg), + (xdrproc_t)xdr_remote_domain_event_device_removed_msg }, }; enum virDrvOpenRemoteFlags { @@ -4683,6 +4692,29 @@ remoteDomainBuildEventPMSuspendDisk(virNetClientProgramPtr prog ATTRIBUTE_UNUSED } +static void +remoteDomainBuildEventDeviceRemoved(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_device_removed_msg *msg = evdata; + virDomainPtr dom; + virDomainEventPtr event = NULL; + + dom = get_nonnull_domain(conn, msg->dom); + if (!dom) + return; + + event = virDomainEventDeviceRemovedNewFromDom(dom, msg->devAlias); + + virDomainFree(dom); + + remoteDomainEventQueue(priv, event); +} + + static virDrvOpenStatus ATTRIBUTE_NONNULL(1) remoteSecretOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags) diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index b48c1167fa..7cfebdf86c 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2832,6 +2832,11 @@ struct remote_domain_migrate_confirm3_params_args { int cancelled; }; +struct remote_domain_event_device_removed_msg { + remote_nonnull_domain dom; + remote_nonnull_string devAlias; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -4989,5 +4994,11 @@ enum remote_procedure { * @generate: none * @acl: domain:start */ - REMOTE_PROC_DOMAIN_CREATE_WITH_FILES = 310 + REMOTE_PROC_DOMAIN_CREATE_WITH_FILES = 310, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index fcd6c6699f..4e27aae81d 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2312,6 +2312,10 @@ struct remote_domain_migrate_confirm3_params_args { u_int flags; int cancelled; }; +struct remote_domain_event_device_removed_msg { + remote_nonnull_domain dom; + remote_nonnull_string devAlias; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -2623,4 +2627,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SET_MEMORY_STATS_PERIOD = 308, REMOTE_PROC_DOMAIN_CREATE_XML_WITH_FILES = 309, REMOTE_PROC_DOMAIN_CREATE_WITH_FILES = 310, + REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311, };