[libvirt] [python PATCHv2 0/2] arbitrary qemu events

Changes since v1: rebase to latest code base, address review comments regarding a leak of dom, add prereq patch to fix bugs that I had been copying and pasting Eric Blake (2): event: fix domain reference bugs qemu: support arbitrary monitor events generator.py | 20 +-- libvirt-override.c | 319 +++++++++++++++++++++++++++++------------------ libvirt-qemu-override.c | 223 ++++++++++++++++++++++++++++++++- libvirt-qemu-override.py | 35 ++++++ 4 files changed, 469 insertions(+), 128 deletions(-) create mode 100644 libvirt-qemu-override.py -- 1.8.5.3

Noticed this bug while adding qemu monitor events; there's probably lots of other misuse of libvirt_virDomainPtrWrap, but for now I'm limiting the fix to all copied-and-pasted event callbacks, since I'm about to copy it again in the next patch. While at it, check for failure to extract the "conn" key from the opaque callback struct, and hoist that check to occur before we reach the point where it is harder to undo on failure (the network code was the only code that had it in the right place, but then it failed to restore thread state on failure). The graphics callback is still not clean; but incremental improvements are better than nothing. * libvirt-override.c (libvirt_virConnectDomainEventCallback) (libvirt_virConnectDomainEvetnLifecycleCallback) (libvirt_virConnectDomainEventGenericCallback) (libvirt_virConnectDomainEventRTCChangeCallback) (libvirt_virConnectDomainEventWatchdogCallback) (libvirt_virConnectDomainEventIOErrorCallback) (libvirt_virConnectDomainEventIOErrorReasonCallback) (libvirt_virConnectDomainEventGraphicsCallback) (libvirt_virConnectDomainEventBlockJobCallback) (libvirt_virConnectDomainEventDiskChangeCallback) (libvirt_virConnectDomainEventTrayChangeCallback) (libvirt_virConnectDomainEventPMWakeupCallback) (libvirt_virConnectDomainEventPMSuspendCallback) (libvirt_virConnectDomainEventBalloonChangeCallback) (libvirt_virConnectDomainEventPMSuspendDiskCallback) (libvirt_virConnectDomainEventDeviceRemovedCallback): Don't pass NULL to PyObject_CallMethod. (libvirt_virConnectNetworkEventLifecycleCallback): Likewise, and don't corrupt thread state. Signed-off-by: Eric Blake <eblake@redhat.com> --- libvirt-override.c | 319 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 200 insertions(+), 119 deletions(-) diff --git a/libvirt-override.c b/libvirt-override.c index 6a85d24..9dc6ad4 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -5020,7 +5020,7 @@ libvirt_virConnectDomainEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, int detail, void *opaque) { - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn = (PyObject*)opaque; PyObject *pyobj_dom; @@ -5031,7 +5031,10 @@ libvirt_virConnectDomainEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn, @@ -5042,6 +5045,7 @@ libvirt_virConnectDomainEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -5055,8 +5059,8 @@ libvirt_virConnectDomainEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, } static PyObject * -libvirt_virConnectDomainEventRegister(ATTRIBUTE_UNUSED PyObject * self, - PyObject * args) +libvirt_virConnectDomainEventRegister(ATTRIBUTE_UNUSED PyObject *self, + PyObject *args) { PyObject *py_retval; /* return value */ PyObject *pyobj_conn; /* virConnectPtr */ @@ -5074,7 +5078,7 @@ libvirt_virConnectDomainEventRegister(ATTRIBUTE_UNUSED PyObject * self, DEBUG("libvirt_virConnectDomainEventRegister(%p %p) called\n", pyobj_conn, pyobj_conn_inst); - conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); Py_INCREF(pyobj_conn_inst); @@ -5082,7 +5086,7 @@ libvirt_virConnectDomainEventRegister(ATTRIBUTE_UNUSED PyObject * self, ret = virConnectDomainEventRegister(conn, libvirt_virConnectDomainEventCallback, - (void *)pyobj_conn_inst, NULL); + pyobj_conn_inst, NULL); LIBVIRT_END_ALLOW_THREADS; @@ -5091,8 +5095,8 @@ libvirt_virConnectDomainEventRegister(ATTRIBUTE_UNUSED PyObject * self, } static PyObject * -libvirt_virConnectDomainEventDeregister(ATTRIBUTE_UNUSED PyObject * self, - PyObject * args) +libvirt_virConnectDomainEventDeregister(ATTRIBUTE_UNUSED PyObject *self, + PyObject *args) { PyObject *py_retval; PyObject *pyobj_conn; @@ -5108,7 +5112,7 @@ libvirt_virConnectDomainEventDeregister(ATTRIBUTE_UNUSED PyObject * self, DEBUG("libvirt_virConnectDomainEventDeregister(%p) called\n", pyobj_conn); - conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); LIBVIRT_BEGIN_ALLOW_THREADS; @@ -5659,22 +5663,26 @@ libvirt_virConnectDomainEventLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNUS { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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", @@ -5686,6 +5694,7 @@ libvirt_virConnectDomainEventLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNUS Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -5705,22 +5714,26 @@ libvirt_virConnectDomainEventGenericCallback(virConnectPtr conn ATTRIBUTE_UNUSED { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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", @@ -5730,6 +5743,7 @@ libvirt_virConnectDomainEventGenericCallback(virConnectPtr conn ATTRIBUTE_UNUSED Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -5750,22 +5764,26 @@ libvirt_virConnectDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUS { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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", @@ -5777,6 +5795,7 @@ libvirt_virConnectDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUS Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -5797,22 +5816,26 @@ libvirt_virConnectDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSE { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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", @@ -5824,6 +5847,7 @@ libvirt_virConnectDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSE Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -5846,22 +5870,26 @@ libvirt_virConnectDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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", @@ -5873,6 +5901,7 @@ libvirt_virConnectDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -5896,22 +5925,26 @@ libvirt_virConnectDomainEventIOErrorReasonCallback(virConnectPtr conn ATTRIBUTE_ { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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*)"_dispatchDomainEventIOErrorReasonCallback", @@ -5923,6 +5956,7 @@ libvirt_virConnectDomainEventIOErrorReasonCallback(virConnectPtr conn ATTRIBUTE_ Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -5947,7 +5981,7 @@ libvirt_virConnectDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSE { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; PyObject *pyobj_local; @@ -5958,15 +5992,20 @@ libvirt_virConnectDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSE LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } Py_INCREF(pyobj_cbData); - dictKey = libvirt_constcharPtrWrap("conn"); - pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); - Py_DECREF(dictKey); - + /* FIXME This code should check for errors... */ pyobj_local = PyDict_New(); PyDict_SetItem(pyobj_local, libvirt_constcharPtrWrap("family"), @@ -6010,6 +6049,7 @@ libvirt_virConnectDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSE Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6032,22 +6072,26 @@ libvirt_virConnectDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSE { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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*)"_dispatchDomainEventBlockPullCallback", @@ -6057,10 +6101,9 @@ libvirt_virConnectDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSE Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { -#if DEBUG_ERROR - printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret); -#endif + DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); } else { Py_DECREF(pyobj_ret); @@ -6082,22 +6125,26 @@ libvirt_virConnectDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNU { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; 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"); + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } + Py_INCREF(pyobj_cbData); + /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn, (char*)"_dispatchDomainEventDiskChangeCallback", @@ -6109,6 +6156,7 @@ libvirt_virConnectDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNU Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6130,22 +6178,26 @@ libvirt_virConnectDomainEventTrayChangeCallback(virConnectPtr conn ATTRIBUTE_UNU { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; 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"); + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } + Py_INCREF(pyobj_cbData); + /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn, (char*)"_dispatchDomainEventTrayChangeCallback", @@ -6156,6 +6208,7 @@ libvirt_virConnectDomainEventTrayChangeCallback(virConnectPtr conn ATTRIBUTE_UNU Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6176,22 +6229,26 @@ libvirt_virConnectDomainEventPMWakeupCallback(virConnectPtr conn ATTRIBUTE_UNUSE { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; 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"); + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } + Py_INCREF(pyobj_cbData); + /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn, (char*)"_dispatchDomainEventPMWakeupCallback", @@ -6203,6 +6260,7 @@ libvirt_virConnectDomainEventPMWakeupCallback(virConnectPtr conn ATTRIBUTE_UNUSE Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6223,22 +6281,26 @@ libvirt_virConnectDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUS { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; 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"); + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } + Py_INCREF(pyobj_cbData); + /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn, (char*)"_dispatchDomainEventPMSuspendCallback", @@ -6250,6 +6312,7 @@ libvirt_virConnectDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUS Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6272,22 +6335,26 @@ libvirt_virConnectDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_ { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ virDomainRef(dom); - pyobj_dom = libvirt_virDomainPtrWrap(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } 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*)"_dispatchDomainEventBalloonChangeCallback", @@ -6299,6 +6366,7 @@ libvirt_virConnectDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_ Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6321,22 +6389,26 @@ libvirt_virConnectDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_ { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; 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"); + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } + Py_INCREF(pyobj_cbData); + /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn, (char*)"_dispatchDomainEventPMSuspendDiskCallback", @@ -6348,6 +6420,7 @@ libvirt_virConnectDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_ Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6370,22 +6443,26 @@ libvirt_virConnectDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_ { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_dom; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; 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"); + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); Py_DECREF(dictKey); + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } + Py_INCREF(pyobj_cbData); + /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn, (char*)"_dispatchDomainEventDeviceRemovedCallback", @@ -6395,6 +6472,7 @@ libvirt_virConnectDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_ Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_dom); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6409,8 +6487,8 @@ libvirt_virConnectDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_ #endif /* LIBVIR_CHECK_VERSION(1, 1, 1) */ static PyObject * -libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self, - PyObject * args) +libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject *self, + PyObject *args) { PyObject *py_retval; /* return value */ PyObject *pyobj_conn; /* virConnectPtr */ @@ -6517,8 +6595,8 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self, } static PyObject * -libvirt_virConnectDomainEventDeregisterAny(ATTRIBUTE_UNUSED PyObject * self, - PyObject * args) +libvirt_virConnectDomainEventDeregisterAny(ATTRIBUTE_UNUSED PyObject *self, + PyObject *args) { PyObject *py_retval; PyObject *pyobj_conn; @@ -6533,7 +6611,7 @@ libvirt_virConnectDomainEventDeregisterAny(ATTRIBUTE_UNUSED PyObject * self, DEBUG("libvirt_virConnectDomainEventDeregister(%p) called\n", pyobj_conn); - conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); LIBVIRT_BEGIN_ALLOW_THREADS; @@ -6563,22 +6641,24 @@ libvirt_virConnectNetworkEventLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNU { PyObject *pyobj_cbData = (PyObject*)opaque; PyObject *pyobj_net; - PyObject *pyobj_ret; + PyObject *pyobj_ret = NULL; PyObject *pyobj_conn; PyObject *dictKey; int ret = -1; LIBVIRT_ENSURE_THREAD_STATE; - dictKey = libvirt_constcharPtrWrap("conn"); - if (!dictKey) - return ret; + if (!(dictKey = libvirt_constcharPtrWrap("conn"))) + goto cleanup; pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); Py_DECREF(dictKey); /* Create a python instance of this virNetworkPtr */ virNetworkRef(net); - pyobj_net = libvirt_virNetworkPtrWrap(net); + if (!(pyobj_net = libvirt_virNetworkPtrWrap(net))) { + virNetworkFree(net); + goto cleanup; + } Py_INCREF(pyobj_cbData); /* Call the Callback Dispatcher */ @@ -6593,6 +6673,7 @@ libvirt_virConnectNetworkEventLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNU Py_DECREF(pyobj_cbData); Py_DECREF(pyobj_net); + cleanup: if (!pyobj_ret) { DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); PyErr_Print(); @@ -6680,7 +6761,7 @@ static PyObject DEBUG("libvirt_virConnectNetworkEventDeregister(%p) called\n", pyobj_conn); - conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); LIBVIRT_BEGIN_ALLOW_THREADS; -- 1.8.5.3

