[libvirt] [python PATCH 1/2] qemu: support arbitrary monitor events

Eric Blake eblake at redhat.com
Wed Feb 5 02:01:07 UTC 2014


Wrap the new virConnectDomainQemuMonitorEventRegister function
being added in libvirt 1.2.2.  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 at redhat.com>
---
 generator.py             |  20 +++--
 libvirt-qemu-override.c  | 221 ++++++++++++++++++++++++++++++++++++++++++++++-
 libvirt-qemu-override.py |  36 ++++++++
 3 files changed, 268 insertions(+), 9 deletions(-)
 create mode 100644 libvirt-qemu-override.py

diff --git a/generator.py b/generator.py
index 42f3913..e2325b0 100755
--- a/generator.py
+++ b/generator.py
@@ -570,6 +570,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
@@ -1803,16 +1805,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")
@@ -1826,6 +1820,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..0abcd3f 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 at 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, 2)
+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, 2) */
+
+
 /************************************************************************
  *									*
  *		Statistics						*
@@ -122,6 +192,151 @@ libvirt_qemu_virDomainQemuAgentCommand(PyObject *self ATTRIBUTE_UNUSED, PyObject
 }
 #endif /* LIBVIR_CHECK_VERSION(0, 10, 0) */

+
+#if LIBVIR_CHECK_VERSION(1, 2, 2)
+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;
+    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)
+        return;
+    pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
+    Py_DECREF(dictKey);
+
+    /* Create a python instance of this virDomainPtr */
+    virDomainRef(dom);
+    pyobj_dom = libvirt_virDomainPtrWrap(dom);
+    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);
+
+    if (!pyobj_ret) {
+        DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+        PyErr_Print();
+    } else {
+        Py_DECREF(pyobj_ret);
+    }
+
+cleanup:
+    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, 2) */
+
 /************************************************************************
  *									*
  *			The registration stuff				*
@@ -133,6 +348,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, 2)
+    {(char *) "virConnectDomainQemuMonitorEventRegister", libvirt_qemu_virConnectDomainQemuMonitorEventRegister, METH_VARARGS, NULL},
+    {(char *) "virConnectDomainQemuMonitorEventDeregister", libvirt_qemu_virConnectDomainQemuMonitorEventDeregister, METH_VARARGS, NULL},
+#endif /* LIBVIR_CHECK_VERSION(1, 2, 2) */
     {NULL, NULL, 0, NULL}
 };

diff --git a/libvirt-qemu-override.py b/libvirt-qemu-override.py
new file mode 100644
index 0000000..ab48bec
--- /dev/null
+++ b/libvirt-qemu-override.py
@@ -0,0 +1,36 @@
+# 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




More information about the libvir-list mailing list