From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> Add code in the python binding to cope with the new APIs virConnectRegisterCloseCallback and virConnectDeregisterCloseCallback. Also demonstrate their use in the python domain events demo --- examples/domain-events/events-python/event-test.py | 14 ++- python/generator.py | 5 +- python/libvirt-override-virConnect.py | 24 +++++ python/libvirt-override.c | 107 ++++++++++++++++++++ 4 files changed, 147 insertions(+), 3 deletions(-) diff --git a/examples/domain-events/events-python/event-test.py b/examples/domain-events/events-python/event-test.py index 736c225..8193d18 100644 --- a/examples/domain-events/events-python/event-test.py +++ b/examples/domain-events/events-python/event-test.py @@ -490,6 +490,16 @@ def myDomainEventPMSuspendCallback(conn, dom, reason, opaque): dom.name(), dom.ID()) def myDomainEventBalloonChangeCallback(conn, dom, utcoffset, actual): print "myDomainEventBalloonChangeCallback: Domain %s(%s) %d" % (dom.name(), dom.ID(), actual) + +run = True + +def myConnectionCloseCallback(conn, reason, opaque): + reasonStrings = ( + "Error", "End-of-file", "Keepalive", "Client", + ) + print "myConnectionCloseCallback: %s: %s" % (conn.getURI(), reasonStrings[reason]) + run = False + def usage(out=sys.stderr): print >>out, "usage: "+os.path.basename(sys.argv[0])+" [-hdl] [uri]" print >>out, " uri will default to qemu:///system" @@ -539,6 +549,8 @@ def main(): if (old_exitfunc): old_exitfunc() sys.exitfunc = exit + vc.registerCloseCallback(myConnectionCloseCallback, None) + #Add 2 callbacks to prove this works with more than just one vc.domainEventRegister(myDomainEventCallback1,None) vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, myDomainEventCallback2, None) @@ -559,7 +571,7 @@ def main(): # of demo we'll just go to sleep. The other option is to # run the event loop in your main thread if your app is # totally event based. - while vc.isAlive() == 1: + while run: time.sleep(1) diff --git a/python/generator.py b/python/generator.py index 6559ece..6ccbf56 100755 --- a/python/generator.py +++ b/python/generator.py @@ -425,8 +425,6 @@ skip_impl = ( 'virDomainGetInterfaceParameters', 'virDomainGetCPUStats', 'virDomainGetDiskErrors', - 'virConnectUnregisterCloseCallback', - 'virConnectRegisterCloseCallback', ) qemu_skip_impl = ( @@ -464,6 +462,9 @@ skip_function = ( 'virStreamRecv', # overridden in libvirt-override-virStream.py 'virStreamSend', # overridden in libvirt-override-virStream.py + 'virConnectDeregisterCloseCallback', # overriden in virConnect.py + 'virConnectRegisterCloseCallback', # overriden in virConnect.py + # 'Ref' functions have no use for bindings users. "virConnectRef", "virDomainRef", diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index 50177ab..de8167e 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -206,3 +206,27 @@ retlist.append(virDomain(self, _obj=domptr)) return retlist + + def _dispatchCloseCallback(self, reason, cbData): + """Dispatches events to python user close callback""" + cb = cbData["cb"] + opaque = cbData["opaque"] + + cb(self, reason, opaque) + return 0 + + + def deregisterCloseCallback(self): + """Removes a close event callback""" + ret = libvirtmod.virConnectDeregisterCloseCallback(self._o) + if ret == -1: raise libvirtError ('virConnectDeregisterCloseCallback() failed', conn=self) + + def registerCloseCallback(self, cb, opaque): + """Adds a close event callback, providing a notification + when a connection fails / closes""" + cbData = { "cb": cb, "conn": self, "opaque": opaque } + ret = libvirtmod.virConnectRegisterCloseCallback(self._o, cbData) + if ret == -1: + raise libvirtError ('virConnectRegisterCloseCallback() failed', conn=self) + return ret + diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 8b41dff..b7269fc 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -5521,6 +5521,111 @@ libvirt_virConnectDomainEventDeregisterAny(ATTRIBUTE_UNUSED PyObject * self, return py_retval; } + +static void +libvirt_virConnectCloseCallbackDispatch(virConnectPtr conn ATTRIBUTE_UNUSED, + int reason, + void *opaque) +{ + PyObject *pyobj_cbData = (PyObject*)opaque; + PyObject *pyobj_ret; + PyObject *pyobj_conn; + PyObject *dictKey; + + LIBVIRT_ENSURE_THREAD_STATE; + + 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*)"_dispatchCloseCallback", + (char*)"iO", + reason, + pyobj_cbData); + + Py_DECREF(pyobj_cbData); + + if(!pyobj_ret) { + DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); + PyErr_Print(); + } else { + Py_DECREF(pyobj_ret); + } + + LIBVIRT_RELEASE_THREAD_STATE; +} + +static PyObject * +libvirt_virConnectRegisterCloseCallback(ATTRIBUTE_UNUSED PyObject * self, + PyObject * args) +{ + PyObject *py_retval; /* return value */ + PyObject *pyobj_conn; /* virConnectPtr */ + PyObject *pyobj_cbData; /* hash of callback data */ + virConnectPtr conn; + int ret = 0; + + if (!PyArg_ParseTuple + (args, (char *) "OO:virConnectRegisterCloseCallback", + &pyobj_conn, &pyobj_cbData)) { + DEBUG("%s failed parsing tuple\n", __FUNCTION__); + return VIR_PY_INT_FAIL; + } + + DEBUG("libvirt_virConnectRegisterCloseCallback(%p %p) called\n", + pyobj_conn, pyobj_cbData); + conn = PyvirConnect_Get(pyobj_conn); + + Py_INCREF(pyobj_cbData); + + LIBVIRT_BEGIN_ALLOW_THREADS; + ret = virConnectRegisterCloseCallback(conn, + libvirt_virConnectCloseCallbackDispatch, + 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_virConnectDeregisterCloseCallback(ATTRIBUTE_UNUSED PyObject * self, + PyObject * args) +{ + PyObject *py_retval; + PyObject *pyobj_conn; + virConnectPtr conn; + int ret = 0; + + if (!PyArg_ParseTuple + (args, (char *) "O:virConnectDomainEventDeregister", + &pyobj_conn)) + return NULL; + + DEBUG("libvirt_virConnectDomainEventDeregister(%p) called\n", + pyobj_conn); + + conn = PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + + ret = virConnectDeregisterCloseCallback(conn, + libvirt_virConnectCloseCallbackDispatch); + + LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_intWrap(ret); + return py_retval; +} + static void libvirt_virStreamEventFreeFunc(void *opaque) { @@ -5822,10 +5927,12 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virConnectListDomainsID", libvirt_virConnectListDomainsID, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedDomains", libvirt_virConnectListDefinedDomains, METH_VARARGS, NULL}, {(char *) "virConnectListAllDomains", libvirt_virConnectListAllDomains, METH_VARARGS, NULL}, + {(char *) "virConnectDeregisterCloseCallback", libvirt_virConnectDeregisterCloseCallback, 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 *) "virConnectRegisterCloseCallback", libvirt_virConnectRegisterCloseCallback, METH_VARARGS, NULL}, {(char *) "virStreamEventAddCallback", libvirt_virStreamEventAddCallback, METH_VARARGS, NULL}, {(char *) "virStreamRecv", libvirt_virStreamRecv, METH_VARARGS, NULL}, {(char *) "virStreamSend", libvirt_virStreamSend, METH_VARARGS, NULL}, -- 1.7.10.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list