Wrap the new virConnectDomainQemuMonitorEventRegister function added in libvirt 1.2.3. This patch copies heavily from network events (commit 6ea5be0) and from event loop callbacks in libvirt-override.c, since in the libvirt_qemu module, we must expose top-level functions rather than class members. * generator.py (qemu_skip_function): Don't generate event code. (qemuBuildWrappers): Delay manual portion until after imports. * libvirt-qemu-override.py (qemuMonitorEventRegister) (qemuMonitorEventDeregister): New file. * libvirt-qemu-override.c (libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc) (libvirt_qemu_virConnectDomainQemuMonitorEventCallback) (libvirt_qemu_virConnectDomainQemuMonitorEventRegister) (libvirt_qemu_virConnectDomainQemuMonitorEventDeregister) (libvirt_qemu_lookupPythonFunc, getLibvirtQemuDictObject) (getLibvirtQemuModuleObject): New functions. Signed-off-by: Eric Blake <eblake@redhat.com> --- generator.py | 20 +++-- libvirt-qemu-override.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++- libvirt-qemu-override.py | 35 ++++++++ 3 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 libvirt-qemu-override.py diff --git a/generator.py b/generator.py index 0e9600f..d5aee22 100755 --- a/generator.py +++ b/generator.py @@ -569,6 +569,8 @@ lxc_skip_function = ( ) qemu_skip_function = ( #"virDomainQemuAttach", + 'virConnectDomainQemuMonitorEventRegister', # overridden in -qemu.py + 'virConnectDomainQemuMonitorEventDeregister', # overridden in -qemu.py ) # Generate C code, but skip python impl @@ -1812,16 +1814,8 @@ def qemuBuildWrappers(module): fd.write("#\n") fd.write("# WARNING WARNING WARNING WARNING\n") fd.write("#\n") - if extra is not None: - fd.writelines(extra.readlines()) - fd.write("#\n") - fd.write("# WARNING WARNING WARNING WARNING\n") - fd.write("#\n") fd.write("# Automatically written part of python bindings for libvirt\n") fd.write("#\n") - fd.write("# WARNING WARNING WARNING WARNING\n") - if extra is not None: - extra.close() fd.write("try:\n") fd.write(" import libvirtmod_qemu\n") @@ -1835,6 +1829,16 @@ def qemuBuildWrappers(module): fd.write(" raise lib_e\n\n") fd.write("import libvirt\n\n") + fd.write("# WARNING WARNING WARNING WARNING\n") + fd.write("#\n") + if extra is not None: + fd.writelines(extra.readlines()) + fd.write("#\n") + if extra is not None: + extra.close() + + fd.write("# WARNING WARNING WARNING WARNING\n") + fd.write("#\n") fd.write("#\n# Functions from module %s\n#\n\n" % module) # # Generate functions directly, no classes diff --git a/libvirt-qemu-override.c b/libvirt-qemu-override.c index 480a7d3..05ead30 100644 --- a/libvirt-qemu-override.c +++ b/libvirt-qemu-override.c @@ -4,7 +4,7 @@ * entry points where an automatically generated stub is * unpractical * - * Copyright (C) 2011-2012 Red Hat, Inc. + * Copyright (C) 2011-2014 Red Hat, Inc. * * Daniel Veillard <veillard@redhat.com> */ @@ -54,6 +54,76 @@ extern void initcygvirtmod_qemu(void); #define VIR_PY_INT_FAIL (libvirt_intWrap(-1)) #define VIR_PY_INT_SUCCESS (libvirt_intWrap(0)) +/******************************************* + * Helper functions to avoid importing modules + * for every callback + *******************************************/ +#if LIBVIR_CHECK_VERSION(1, 2, 3) +static PyObject *libvirt_qemu_module; +static PyObject *libvirt_qemu_dict; + +static PyObject * +getLibvirtQemuModuleObject(void) +{ + if (libvirt_qemu_module) + return libvirt_qemu_module; + + // PyImport_ImportModule returns a new reference + /* Bogus (char *) cast for RHEL-5 python API brokenness */ + libvirt_qemu_module = PyImport_ImportModule((char *)"libvirt_qemu"); + if (!libvirt_qemu_module) { + DEBUG("%s Error importing libvirt_qemu module\n", __FUNCTION__); + PyErr_Print(); + return NULL; + } + + return libvirt_qemu_module; +} + +static PyObject * +getLibvirtQemuDictObject(void) +{ + if (libvirt_qemu_dict) + return libvirt_qemu_dict; + + // PyModule_GetDict returns a borrowed reference + libvirt_qemu_dict = PyModule_GetDict(getLibvirtQemuModuleObject()); + if (!libvirt_qemu_dict) { + DEBUG("%s Error importing libvirt_qemu dictionary\n", __FUNCTION__); + PyErr_Print(); + return NULL; + } + + Py_INCREF(libvirt_qemu_dict); + return libvirt_qemu_dict; +} + + +static PyObject * +libvirt_qemu_lookupPythonFunc(const char *funcname) +{ + PyObject *python_cb; + + /* Lookup the python callback */ + python_cb = PyDict_GetItemString(getLibvirtQemuDictObject(), funcname); + + if (!python_cb) { + DEBUG("%s: Error finding %s\n", __FUNCTION__, funcname); + PyErr_Print(); + PyErr_Clear(); + return NULL; + } + + if (!PyCallable_Check(python_cb)) { + DEBUG("%s: %s is not callable\n", __FUNCTION__, funcname); + return NULL; + } + + return python_cb; +} +#endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */ + + /************************************************************************ * * * Statistics * @@ -122,6 +192,153 @@ libvirt_qemu_virDomainQemuAgentCommand(PyObject *self ATTRIBUTE_UNUSED, PyObject } #endif /* LIBVIR_CHECK_VERSION(0, 10, 0) */ + +#if LIBVIR_CHECK_VERSION(1, 2, 3) +static void +libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc(void *opaque) +{ + PyObject *pyobj_conn = (PyObject*)opaque; + LIBVIRT_ENSURE_THREAD_STATE; + Py_DECREF(pyobj_conn); + LIBVIRT_RELEASE_THREAD_STATE; +} + +static void +libvirt_qemu_virConnectDomainQemuMonitorEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *event, + long long seconds, + unsigned int micros, + const char *details, + void *opaque) +{ + PyObject *pyobj_cbData = (PyObject*)opaque; + PyObject *pyobj_dom; + PyObject *pyobj_ret = NULL; + PyObject *pyobj_conn; + PyObject *dictKey; + PyObject *pyobj_cb; + + LIBVIRT_ENSURE_THREAD_STATE; + + pyobj_cb = libvirt_qemu_lookupPythonFunc("_dispatchQemuMonitorEventCallback"); + if (!pyobj_cb) + goto cleanup; + + dictKey = libvirt_constcharPtrWrap("conn"); + if (!dictKey) + goto cleanup; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) { + virDomainFree(dom); + goto cleanup; + } + Py_INCREF(pyobj_cbData); + + /* Call the Callback Dispatcher */ + pyobj_ret = PyObject_CallFunction(pyobj_cb, + (char *)"OOsLIsO", + pyobj_conn, pyobj_dom, event, seconds, + micros, details, pyobj_cbData); + + Py_DECREF(pyobj_cbData); + Py_DECREF(pyobj_dom); + +cleanup: + 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_qemu_virConnectDomainQemuMonitorEventRegister(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *py_retval; + PyObject *pyobj_conn; + PyObject *pyobj_dom; + PyObject *pyobj_cbData; + const char *event; + virConnectPtr conn; + int ret = 0; + virConnectDomainQemuMonitorEventCallback cb = NULL; + virDomainPtr dom; + unsigned int flags; + + if (!PyArg_ParseTuple + (args, (char *) "OOzOI", + &pyobj_conn, &pyobj_dom, &event, &pyobj_cbData, &flags)) { + DEBUG("%s failed parsing tuple\n", __FUNCTION__); + return VIR_PY_INT_FAIL; + } + + DEBUG("libvirt_qemu_virConnectDomainQemuMonitorEventRegister(%p %p %s %p %x) called\n", + pyobj_conn, pyobj_dom, NULLSTR(event), pyobj_cbData, flags); + conn = PyvirConnect_Get(pyobj_conn); + if (pyobj_dom == Py_None) + dom = NULL; + else + dom = PyvirDomain_Get(pyobj_dom); + + cb = libvirt_qemu_virConnectDomainQemuMonitorEventCallback; + + Py_INCREF(pyobj_cbData); + + LIBVIRT_BEGIN_ALLOW_THREADS; + ret = virConnectDomainQemuMonitorEventRegister(conn, dom, event, + cb, pyobj_cbData, + libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc, + flags); + LIBVIRT_END_ALLOW_THREADS; + + if (ret < 0) + Py_DECREF(pyobj_cbData); + + py_retval = libvirt_intWrap(ret); + return py_retval; +} + + +static PyObject * +libvirt_qemu_virConnectDomainQemuMonitorEventDeregister(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *py_retval; + PyObject *pyobj_conn; + int callbackID; + virConnectPtr conn; + int ret = 0; + + if (!PyArg_ParseTuple + (args, (char *) "Oi:virConnectDomainQemuMonitorEventDeregister", + &pyobj_conn, &callbackID)) + return NULL; + + DEBUG("libvirt_qemu_virConnectDomainQemuMonitorEventDeregister(%p) called\n", + pyobj_conn); + + conn = PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + + ret = virConnectDomainQemuMonitorEventDeregister(conn, callbackID); + + LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_intWrap(ret); + return py_retval; +} +#endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */ + /************************************************************************ * * * The registration stuff * @@ -133,6 +350,10 @@ static PyMethodDef libvirtQemuMethods[] = { #if LIBVIR_CHECK_VERSION(0, 10, 0) {(char *) "virDomainQemuAgentCommand", libvirt_qemu_virDomainQemuAgentCommand, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(0, 10, 0) */ +#if LIBVIR_CHECK_VERSION(1, 2, 3) + {(char *) "virConnectDomainQemuMonitorEventRegister", libvirt_qemu_virConnectDomainQemuMonitorEventRegister, METH_VARARGS, NULL}, + {(char *) "virConnectDomainQemuMonitorEventDeregister", libvirt_qemu_virConnectDomainQemuMonitorEventDeregister, METH_VARARGS, NULL}, +#endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */ {NULL, NULL, 0, NULL} }; diff --git a/libvirt-qemu-override.py b/libvirt-qemu-override.py new file mode 100644 index 0000000..265a252 --- /dev/null +++ b/libvirt-qemu-override.py @@ -0,0 +1,35 @@ +# Manually written part of python bindings for libvirt-qemu + +def _dispatchQemuMonitorEventCallback(conn, dom, event, seconds, micros, details, cbData): + """Dispatches events to python user qemu monitor event callbacks + """ + cb = cbData["cb"] + opaque = cbData["opaque"] + + cb(conn, libvirt.virDomain(conn, _obj=dom), event, seconds, micros, details, opaque) + return 0 + +def qemuMonitorEventDeregister(conn, callbackID): + """Removes a qemu monitor event callback. De-registering for a callback + will disable delivery of this event type""" + try: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventDeregister(conn._o, callbackID) + if ret == -1: raise libvirt.libvirtError ('virConnectDomainQemuMonitorEventDeregister() failed') + del conn.qemuMonitorEventCallbackID[callbackID] + except AttributeError: + pass + +def qemuMonitorEventRegister(conn, dom, event, cb, opaque, flags=0): + """Adds a qemu monitor event callback. Registering for a monitor + callback will enable delivery of the events""" + if not hasattr(conn, 'qemuMonitorEventCallbackID'): + conn.qemuMonitorEventCallbackID = {} + cbData = { "cb": cb, "conn": conn, "opaque": opaque } + if dom is None: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventRegister(conn._o, None, event, cbData, flags) + else: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventRegister(conn._o, dom._o, event, cbData, flags) + if ret == -1: + raise libvirt.libvirtError ('virConnectDomainQemuMonitorEventRegister() failed') + conn.qemuMonitorEventCallbackID[ret] = opaque + return ret -- 1.8.5.3

