]> xenbits.xensource.com Git - libvirt.git/commitdiff
Introduce a new public API for domain events
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 18 Mar 2010 13:01:48 +0000 (13:01 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 26 Mar 2010 13:52:03 +0000 (13:52 +0000)
The current API for domain events has a number of problems

 - Only allows for domain lifecycle change events
 - Does not allow the same callback to be registered multiple times
 - Does not allow filtering of events to a specific domain

This introduces a new more general purpose domain events API

  typedef enum {
     VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0,       /* virConnectDomainEventCallback */
      ...more events later..
  }

  int virConnectDomainEventRegisterAny(virConnectPtr conn,
                                       virDomainPtr dom, /* Optional, to filter */
                                       int eventID,
                                       virConnectDomainEventGenericCallback cb,
                                       void *opaque,
                                       virFreeCallback freecb);

  int virConnectDomainEventDeregisterAny(virConnectPtr conn,
                                         int callbackID);

Since different event types can received different data in the callback,
the API is defined with a generic callback. Specific events will each
have a custom signature for their callback. Thus when registering an
event it is neccessary to cast the callback to the generic signature

eg

  int myDomainEventCallback(virConnectPtr conn,
                            virDomainPtr dom,
                            int event,
                            int detail,
                            void *opaque)
  {
    ...
  }

  virConnectDomainEventRegisterAny(conn, NULL,
                                   VIR_DOMAIN_EVENT_ID_LIFECYCLE,
                                   VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback)
                                   NULL, NULL);

The VIR_DOMAIN_EVENT_CALLBACK() macro simply does a "bad" cast
to the generic signature

* include/libvirt/libvirt.h.in: Define new APIs for registering
  domain events
* src/driver.h: Internal driver entry points for new events APIs
* src/libvirt.c: Wire up public API to driver API for events APIs
* src/libvirt_public.syms: Export new APIs
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
  src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
  src/qemu/qemu_driver.c, src/remote/remote_driver.c,
  src/test/test_driver.c, src/uml/uml_driver.c,
  src/vbox/vbox_tmpl.c, src/xen/xen_driver.c,
  src/xenapi/xenapi_driver.c: Stub out new API entries

17 files changed:
include/libvirt/libvirt.h.in
python/generator.py
src/driver.h
src/esx/esx_driver.c
src/libvirt.c
src/libvirt_public.syms
src/lxc/lxc_driver.c
src/opennebula/one_driver.c
src/openvz/openvz_driver.c
src/phyp/phyp_driver.c
src/qemu/qemu_driver.c
src/remote/remote_driver.c
src/test/test_driver.c
src/uml/uml_driver.c
src/vbox/vbox_tmpl.c
src/xen/xen_driver.c
src/xenapi/xenapi_driver.c

index aaefa098bb1dc7d86805b0b2deaa06cba9581448..35c3891a2cb622d6dde28e8a10d3c9e0e80ab9c3 100644 (file)
@@ -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
index f7625fd3b459f34cdcf8ecd684388990dfbdb4cb..d8a44c76f51f4caa7baaabed17b2d6f49334cd87 100755 (executable)
@@ -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',
index 362533fbb28c83b257a83fb5fc743fd9f2d9d451..6c8089e38ccaea7ab6398e01ea841e837c9c858c 100644 (file)
@@ -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
index 30a1adb73739bf3526611cc0e122cd26bb75ba68..90cedd5ecc35cb1ee4fe61ea00b09de2eda4570b 100644 (file)
@@ -3399,6 +3399,8 @@ static virDriver esxDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 
index 7b74fd9336d62e758ecbd441a2f86b5a02909624..50239ff2f47df170f220f840428f5ee549a16abf 100644 (file)
@@ -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;
index 623e53cb112264a6f273f5ba29eb6d665c95673f..6cb03a5a04e7cc38aabc42a66b6184fe934205d4 100644 (file)
@@ -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 ....
index ba13065288e0f2d1592f7c21c39c1e1b7083b890..ac53b4d499ca234a96c2b538fa3595ffbaa27480 100644 (file)
@@ -2460,6 +2460,8 @@ static virDriver lxcDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 static virStateDriver lxcStateDriver = {
index e1d1efc99acf43ed6caab13843f67ceddece3fe1..2957ac99e3d59338b348fb0a941910ab6c28d5b7 100644 (file)
@@ -789,6 +789,8 @@ static virDriver oneDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 static virStateDriver oneStateDriver = {
index 50aadfc68cacf8ffa8e60ec4f408d448cd6728b1..d9b15ca5c5a8a5f22e8fc81fd84deaa92a4b895f 100644 (file)
@@ -1541,6 +1541,8 @@ static virDriver openvzDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 int openvzRegister(void) {
index e4d67dc1752de98518feb42f32c03c0a329151b3..6cea3d14282ebc42ddc50cb5fc133f5fdb667b56 100644 (file)
@@ -1648,6 +1648,8 @@ virDriver phypDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 int
index 257f91466aebf77b92ef7776d12f697640caf833..e8d8c2f1c03d0d5eefee60d30a7377e673abff0d 100644 (file)
@@ -9676,6 +9676,8 @@ static virDriver qemuDriver = {
     qemuDomainGetJobInfo, /* domainGetJobInfo */
     qemuDomainAbortJob, /* domainAbortJob */
     qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 
index 1476f191814591557a6e9ed7b5e158b03e5d0290..286e400fa0a24a16dac3b950413be7b9c59a2ed3 100644 (file)
@@ -9189,6 +9189,8 @@ static virDriver remote_driver = {
     remoteDomainGetJobInfo, /* domainGetJobInfo */
     remoteDomainAbortJob, /* domainFinishJob */
     remoteDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 static virNetworkDriver network_driver = {
index fb5c3f6bdaa79b29459f90407ea1a3ddcf7aa6b9..288ef69c704541c2bad302b6621cb7e9d907f5ed 100644 (file)
@@ -5245,6 +5245,8 @@ static virDriver testDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 static virNetworkDriver testNetworkDriver = {
index bf067876b951644a49b984e4836848da1fe09efd..798df53e9e98a0777c8bda848a902fe203fa0265 100644 (file)
@@ -1933,6 +1933,8 @@ static virDriver umlDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 
index 510abaecee2082d7ea4e62b913ab4b300419cac3..3d10868179816e07daf84016c0720d5cb8b8620f 100644 (file)
@@ -7073,6 +7073,8 @@ virDriver NAME(Driver) = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 virNetworkDriver NAME(NetworkDriver) = {
index 204ed9112823de9d3e73f49fa77c3d8d7f9f8f56..71a0d6f0f6126819bf6b30fc46235d3d4639e889 100644 (file)
@@ -1907,6 +1907,8 @@ static virDriver xenUnifiedDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 /**
index ac004243b5a8597a8dc904784542ab391eff8067..b4ee4cf84012c7ccfebe6412a1efb0d736cecbef 100644 (file)
@@ -1748,6 +1748,8 @@ static virDriver xenapiDriver = {
     NULL, /* domainGetJobInfo */
     NULL, /* domainAbortJob */
     NULL, /* domainMigrateSetMaxDowntime */
+    NULL, /* domainEventRegisterAny */
+    NULL, /* domainEventDeregisterAny */
 };
 
 /**