From: "Daniel P. Berrange" <berrange(a)redhat.com>
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