From 24f9a46106ff5f55bf225867f259573241061719 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 26 Mar 2010 13:22:06 +0000 Subject: Fix up python bindings for new event callbacks 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 --- libvirt-override-virConnect.py | 45 ++++ libvirt-override.c | 451 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 496 insertions(+) diff --git a/libvirt-override-virConnect.py b/libvirt-override-virConnect.py index 1fdf548..444a499 100644 --- a/libvirt-override-virConnect.py +++ b/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/libvirt-override.c b/libvirt-override.c index e27bce6..02bc313 100644 --- a/libvirt-override.c +++ b/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}, -- cgit