On 24.3.2014 20:14, Eric Blake wrote:
Changes since v1: rebase to latest code base, address review comments regarding a leak of dom, add prereq patch to fix bugs that I had been copying and pasting
Eric Blake (2): event: fix domain reference bugs qemu: support arbitrary monitor events
generator.py | 20 +-- libvirt-override.c | 319 +++++++++++++++++++++++++++++------------------ libvirt-qemu-override.c | 223 ++++++++++++++++++++++++++++++++- libvirt-qemu-override.py | 35 ++++++ 4 files changed, 469 insertions(+), 128 deletions(-) create mode 100644 libvirt-qemu-override.py
Tested and the code seems to by OK too. ACK Pavel

On 03/25/2014 04:37 AM, Pavel Hrdina wrote:
On 24.3.2014 20:14, Eric Blake wrote:
Changes since v1: rebase to latest code base, address review comments regarding a leak of dom, add prereq patch to fix bugs that I had been copying and pasting
Eric Blake (2): event: fix domain reference bugs qemu: support arbitrary monitor events
generator.py | 20 +-- libvirt-override.c | 319 +++++++++++++++++++++++++++++------------------ libvirt-qemu-override.c | 223 ++++++++++++++++++++++++++++++++- libvirt-qemu-override.py | 35 ++++++ 4 files changed, 469 insertions(+), 128 deletions(-) create mode 100644 libvirt-qemu-override.py
Tested and the code seems to by OK too. ACK
Thanks; pushed. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
Pavel Hrdina