diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index aaefa098bb..35c3891a2c 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1857,6 +1857,44 @@ int virDomainGetJobInfo(virDomainPtr dom, int virDomainAbortJob(virDomainPtr dom); +/* A generic callback definition. Specific events usually have a customization + * with extra parameters */ +typedef void (*virConnectDomainEventGenericCallback)(virConnectPtr conn, + virDomainPtr dom, + void *opaque); + +/** + * VIR_DOMAIN_EVENT_CALLBACK: + * + * Used to cast the event specific callback into the generic one + * for use for virDomainEventRegister + */ +#define VIR_DOMAIN_EVENT_CALLBACK(cb) ((virConnectDomainEventGenericCallback)(cb)) + + +typedef enum { + VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0, /* virConnectDomainEventCallback */ + + /* + * NB: this enum value will increase over time as new events are + * added to the libvirt API. It reflects the last event ID supported + * by this version of the libvirt API. + */ + VIR_DOMAIN_EVENT_ID_LAST +} virDomainEventID; + + +/* Use VIR_DOMAIN_EVENT_CALLBACK() to cast the 'cb' parameter */ +int virConnectDomainEventRegisterAny(virConnectPtr conn, + virDomainPtr dom, /* Optional, to filter */ + int eventID, + virConnectDomainEventGenericCallback cb, + void *opaque, + virFreeCallback freecb); + +int virConnectDomainEventDeregisterAny(virConnectPtr conn, + int callbackID); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index f7625fd3b4..d8a44c76f5 100755 --- a/python/generator.py +++ b/python/generator.py @@ -169,6 +169,7 @@ skipped_modules = { skipped_types = { # 'int *': "usually a return type", 'virConnectDomainEventCallback': "No function types in python", + 'virConnectDomainEventGenericCallback': "No function types in python", 'virEventAddHandleFunc': "No function types in python", } @@ -330,6 +331,8 @@ skip_function = ( 'virNodeGetSecurityModel', # Needs investigation... 'virConnectDomainEventRegister', # overridden in virConnect.py 'virConnectDomainEventDeregister', # overridden in virConnect.py + 'virConnectDomainEventRegisterAny', # overridden in virConnect.py + 'virConnectDomainEventDeregisterAny', # overridden in virConnect.py 'virSaveLastError', # We have our own python error wrapper 'virFreeError', # Only needed if we use virSaveLastError 'virStreamEventAddCallback', diff --git a/src/driver.h b/src/driver.h index 362533fbb2..6c8089e38c 100644 --- a/src/driver.h +++ b/src/driver.h @@ -386,6 +386,18 @@ typedef int unsigned long long downtime, unsigned int flags); +typedef int + (*virDrvDomainEventRegisterAny)(virConnectPtr conn, + virDomainPtr dom, + int eventID, + virConnectDomainEventGenericCallback cb, + void *opaque, + virFreeCallback freecb); + +typedef int + (*virDrvDomainEventDeregisterAny)(virConnectPtr conn, + int callbackID); + /** * _virDriver: * @@ -480,6 +492,8 @@ struct _virDriver { virDrvDomainGetJobInfo domainGetJobInfo; virDrvDomainAbortJob domainAbortJob; virDrvDomainMigrateSetMaxDowntime domainMigrateSetMaxDowntime; + virDrvDomainEventRegisterAny domainEventRegisterAny; + virDrvDomainEventDeregisterAny domainEventDeregisterAny; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 30a1adb737..90cedd5ecc 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -3399,6 +3399,8 @@ static virDriver esxDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; diff --git a/src/libvirt.c b/src/libvirt.c index 7b74fd9336..50239ff2f4 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -9338,8 +9338,12 @@ error: * @opaque: opaque data to pass on to the callback * @freecb: optional function to deallocate opaque when not used anymore * - * Adds a Domain Event Callback. - * Registering for a domain callback will enable delivery of the events + * Adds a callback to receive notifications of domain lifecycle events + * occurring on a connection + * + * Use of this method is no longer recommended. Instead applications + * should try virConnectDomainEventRegisterAny which has a more flexible + * API contract * * The virDomainPtr object handle passed into the callback upon delivery * of an event is only valid for the duration of execution of the callback. @@ -9388,9 +9392,12 @@ error: * @conn: pointer to the connection * @cb: callback to the function handling domain events * - * Removes a Domain Event Callback. - * De-registering for a domain callback will disable - * delivery of this event type + * Removes a callback previously registered with the virConnectDomainEventRegister + * funtion. + * + * Use of this method is no longer recommended. Instead applications + * should try virConnectDomainEventUnregisterAny which has a more flexible + * API contract * * Returns 0 on success, -1 on failure */ @@ -11356,7 +11363,121 @@ virDomainMigrateSetMaxDowntime(virDomainPtr domain, } virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); - +error: + virDispatchError(conn); + return -1; +} + +/** + * virConnectDomainEventRegisterAny: + * @conn: pointer to the connection + * @dom: pointer to the domain + * @eventID: the event type to receive + * @cb: callback to the function handling domain events + * @opaque: opaque data to pass on to the callback + * @freecb: optional function to deallocate opaque when not used anymore + * + * Adds a callback to receive notifications of arbitrary domain events + * occurring on a domain. + * + * If dom is NULL, then events will be monitored for any domain. If dom + * is non-NULL, then only the specific domain will be monitored + * + * Most types of event have a callback providing a custom set of parameters + * for the event. When registering an event, it is thus neccessary to use + * the VIR_DOMAIN_EVENT_CALLBACK() macro to cast the supplied function pointer + * to match the signature of this method. + * + * The virDomainPtr object handle passed into the callback upon delivery + * of an event is only valid for the duration of execution of the callback. + * If the callback wishes to keep the domain object after the callback + * returns, it shall take a reference to it, by calling virDomainRef. + * The reference can be released once the object is no longer required + * by calling virDomainFree. + * + * The return value from this method is a positive integer identifier + * for the callback. To unregister a callback, this callback ID should + * be passed to the virDomainEventUnregisterAny method + * + * Returns a callback identifier on success, -1 on failure + */ +int +virConnectDomainEventRegisterAny(virConnectPtr conn, + virDomainPtr dom, + int eventID, + virConnectDomainEventGenericCallback cb, + void *opaque, + virFreeCallback freecb) +{ + DEBUG("conn=%p dom=%p, eventID=%d, cb=%p, opaque=%p, freecb=%p", conn, dom, eventID, cb, opaque, freecb); + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (dom != NULL && + !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(conn); + return (-1); + } + if (eventID < 0 || eventID >= VIR_DOMAIN_EVENT_ID_LAST || cb == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if ((conn->driver) && (conn->driver->domainEventRegisterAny)) { + int ret; + ret = conn->driver->domainEventRegisterAny(conn, dom, eventID, cb, opaque, freecb); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); +error: + virDispatchError(conn); + return -1; +} + +/** + * virConnectDomainEventDeregisterAny: + * @conn: pointer to the connection + * @callbackID: the callback identifier + * + * Removes an event callback. The callbackID parameter should be the + * vaule obtained from a previous virDomainEventRegisterAny method. + * + * Returns 0 on success, -1 on failure + */ +int +virConnectDomainEventDeregisterAny(virConnectPtr conn, + int callbackID) +{ + DEBUG("conn=%p, callbackID=%d", conn, callbackID); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (callbackID < 0) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + if ((conn->driver) && (conn->driver->domainEventDeregisterAny)) { + int ret; + ret = conn->driver->domainEventDeregisterAny(conn, callbackID); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); error: virDispatchError(conn); return -1; diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 623e53cb11..6cb03a5a04 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -362,6 +362,8 @@ LIBVIRT_0.7.8 { global: virStorageVolWipe; virDomainMigrateSetMaxDowntime; + virConnectDomainEventRegisterAny; + virConnectDomainEventDeregisterAny; } LIBVIRT_0.7.7; # .... define new API here using predicted next version number .... diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index ba13065288..ac53b4d499 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2460,6 +2460,8 @@ static virDriver lxcDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; static virStateDriver lxcStateDriver = { diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c index e1d1efc99a..2957ac99e3 100644 --- a/src/opennebula/one_driver.c +++ b/src/opennebula/one_driver.c @@ -789,6 +789,8 @@ static virDriver oneDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; static virStateDriver oneStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 50aadfc68c..d9b15ca5c5 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1541,6 +1541,8 @@ static virDriver openvzDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index e4d67dc175..6cea3d1428 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -1648,6 +1648,8 @@ virDriver phypDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; int diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 257f91466a..e8d8c2f1c0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9676,6 +9676,8 @@ static virDriver qemuDriver = { qemuDomainGetJobInfo, /* domainGetJobInfo */ qemuDomainAbortJob, /* domainAbortJob */ qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 1476f19181..286e400fa0 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -9189,6 +9189,8 @@ static virDriver remote_driver = { remoteDomainGetJobInfo, /* domainGetJobInfo */ remoteDomainAbortJob, /* domainFinishJob */ remoteDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index fb5c3f6bda..288ef69c70 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5245,6 +5245,8 @@ static virDriver testDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index bf067876b9..798df53e9e 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1933,6 +1933,8 @@ static virDriver umlDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 510abaecee..3d10868179 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -7073,6 +7073,8 @@ virDriver NAME(Driver) = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 204ed91128..71a0d6f0f6 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -1907,6 +1907,8 @@ static virDriver xenUnifiedDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; /** diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index ac004243b5..b4ee4cf840 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1748,6 +1748,8 @@ static virDriver xenapiDriver = { NULL, /* domainGetJobInfo */ NULL, /* domainAbortJob */ NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ }; /**