The generator was disabled for the new event callbacks, since they
need to be hand written. This patch adds the C and python glue to
expose the new APIs in the python binding. The python example
program is extended to demonstrate of the code
* python/libvirt-override.c: Registration and dispatch of events
at the C layer
* python/libvirt-override-virConnect.py: Python glue for events
* examples/domain-events/events-python/event-test.py: Demo use
of new event callbacks
---
examples/domain-events/events-python/event-test.py | 22 +-
python/libvirt-override-virConnect.py | 45 ++
python/libvirt-override.c | 451 ++++++++++++++++++++
3 files changed, 517 insertions(+), 1 deletions(-)
diff --git a/examples/domain-events/events-python/event-test.py
b/examples/domain-events/events-python/event-test.py
index 181b389..0c6e2f0 100644
--- a/examples/domain-events/events-python/event-test.py
+++ b/examples/domain-events/events-python/event-test.py
@@ -412,6 +412,21 @@ def myDomainEventCallback1 (conn, dom, event, detail, opaque):
def myDomainEventCallback2 (conn, dom, event, detail, opaque):
print "myDomainEventCallback2 EVENT: Domain %s(%s) %s %d" % (dom.name(),
dom.ID(), eventToString(event), detail)
+def myDomainEventRebootCallback(conn, dom, opaque):
+ print "myDomainEventRebootCallback: Domain %s(%s)" % (dom.name(),
dom.ID())
+
+def myDomainEventRTCChangeCallback(conn, dom, utcoffset, opaque):
+ print "myDomainEventRTCChangeCallback: Domain %s(%s) %d" % (dom.name(),
dom.ID(), utcoffset)
+
+def myDomainEventWatchdogCallback(conn, dom, action, opaque):
+ print "myDomainEventWatchdogCallback: Domain %s(%s) %d" % (dom.name(),
dom.ID(), action)
+
+def myDomainEventIOErrorCallback(conn, dom, srcpath, devalias, action, opaque):
+ print "myDomainEventIOErrorCallback: Domain %s(%s) %s %s %d" % (dom.name(),
dom.ID(), srcpath, devalias, action)
+
+def myDomainEventGraphicsCallback(conn, dom, phase, localAddr, remoteAddr, authScheme,
subject, opaque):
+ print "myDomainEventGraphicsCallback: Domain %s(%s) %d %s" % (dom.name(),
dom.ID(), phase, authScheme)
+
def usage():
print "usage: "+os.path.basename(sys.argv[0])+" [uri]"
print " uri will default to qemu:///system"
@@ -451,7 +466,12 @@ def main():
#Add 2 callbacks to prove this works with more than just one
vc.domainEventRegister(myDomainEventCallback1,None)
- vc.domainEventRegister(myDomainEventCallback2,None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
myDomainEventCallback2, None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_REBOOT,
myDomainEventRebootCallback, None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE,
myDomainEventRTCChangeCallback, None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR,
myDomainEventIOErrorCallback, None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG,
myDomainEventWatchdogCallback, None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS,
myDomainEventGraphicsCallback, None)
# The rest of your app would go here normally, but for sake
# of demo we'll just go to sleep. The other option is to
diff --git a/python/libvirt-override-virConnect.py
b/python/libvirt-override-virConnect.py
index 1fdf548..444a499 100644
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -41,3 +41,48 @@
return 0
except AttributeError:
pass
+
+ def dispatchDomainEventLifecycleCallback(self, dom, event, detail, cbData):
+ """Dispatches events to python user domain event callbacks
+ """
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), event, detail, opaque)
+ return 0
+
+ def dispatchDomainEventGenericCallback(self, dom, cbData):
+ """Dispatches events to python user domain event callbacks
+ """
+ try:
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), opaque)
+ return 0
+ except AttributeError:
+ pass
+
+ def domainEventDeregisterAny(self, callbackID):
+ """Removes a Domain Event Callback. De-registering for a
+ domain callback will disable delivery of this event type """
+ try:
+ ret = libvirtmod.virConnectDomainEventDeregisterAny(self._o, callbackID)
+ if ret == -1: raise libvirtError ('virConnectDomainEventDeregisterAny()
failed', conn=self)
+ del self.domainEventCallbackID[callbackID]
+ except AttributeError:
+ pass
+
+ def domainEventRegisterAny(self, dom, eventID, cb, opaque):
+ """Adds a Domain Event Callback. Registering for a domain
+ callback will enable delivery of the events """
+ if not hasattr(self, 'domainEventCallbackID'):
+ self.domainEventCallbackID = {}
+ cbData = { "cb": cb, "conn": self, "opaque": opaque
}
+ if dom is None:
+ ret = libvirtmod.virConnectDomainEventRegisterAny(self._o, None, eventID,
cbData)
+ else:
+ ret = libvirtmod.virConnectDomainEventRegisterAny(self._o, dom._o, eventID,
cbData)
+ if ret == -1:
+ raise libvirtError ('virConnectDomainEventRegisterAny() failed',
conn=self)
+ self.domainEventCallbackID[ret] = opaque
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index e27bce6..02bc313 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -2761,6 +2761,455 @@ libvirt_virEventInvokeTimeoutCallback(PyObject *self
ATTRIBUTE_UNUSED,
return VIR_PY_INT_SUCCESS;
}
+
+static void
+libvirt_virConnectDomainEventFreeFunc(void *opaque)
+{
+ PyObject *pyobj_conn = (PyObject*)opaque;
+ LIBVIRT_ENSURE_THREAD_STATE;
+ Py_DECREF(pyobj_conn);
+ LIBVIRT_RELEASE_THREAD_STATE;
+}
+
+static int
+libvirt_virConnectDomainEventLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int event,
+ int detail,
+ 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*)"dispatchDomainEventLifecycleCallback",
+ (char*)"OiiO",
+ pyobj_dom,
+ event, detail,
+ pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
+static int
+libvirt_virConnectDomainEventGenericCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ 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*)"dispatchDomainEventGenericCallback",
+ (char*)"OO",
+ pyobj_dom, pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
+static int
+libvirt_virConnectDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ long long utcoffset,
+ 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*)"dispatchDomainEventRTCChangeCallback",
+ (char*)"OLO",
+ pyobj_dom,
+ (PY_LONG_LONG)utcoffset,
+ pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
+static int
+libvirt_virConnectDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int action,
+ 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*)"dispatchDomainEventWatchdogCallback",
+ (char*)"OiO",
+ pyobj_dom,
+ action,
+ pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
+static int
+libvirt_virConnectDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *srcPath,
+ const char *devAlias,
+ int action,
+ 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*)"dispatchDomainEventIOErrorCallback",
+ (char*)"OssiO",
+ pyobj_dom,
+ srcPath, devAlias, action,
+ pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
+static int
+libvirt_virConnectDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int phase,
+ virDomainEventGraphicsAddressPtr local,
+ virDomainEventGraphicsAddressPtr remote,
+ const char *authScheme,
+ virDomainEventGraphicsSubjectPtr subject,
+ void *opaque)
+{
+ PyObject *pyobj_cbData = (PyObject*)opaque;
+ PyObject *pyobj_dom;
+ PyObject *pyobj_ret;
+ PyObject *pyobj_conn;
+ PyObject *dictKey;
+ PyObject *pyobj_local;
+ PyObject *pyobj_remote;
+ PyObject *pyobj_subject;
+ int ret = -1;
+ int i;
+
+ 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);
+
+ pyobj_local = PyDict_New();
+ PyDict_SetItem(pyobj_local,
+ libvirt_constcharPtrWrap("family"),
+ libvirt_intWrap(local->family));
+ PyDict_SetItem(pyobj_local,
+ libvirt_constcharPtrWrap("node"),
+ libvirt_constcharPtrWrap(local->node));
+ PyDict_SetItem(pyobj_local,
+ libvirt_constcharPtrWrap("service"),
+ libvirt_constcharPtrWrap(local->service));
+
+ pyobj_remote = PyDict_New();
+ PyDict_SetItem(pyobj_remote,
+ libvirt_constcharPtrWrap("family"),
+ libvirt_intWrap(remote->family));
+ PyDict_SetItem(pyobj_remote,
+ libvirt_constcharPtrWrap("node"),
+ libvirt_constcharPtrWrap(remote->node));
+ PyDict_SetItem(pyobj_remote,
+ libvirt_constcharPtrWrap("service"),
+ libvirt_constcharPtrWrap(remote->service));
+
+ pyobj_subject = PyList_New(subject->nidentity);
+ for (i = 0 ; i < subject->nidentity ; i++) {
+ PyObject *pair = PyTuple_New(2);
+ PyTuple_SetItem(pair, 0,
libvirt_constcharPtrWrap(subject->identities[i].type));
+ PyTuple_SetItem(pair, 1,
libvirt_constcharPtrWrap(subject->identities[i].name));
+
+ PyList_SetItem(pyobj_subject, i, pair);
+ }
+
+ /* Call the Callback Dispatcher */
+ pyobj_ret = PyObject_CallMethod(pyobj_conn,
+
(char*)"dispatchDomainEventGraphicsCallback",
+ (char*)"OiOOsOO",
+ pyobj_dom,
+ phase, pyobj_local, pyobj_remote,
+ authScheme, pyobj_subject,
+ pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ 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)
+{
+ PyObject *py_retval; /* return value */
+ PyObject *pyobj_conn; /* virConnectPtr */
+ PyObject *pyobj_dom;
+ PyObject *pyobj_cbData; /* hash of callback data */
+ int eventID;
+ virConnectPtr conn;
+ int ret = 0;
+ virConnectDomainEventGenericCallback cb = NULL;
+ virDomainPtr dom;
+
+ if (!PyArg_ParseTuple
+ (args, (char *) "OOiO:virConnectDomainEventRegisterAny",
+ &pyobj_conn, &pyobj_dom, &eventID, &pyobj_cbData)) {
+#if DEBUG_ERROR
+ printf("%s failed parsing tuple\n", __FUNCTION__);
+#endif
+ return VIR_PY_INT_FAIL;
+ }
+
+#ifdef DEBUG_ERROR
+ printf("libvirt_virConnectDomainEventRegister(%p %p %d %p) called\n",
+ pyobj_conn, pyobj_dom, eventID, pyobj_cbData);
+#endif
+ conn = PyvirConnect_Get(pyobj_conn);
+ if (pyobj_dom == Py_None)
+ dom = NULL;
+ else
+ dom = PyvirDomain_Get(pyobj_dom);
+
+ switch (eventID) {
+ case VIR_DOMAIN_EVENT_ID_LIFECYCLE:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventLifecycleCallback);
+ break;
+ case VIR_DOMAIN_EVENT_ID_REBOOT:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventGenericCallback);
+ break;
+ case VIR_DOMAIN_EVENT_ID_RTC_CHANGE:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventRTCChangeCallback);
+ break;
+ case VIR_DOMAIN_EVENT_ID_WATCHDOG:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventWatchdogCallback);
+ break;
+ case VIR_DOMAIN_EVENT_ID_IO_ERROR:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventIOErrorCallback);
+ break;
+ case VIR_DOMAIN_EVENT_ID_GRAPHICS:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventGraphicsCallback);
+ break;
+ }
+
+ if (!cb) {
+ return VIR_PY_INT_FAIL;
+ }
+
+ Py_INCREF(pyobj_cbData);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ ret = virConnectDomainEventRegisterAny(conn, dom, eventID,
+ cb, pyobj_cbData,
+ libvirt_virConnectDomainEventFreeFunc);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (ret < 0) {
+ Py_DECREF(pyobj_cbData);
+ }
+
+ py_retval = libvirt_intWrap(ret);
+ return (py_retval);
+}
+
+static PyObject *
+libvirt_virConnectDomainEventDeregisterAny(ATTRIBUTE_UNUSED PyObject * self,
+ PyObject * args)
+{
+ PyObject *py_retval;
+ PyObject *pyobj_conn;
+ int callbackID;
+ virConnectPtr conn;
+ int ret = 0;
+
+ if (!PyArg_ParseTuple
+ (args, (char *) "Oi:virConnectDomainEventDeregister",
+ &pyobj_conn, &callbackID))
+ return (NULL);
+
+#ifdef DEBUG_ERROR
+ printf("libvirt_virConnectDomainEventDeregister(%p) called\n",
pyobj_conn);
+#endif
+
+ conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+
+ ret = virConnectDomainEventDeregisterAny(conn, callbackID);
+
+ LIBVIRT_END_ALLOW_THREADS;
+ py_retval = libvirt_intWrap(ret);
+ return (py_retval);
+}
+
+
/************************************************************************
* *
* The registration stuff *
@@ -2776,6 +3225,8 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virConnectListDefinedDomains",
libvirt_virConnectListDefinedDomains, METH_VARARGS, NULL},
{(char *) "virConnectDomainEventRegister",
libvirt_virConnectDomainEventRegister, METH_VARARGS, NULL},
{(char *) "virConnectDomainEventDeregister",
libvirt_virConnectDomainEventDeregister, METH_VARARGS, NULL},
+ {(char *) "virConnectDomainEventRegisterAny",
libvirt_virConnectDomainEventRegisterAny, METH_VARARGS, NULL},
+ {(char *) "virConnectDomainEventDeregisterAny",
libvirt_virConnectDomainEventDeregisterAny, METH_VARARGS, NULL},
{(char *) "virDomainGetInfo", libvirt_virDomainGetInfo, METH_VARARGS,
NULL},
{(char *) "virNodeGetInfo", libvirt_virNodeGetInfo, METH_VARARGS, NULL},
{(char *) "virDomainGetUUID", libvirt_virDomainGetUUID, METH_VARARGS,
NULL},
--
1.6.6.1