[libvirt] [PATCH 0/7] Expose QEMU APIs to Python binding

This patchset is to expose QEMU APIs to Python binding, as we don't intend to support the QEMU APIs officially, it's exposed seperately with general libvirt APIs with standalone libvirt_qemu.py and libvirtmod_qemu.so. And there is no class for QEMU APIs, there are written directly as function in libvirt_qemu.py. How to use the APIs. #! /usr/bin/python -u import libvirt import libvirt_qemu conn = libvirt.open(None) dom = conn.lookupByName('test') print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1) libvirt_qemu.qemuAttach(conn, 2307, 0) PS: make check/make dist/make rpm are passed. [PATCH 1/7] qemu_api: Modify apibuild.py to generate docs for QEMU [PATCH 2/7] qemu_api: Update Makefile for subdir docs [PATCH 3/7] qemu_api: Add comments for API [PATCH 4/7] qemu_api: Add override XML and C files for QEMU APIs [PATCH 5/7] qemu_api: Update Py binding generator to generate files [PATCH 6/7] qemu_api: Update Makefile to generate libvirtmod_qemu [PATCH 7/7] qemu_api: Update libvirt spec file Regards, Osier

The generated docs are: libvirt-qemu-api.xml, libvirt-qemu-refs.xml --- docs/apibuild.py | 26 +++++++++++++++++++------- 1 files changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/apibuild.py b/docs/apibuild.py index 3563d94..c8b5994 100755 --- a/docs/apibuild.py +++ b/docs/apibuild.py @@ -27,6 +27,11 @@ included_files = { "event.c": "event loop for monitoring file handles", } +qemu_included_files = { + "libvirt-qemu.h": "header with QEMU specific API definitions", + "libvirt-qemu.c": "Implementations for the QEMU specific APIs", +} + ignored_words = { "ATTRIBUTE_UNUSED": (0, "macro keyword"), "ATTRIBUTE_SENTINEL": (0, "macro keyword"), @@ -1832,7 +1837,10 @@ class docBuilder: self.name = name self.path = path self.directories = directories - self.includes = includes + included_files.keys() + if name == "libvirt": + self.includes = includes + included_files.keys() + elif name == "libvirt-qemu": + self.includes = includes + qemu_included_files.keys() self.modules = {} self.headers = {} self.idx = index() @@ -2345,22 +2353,25 @@ class docBuilder: output.close() -def rebuild(): +def rebuild(name): + if name not in ["libvirt", "libvirt-qemu"]: + self.warning("rebuild() failed, unkown module %s") % name + return None builder = None srcdir = os.environ["srcdir"] if glob.glob(srcdir + "/../src/libvirt.c") != [] : if not quiet: - print "Rebuilding API description for libvirt" + print "Rebuilding API description for %s" % name dirs = [srcdir + "/../src", srcdir + "/../src/util", srcdir + "/../include/libvirt"] if glob.glob(srcdir + "/../include/libvirt/libvirt.h") == [] : dirs.append("../include/libvirt") - builder = docBuilder("libvirt", srcdir, dirs, []) + builder = docBuilder(name, srcdir, dirs, []) elif glob.glob("src/libvirt.c") != [] : if not quiet: - print "Rebuilding API description for libvirt" - builder = docBuilder("libvirt", srcdir, + print "Rebuilding API description for %s" % name + builder = docBuilder(name, srcdir, ["src", "src/util", "include/libvirt"], []) else: @@ -2384,7 +2395,8 @@ if __name__ == "__main__": debug = 1 parse(sys.argv[1]) else: - rebuild() + rebuild("libvirt") + rebuild("libvirt-qemu") if warnings > 0: sys.exit(2) else: -- 1.7.6

On Fri, Sep 09, 2011 at 07:24:41PM +0800, Osier Yang wrote:
The generated docs are: libvirt-qemu-api.xml, libvirt-qemu-refs.xml --- docs/apibuild.py | 26 +++++++++++++++++++------- 1 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/docs/apibuild.py b/docs/apibuild.py index 3563d94..c8b5994 100755 --- a/docs/apibuild.py +++ b/docs/apibuild.py @@ -27,6 +27,11 @@ included_files = { "event.c": "event loop for monitoring file handles", }
+qemu_included_files = { + "libvirt-qemu.h": "header with QEMU specific API definitions", + "libvirt-qemu.c": "Implementations for the QEMU specific APIs", +} + ignored_words = { "ATTRIBUTE_UNUSED": (0, "macro keyword"), "ATTRIBUTE_SENTINEL": (0, "macro keyword"), @@ -1832,7 +1837,10 @@ class docBuilder: self.name = name self.path = path self.directories = directories - self.includes = includes + included_files.keys() + if name == "libvirt": + self.includes = includes + included_files.keys() + elif name == "libvirt-qemu": + self.includes = includes + qemu_included_files.keys() self.modules = {} self.headers = {} self.idx = index() @@ -2345,22 +2353,25 @@ class docBuilder: output.close()
-def rebuild(): +def rebuild(name): + if name not in ["libvirt", "libvirt-qemu"]: + self.warning("rebuild() failed, unkown module %s") % name + return None builder = None srcdir = os.environ["srcdir"] if glob.glob(srcdir + "/../src/libvirt.c") != [] : if not quiet: - print "Rebuilding API description for libvirt" + print "Rebuilding API description for %s" % name dirs = [srcdir + "/../src", srcdir + "/../src/util", srcdir + "/../include/libvirt"] if glob.glob(srcdir + "/../include/libvirt/libvirt.h") == [] : dirs.append("../include/libvirt") - builder = docBuilder("libvirt", srcdir, dirs, []) + builder = docBuilder(name, srcdir, dirs, []) elif glob.glob("src/libvirt.c") != [] : if not quiet: - print "Rebuilding API description for libvirt" - builder = docBuilder("libvirt", srcdir, + print "Rebuilding API description for %s" % name + builder = docBuilder(name, srcdir, ["src", "src/util", "include/libvirt"], []) else: @@ -2384,7 +2395,8 @@ if __name__ == "__main__": debug = 1 parse(sys.argv[1]) else: - rebuild() + rebuild("libvirt") + rebuild("libvirt-qemu") if warnings > 0: sys.exit(2) else:
ACK, looks fine ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 09/09/2011 05:24 AM, Osier Yang wrote:
The generated docs are: libvirt-qemu-api.xml, libvirt-qemu-refs.xml --- docs/apibuild.py | 26 +++++++++++++++++++------- 1 files changed, 19 insertions(+), 7 deletions(-)
I'm pushing this under the trivial rule to ignore the newly-generated files from this series. diff --git i/.gitignore w/.gitignore index 1e8d5ab..06c3d0b 100644 --- i/.gitignore +++ w/.gitignore @@ -36,6 +36,7 @@ /configure.lineno /daemon/*_dispatch.h /docs/hvsupport.html.in +/docs/libvirt-qemu-*.xml /gnulib/lib/* /gnulib/m4/* /gnulib/tests/* @@ -53,6 +54,9 @@ /po/* /proxy/ /python/generator.py.stamp +/python/libvirt-qemu-export.c +/python/libvirt-qemu.[ch] +/python/libvirt_qemu.py /sc_* /src/hyperv/*.generated.* /src/libvirt_iohelper -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

--- docs/Makefile.am | 19 +++++++++++++++---- 1 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/Makefile.am b/docs/Makefile.am index 50a199f..70ec6f9 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -17,6 +17,7 @@ BUILT_SOURCES=hvsupport.html.in apihtml = \ html/index.html \ html/libvirt-libvirt.html \ + html/libvirt-libvirt-qemu.html \ html/libvirt-virterror.html apipng = \ @@ -30,6 +31,7 @@ devhelphtml = \ devhelp/index.html \ devhelp/general.html \ devhelp/libvirt-libvirt.html \ + devhelp/libvirt-libvirt-qemu.html \ devhelp/libvirt-virterror.html css = \ @@ -76,6 +78,10 @@ xml = \ libvirt-api.xml \ libvirt-refs.xml +qemu_xml = \ + libvirt-qemu-api.xml \ + libvirt-qemu-refs.xml + fig = \ libvirt-net-logical.fig \ libvirt-net-physical.fig \ @@ -89,7 +95,7 @@ EXTRA_DIST= \ hacking1.xsl hacking2.xsl wrapstring.xsl \ $(dot_html) $(dot_html_in) $(gif) $(apihtml) $(apipng) \ $(devhelphtml) $(devhelppng) $(devhelpcss) $(devhelpxsl) \ - $(xml) $(fig) $(png) $(css) \ + $(xml) $(qemu_xml) $(fig) $(png) $(css) \ $(patches) \ sitemap.html.in \ todo.pl hvsupport.pl todo.cfg-example @@ -102,6 +108,7 @@ MAINTAINERCLEANFILES = \ all: web api: $(srcdir)/libvirt-api.xml $(srcdir)/libvirt-refs.xml +qemu_api: $(srcdir)/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-refs.xml web: $(dot_html) html/index.html devhelp/index.html @@ -172,15 +179,18 @@ $(addprefix $(srcdir)/,$(devhelphtml)): $(srcdir)/libvirt-api.xml $(devhelpxsl) $(XSLTPROC) --nonet -o $(srcdir)/devhelp/ \ $(top_srcdir)/docs/devhelp/devhelp.xsl $(srcdir)/libvirt-api.xml ; fi + python_generated_files = \ $(srcdir)/html/libvirt-libvirt.html \ + $(srcdir)/html/libvirt-libvirt-qemu.html \ $(srcdir)/html/libvirt-virterror.html \ - $(srcdir)/libvirt-api.xml \ - $(srcdir)/libvirt-refs.xml + $(api) \ + $(qemu_api) $(python_generated_files): $(srcdir)/apibuild.py \ $(srcdir)/../include/libvirt/*.h \ $(srcdir)/../src/libvirt.c \ + $(srcdir)/../src/libvirt-qemu.c \ $(srcdir)/../src/util/virterror.c $(AM_V_GEN)srcdir=$(srcdir) $(PYTHON) $(srcdir)/apibuild.py @@ -191,8 +201,9 @@ clean-local: maintainer-clean-local: clean-local rm -rf $(srcdir)/libvirt-api.xml $(srcdir)/libvirt-refs.xml todo.html.in hvsupport.html.in + rm -rf $(srcdir)/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-refs.xml -rebuild: api all +rebuild: api qemu_api all install-data-local: $(mkinstalldirs) $(DESTDIR)$(HTML_DIR) -- 1.7.6

On Fri, Sep 09, 2011 at 07:24:42PM +0800, Osier Yang wrote:
--- docs/Makefile.am | 19 +++++++++++++++---- 1 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/docs/Makefile.am b/docs/Makefile.am index 50a199f..70ec6f9 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am [...]
api: $(srcdir)/libvirt-api.xml $(srcdir)/libvirt-refs.xml +qemu_api: $(srcdir)/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-refs.xml
web: $(dot_html) html/index.html devhelp/index.html
@@ -172,15 +179,18 @@ $(addprefix $(srcdir)/,$(devhelphtml)): $(srcdir)/libvirt-api.xml $(devhelpxsl) $(XSLTPROC) --nonet -o $(srcdir)/devhelp/ \ $(top_srcdir)/docs/devhelp/devhelp.xsl $(srcdir)/libvirt-api.xml ; fi
+ python_generated_files = \ $(srcdir)/html/libvirt-libvirt.html \ + $(srcdir)/html/libvirt-libvirt-qemu.html \ $(srcdir)/html/libvirt-virterror.html \ - $(srcdir)/libvirt-api.xml \ - $(srcdir)/libvirt-refs.xml + $(api) \ + $(qemu_api)
Unfortunately that does not work ! Without expanding the names of the fiels with the $(srcdir)/ prefix, built failed for me, so please merge in the following diff before commit otherwise fine, ACK, Daniel diff --git a/docs/Makefile.am b/docs/Makefile.am index 70ec6f9..0eb69b2 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -184,8 +184,10 @@ python_generated_files = \ $(srcdir)/html/libvirt-libvirt.html \ $(srcdir)/html/libvirt-libvirt-qemu.html \ $(srcdir)/html/libvirt-virterror.html \ - $(api) \ - $(qemu_api) + $(srcdir)/libvirt-api.xml \ + $(srcdir)/libvirt-refs.xml \ + $(srcdir)/libvirt-qemu-api.xml \ + $(srcdir)/libvirt-qemu-refs.xml $(python_generated_files): $(srcdir)/apibuild.py \ $(srcdir)/../include/libvirt/*.h \ -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

And fix argument @pid's type of virDomainQemuAttach. --- src/libvirt-qemu.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index 9481e01..b46868f 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -36,6 +36,43 @@ virReportErrorHelper(VIR_FROM_DOM, error, NULL, __FUNCTION__, \ __LINE__, info) +/** + * virDomainQemuMonitorCommand: + * @domain: a domain object + * @cmd: the qemu monitor command string + * @result: a string returned by @cmd + * @flags: bitwise-or of supported virDomainQemuMonitorCommandFlags + * + * This API is QEMU specific, so will only work with hypervisor + * connections to the QEMU driver. + * + * Send an arbitrary monitor command @cmd to @domain through the + * qemu monitor. There are several requirements to safely and + * succcesfully to use this API: + * + * - It must have been started with a monitor socket using the UNIX + * domain socket protocol. + * - No other operations which are changing the domain state or + * configuration at the same time, e.g. domain saving, it might + * cause libvirtd crashed. + * - If the @cmd is intend to change domain configuration, it must + * be no or other configuration changes can have been made via + * the monitor since it started. + * - The '-name' and '-uuid' arguments should have been set (not + * mandatory, but strongly recommended) + * + * If VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP is set, the command is + * considered to be a human monitor command and libvirt will automatically + * convert it into QMP if needed. In that case the @result will also + * be converted back from QMP. + * + * If successful, @result will be filled as a string with the output + * of the @cmd. And other APIs should operate normally (provided the + * above requirements were honoured + * + * Returns 0 in case of success, -1 in case of failure + * + */ int virDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd, char **result, unsigned int flags) @@ -81,8 +118,6 @@ error: return -1; } - - /** * virDomainQemuAttach: * @conn: pointer to a hypervisor connection @@ -111,7 +146,7 @@ error: */ virDomainPtr virDomainQemuAttach(virConnectPtr conn, - unsigned pid, + unsigned int pid, unsigned int flags) { VIR_DEBUG("conn=%p, pid=%u, flags=%x", conn, pid, flags); -- 1.7.6

On Fri, Sep 09, 2011 at 07:24:43PM +0800, Osier Yang wrote:
And fix argument @pid's type of virDomainQemuAttach. --- src/libvirt-qemu.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index 9481e01..b46868f 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -36,6 +36,43 @@ virReportErrorHelper(VIR_FROM_DOM, error, NULL, __FUNCTION__, \ __LINE__, info)
+/** + * virDomainQemuMonitorCommand: + * @domain: a domain object + * @cmd: the qemu monitor command string + * @result: a string returned by @cmd + * @flags: bitwise-or of supported virDomainQemuMonitorCommandFlags + * + * This API is QEMU specific, so will only work with hypervisor + * connections to the QEMU driver. + * + * Send an arbitrary monitor command @cmd to @domain through the + * qemu monitor. There are several requirements to safely and + * succcesfully to use this API: + * + * - It must have been started with a monitor socket using the UNIX + * domain socket protocol. + * - No other operations which are changing the domain state or + * configuration at the same time, e.g. domain saving, it might + * cause libvirtd crashed. + * - If the @cmd is intend to change domain configuration, it must + * be no or other configuration changes can have been made via + * the monitor since it started. + * - The '-name' and '-uuid' arguments should have been set (not + * mandatory, but strongly recommended) + * + * If VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP is set, the command is + * considered to be a human monitor command and libvirt will automatically + * convert it into QMP if needed. In that case the @result will also + * be converted back from QMP. + * + * If successful, @result will be filled as a string with the output + * of the @cmd. And other APIs should operate normally (provided the + * above requirements were honoured + * + * Returns 0 in case of success, -1 in case of failure + * + */ int virDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd, char **result, unsigned int flags) @@ -81,8 +118,6 @@ error: return -1; }
- - /** * virDomainQemuAttach: * @conn: pointer to a hypervisor connection @@ -111,7 +146,7 @@ error: */ virDomainPtr virDomainQemuAttach(virConnectPtr conn, - unsigned pid, + unsigned int pid, unsigned int flags) { VIR_DEBUG("conn=%p, pid=%u, flags=%x", conn, pid, flags); -- 1.7.6
ACK, that could be carried separately too, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 09/09/2011 05:24 AM, Osier Yang wrote:
+ * + * Send an arbitrary monitor command @cmd to @domain through the + * qemu monitor. There are several requirements to safely and + * succcesfully to use this API:
You've already pushed, but with a number of doc problems. s/succcesfully/successfully/ (copy-and-paste issue)
+ * + * - It must have been started with a monitor socket using the UNIX + * domain socket protocol. + * - No other operations which are changing the domain state or + * configuration at the same time, e.g. domain saving, it might + * cause libvirtd crashed.
s/libvirtd crashed/libvirtd to crash/
+ * - If the @cmd is intend to change domain configuration, it must
s/intend/intended/
+ * be no or other configuration changes can have been made via
s/it must be no or other/there must have been no other/ s/can have been made/made/
+ * the monitor since it started. + * - The '-name' and '-uuid' arguments should have been set (not + * mandatory, but strongly recommended)
Is this really appropriate comments for virDomainQemuMonitorCommand? It sounds like you are repeating the help for virDomainQemuAttach.
+ * + * If VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP is set, the command is + * considered to be a human monitor command and libvirt will automatically + * convert it into QMP if needed. In that case the @result will also + * be converted back from QMP. + * + * If successful, @result will be filled as a string with the output + * of the @cmd. And other APIs should operate normally (provided the + * above requirements were honoured
Prefer US spelling in public docs: s/honoured/honored/ -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

The new doc text had a few readability issues. Also, the monitor command text copied a bit too much from the attach case. * src/libvirt-qemu.c (virDomainQemuMonitorCommand) (virDomainQemuAttach): Fix typos and grammar. --- src/libvirt-qemu.c | 31 +++++++++++++------------------ 1 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index b46868f..248cc33 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -43,32 +43,27 @@ * @result: a string returned by @cmd * @flags: bitwise-or of supported virDomainQemuMonitorCommandFlags * - * This API is QEMU specific, so will only work with hypervisor + * This API is QEMU specific, so it will only work with hypervisor * connections to the QEMU driver. * * Send an arbitrary monitor command @cmd to @domain through the * qemu monitor. There are several requirements to safely and - * succcesfully to use this API: + * successfully use this API: * - * - It must have been started with a monitor socket using the UNIX - * domain socket protocol. - * - No other operations which are changing the domain state or - * configuration at the same time, e.g. domain saving, it might - * cause libvirtd crashed. - * - If the @cmd is intend to change domain configuration, it must - * be no or other configuration changes can have been made via - * the monitor since it started. - * - The '-name' and '-uuid' arguments should have been set (not - * mandatory, but strongly recommended) + * - A @cmd that queries state without making any modifications is safe + * - A @cmd that alters state that is also tracked by libvirt is unsafe, + * and may cause libvirtd to crash + * - A @cmd that alters state not tracked by the current version of + * libvirt is possible as a means to test new qemu features before + * they have support in libvirt, but no guarantees are made to safety * * If VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP is set, the command is * considered to be a human monitor command and libvirt will automatically * convert it into QMP if needed. In that case the @result will also * be converted back from QMP. * - * If successful, @result will be filled as a string with the output - * of the @cmd. And other APIs should operate normally (provided the - * above requirements were honoured + * If successful, @result will be filled with the string output of the + * @cmd, and the caller must free this string. * * Returns 0 in case of success, -1 in case of failure * @@ -124,11 +119,11 @@ error: * @pid: the UNIX process ID of the external QEMU process * @flags: optional flags, currently unused * - * This API is QEMU specific, so will only work with hypervisor + * This API is QEMU specific, so it will only work with hypervisor * connections to the QEMU driver. * * This API will attach to an externally launched QEMU process - * identified by @pid. There are several requirements to succcesfully + * identified by @pid. There are several requirements to successfully * attach to an external QEMU process: * * - It must have been started with a monitor socket using the UNIX @@ -140,7 +135,7 @@ error: * * If successful, then the guest will appear in the list of running * domains for this connection, and other APIs should operate - * normally (provided the above requirements were honoured + * normally (provided the above requirements were honored). * * Returns a new domain object on success, NULL otherwise */ -- 1.7.4.4

On Wed, Sep 14, 2011 at 09:50:15 -0600, Eric Blake wrote:
The new doc text had a few readability issues. Also, the monitor command text copied a bit too much from the attach case.
* src/libvirt-qemu.c (virDomainQemuMonitorCommand) (virDomainQemuAttach): Fix typos and grammar. --- src/libvirt-qemu.c | 31 +++++++++++++------------------ 1 files changed, 13 insertions(+), 18 deletions(-)
ACK The "succcesfully" typo was a bit hard to notice :) Jirka

On 09/15/2011 01:54 PM, Jiri Denemark wrote:
On Wed, Sep 14, 2011 at 09:50:15 -0600, Eric Blake wrote:
The new doc text had a few readability issues. Also, the monitor command text copied a bit too much from the attach case.
* src/libvirt-qemu.c (virDomainQemuMonitorCommand) (virDomainQemuAttach): Fix typos and grammar. --- src/libvirt-qemu.c | 31 +++++++++++++------------------ 1 files changed, 13 insertions(+), 18 deletions(-)
ACK
Thanks; pushed.
The "succcesfully" typo was a bit hard to notice :)
No kidding. The human brain is sometimes a little too good at filtering out noise :) -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

There is only one function (virDomainQemuMonitorCommand) need to be hand-craft. --- python/libvirt-qemu-override-api.xml | 12 +++ python/libvirt-qemu-override.c | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 0 deletions(-) create mode 100644 python/libvirt-qemu-override-api.xml create mode 100644 python/libvirt-qemu-override.c diff --git a/python/libvirt-qemu-override-api.xml b/python/libvirt-qemu-override-api.xml new file mode 100644 index 0000000..d69acea --- /dev/null +++ b/python/libvirt-qemu-override-api.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<api name='libvir-qemu-python'> + <symbols> + <function name='virDomainQemuMonitorCommand' file='python-qemu'> + <info>Send an arbitrary monitor command through qemu monitor of domain</info> + <return type='str *' info='the command output or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> + <arg name='cmd' type='const char *' info='the command which will be passed to QEMU monitor'/> + <arg name='flags' type='unsigned int' info='an OR'ed set of virDomainQemuMonitorCommandFlags'/> + </function> + </symbols> +</api> diff --git a/python/libvirt-qemu-override.c b/python/libvirt-qemu-override.c new file mode 100644 index 0000000..485c809 --- /dev/null +++ b/python/libvirt-qemu-override.c @@ -0,0 +1,136 @@ +/* + * libvir.c: this modules implements the main part of the glue of the + * libvir library and the Python interpreter. It provides the + * entry points where an automatically generated stub is + * unpractical + * + * Copyright (C) 2011 Red Hat, Inc. + * + * Daniel Veillard <veillard@redhat.com> + */ + +#include <config.h> + +/* Horrible kludge to work around even more horrible name-space pollution + via Python.h. That file includes /usr/include/python2.5/pyconfig*.h, + which has over 180 autoconf-style HAVE_* definitions. Shame on them. */ +#undef HAVE_PTHREAD_H + +#include <Python.h> +#include "libvirt/libvirt-qemu.h" +#include "libvirt/virterror.h" +#include "typewrappers.h" +#include "libvirt-qemu.h" + +#ifndef __CYGWIN__ +extern void initlibvirtmod_qemu(void); +#else +extern void initcygvirtmod_qemu(void); +#endif + +#if 0 +# define DEBUG_ERROR 1 +#endif + +#if DEBUG_ERROR +# define DEBUG(fmt, ...) \ + printf(fmt, __VA_ARGS__) +#else +# define DEBUG(fmt, ...) \ + do {} while (0) +#endif + +/* The two-statement sequence "Py_INCREF(Py_None); return Py_None;" + is so common that we encapsulate it here. Now, each use is simply + return VIR_PY_NONE; */ +#define VIR_PY_NONE (Py_INCREF (Py_None), Py_None) +#define VIR_PY_INT_FAIL (libvirt_intWrap(-1)) +#define VIR_PY_INT_SUCCESS (libvirt_intWrap(0)) + +/* We don't want to free() returned value. As written in doc: + * PyString_AsString returns pointer to 'internal buffer of string, + * not a copy' and 'It must not be deallocated'. */ +static char *py_str(PyObject *obj) +{ + PyObject *str = PyObject_Str(obj); + if (!str) { + PyErr_Print(); + PyErr_Clear(); + return NULL; + }; + return PyString_AsString(str); +} + +/************************************************************************ + * * + * Statistics * + * * + ************************************************************************/ + +static PyObject * +libvirt_qemu_virDomainQemuMonitorCommand(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + char *result = NULL; + virDomainPtr domain; + PyObject *pyobj_domain; + unsigned int flags; + char *cmd; + int c_retval; + + if (!PyArg_ParseTuple(args, (char *)"Ozi:virDomainQemuMonitorCommand", + &pyobj_domain, &cmd, &flags)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + + if (domain == NULL) + return VIR_PY_NONE; + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainQemuMonitorCommand(domain, cmd, &result, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (c_retval < 0) + return VIR_PY_NONE; + + py_retval = PyString_FromString(result); + return(py_retval); +} + +/************************************************************************ + * * + * The registration stuff * + * * + ************************************************************************/ +static PyMethodDef libvirtQemuMethods[] = { +#include "libvirt-qemu-export.c" + {(char *) "virDomainQemuMonitorCommand", libvirt_qemu_virDomainQemuMonitorCommand, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +void +#ifndef __CYGWIN__ +initlibvirtmod_qemu +#else +initcygvirtmod_qemu +#endif + (void) +{ + static int initialized = 0; + + if (initialized != 0) + return; + + if (virInitialize() < 0) + return; + + /* initialize the python extension module */ + Py_InitModule((char *) +#ifndef __CYGWIN__ + "libvirtmod_qemu" +#else + "cygvirtmod_qemu" +#endif + , libvirtQemuMethods); + + initialized = 1; +} -- 1.7.6

On Fri, Sep 09, 2011 at 07:24:44PM +0800, Osier Yang wrote:
There is only one function (virDomainQemuMonitorCommand) need to be hand-craft. --- python/libvirt-qemu-override-api.xml | 12 +++ python/libvirt-qemu-override.c | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 0 deletions(-) create mode 100644 python/libvirt-qemu-override-api.xml create mode 100644 python/libvirt-qemu-override.c
diff --git a/python/libvirt-qemu-override-api.xml b/python/libvirt-qemu-override-api.xml new file mode 100644 index 0000000..d69acea --- /dev/null +++ b/python/libvirt-qemu-override-api.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<api name='libvir-qemu-python'> + <symbols> + <function name='virDomainQemuMonitorCommand' file='python-qemu'> + <info>Send an arbitrary monitor command through qemu monitor of domain</info> + <return type='str *' info='the command output or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> + <arg name='cmd' type='const char *' info='the command which will be passed to QEMU monitor'/> + <arg name='flags' type='unsigned int' info='an OR'ed set of virDomainQemuMonitorCommandFlags'/> + </function> + </symbols> +</api> diff --git a/python/libvirt-qemu-override.c b/python/libvirt-qemu-override.c new file mode 100644 index 0000000..485c809 --- /dev/null +++ b/python/libvirt-qemu-override.c @@ -0,0 +1,136 @@ +/* + * libvir.c: this modules implements the main part of the glue of the + * libvir library and the Python interpreter. It provides the + * entry points where an automatically generated stub is + * unpractical + * + * Copyright (C) 2011 Red Hat, Inc. + * + * Daniel Veillard <veillard@redhat.com> + */ + +#include <config.h> + +/* Horrible kludge to work around even more horrible name-space pollution + via Python.h. That file includes /usr/include/python2.5/pyconfig*.h, + which has over 180 autoconf-style HAVE_* definitions. Shame on them. */ +#undef HAVE_PTHREAD_H + +#include <Python.h> +#include "libvirt/libvirt-qemu.h" +#include "libvirt/virterror.h" +#include "typewrappers.h" +#include "libvirt-qemu.h" + +#ifndef __CYGWIN__ +extern void initlibvirtmod_qemu(void); +#else +extern void initcygvirtmod_qemu(void); +#endif + +#if 0 +# define DEBUG_ERROR 1 +#endif + +#if DEBUG_ERROR +# define DEBUG(fmt, ...) \ + printf(fmt, __VA_ARGS__) +#else +# define DEBUG(fmt, ...) \ + do {} while (0) +#endif + +/* The two-statement sequence "Py_INCREF(Py_None); return Py_None;" + is so common that we encapsulate it here. Now, each use is simply + return VIR_PY_NONE; */ +#define VIR_PY_NONE (Py_INCREF (Py_None), Py_None) +#define VIR_PY_INT_FAIL (libvirt_intWrap(-1)) +#define VIR_PY_INT_SUCCESS (libvirt_intWrap(0)) + +/* We don't want to free() returned value. As written in doc: + * PyString_AsString returns pointer to 'internal buffer of string, + * not a copy' and 'It must not be deallocated'. */ +static char *py_str(PyObject *obj) +{ + PyObject *str = PyObject_Str(obj); + if (!str) { + PyErr_Print(); + PyErr_Clear(); + return NULL; + }; + return PyString_AsString(str); +} + +/************************************************************************ + * * + * Statistics * + * * + ************************************************************************/ + +static PyObject * +libvirt_qemu_virDomainQemuMonitorCommand(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + char *result = NULL; + virDomainPtr domain; + PyObject *pyobj_domain; + unsigned int flags; + char *cmd; + int c_retval; + + if (!PyArg_ParseTuple(args, (char *)"Ozi:virDomainQemuMonitorCommand", + &pyobj_domain, &cmd, &flags)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + + if (domain == NULL) + return VIR_PY_NONE; + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainQemuMonitorCommand(domain, cmd, &result, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (c_retval < 0) + return VIR_PY_NONE; + + py_retval = PyString_FromString(result); + return(py_retval); +} + +/************************************************************************ + * * + * The registration stuff * + * * + ************************************************************************/ +static PyMethodDef libvirtQemuMethods[] = { +#include "libvirt-qemu-export.c" + {(char *) "virDomainQemuMonitorCommand", libvirt_qemu_virDomainQemuMonitorCommand, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +void +#ifndef __CYGWIN__ +initlibvirtmod_qemu +#else +initcygvirtmod_qemu +#endif + (void) +{ + static int initialized = 0; + + if (initialized != 0) + return; + + if (virInitialize() < 0) + return; + + /* initialize the python extension module */ + Py_InitModule((char *) +#ifndef __CYGWIN__ + "libvirtmod_qemu" +#else + "cygvirtmod_qemu" +#endif + , libvirtQemuMethods); + + initialized = 1; +}
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

It will generate: libvirt-qemu.py libvirt-qemu.h libvirt-qemu.c libvirt-qemu-export.c --- python/generator.py | 363 +++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 294 insertions(+), 69 deletions(-) diff --git a/python/generator.py b/python/generator.py index d17fb26..327e1d5 100755 --- a/python/generator.py +++ b/python/generator.py @@ -4,7 +4,9 @@ # functions = {} +qemu_functions = {} enums = {} # { enumType: { enumConstant: enumValue } } +qemu_enums = {} # { enumType: { enumConstant: enumValue } } import os import sys @@ -82,10 +84,13 @@ class docParser(xml.sax.handler.ContentHandler): self.function_descr = None self.function_return = None self.function_file = None + self.function_module= None if attrs.has_key('name'): self.function = attrs['name'] if attrs.has_key('file'): self.function_file = attrs['file'] + if attrs.has_key('module'): + self.function_module= attrs['module'] elif tag == 'cond': self._data = [] elif tag == 'info': @@ -115,16 +120,36 @@ class docParser(xml.sax.handler.ContentHandler): if attrs.has_key('field'): self.function_return_field = attrs['field'] elif tag == 'enum': - enum(attrs['type'],attrs['name'],attrs['value']) + if attrs['file'] == "libvirt": + enum(attrs['type'],attrs['name'],attrs['value']) + elif attrs['file'] == "libvirt-qemu": + qemu_enum(attrs['type'],attrs['name'],attrs['value']) def end(self, tag): if debug: print "end %s" % tag if tag == 'function': if self.function != None: - function(self.function, self.function_descr, - self.function_return, self.function_args, - self.function_file, self.function_cond) + if self.function_module == "libvirt": + function(self.function, self.function_descr, + self.function_return, self.function_args, + self.function_file, self.function_module, + self.function_cond) + elif self.function_module == "libvirt-qemu": + qemu_function(self.function, self.function_descr, + self.function_return, self.function_args, + self.function_file, self.function_module, + self.function_cond) + elif self.function_file == "python": + function(self.function, self.function_descr, + self.function_return, self.function_args, + self.function_file, self.function_module, + self.function_cond) + elif self.function_file == "python-qemu": + qemu_function(self.function, self.function_descr, + self.function_return, self.function_args, + self.function_file, self.function_module, + self.function_cond) self.in_function = 0 elif tag == 'arg': if self.in_function == 1: @@ -150,8 +175,11 @@ class docParser(xml.sax.handler.ContentHandler): self.function_cond = str -def function(name, desc, ret, args, file, cond): - functions[name] = (desc, ret, args, file, cond) +def function(name, desc, ret, args, file, module, cond): + functions[name] = (desc, ret, args, file, module, cond) + +def qemu_function(name, desc, ret, args, file, module, cond): + qemu_functions[name] = (desc, ret, args, file, module, cond) def enum(type, name, value): if not enums.has_key(type): @@ -176,6 +204,12 @@ def enum(type, name, value): value = 2 enums[type][name] = value +def qemu_enum(type, name, value): + if not qemu_enums.has_key(type): + qemu_enums[type] = {} + qemu_enums[type][name] = value + + ####################################################################### # # Some filtering rukes to drop functions/types which should not @@ -184,9 +218,11 @@ def enum(type, name, value): ####################################################################### functions_failed = [] +qemu_functions_failed = [] functions_skipped = [ "virConnectListDomains", ] +qemu_functions_skipped = [] skipped_modules = { } @@ -376,6 +412,10 @@ skip_impl = ( 'virDomainBlockStatsFlags', ) +qemu_skip_impl = ( + 'virDomainQemuMonitorCommand', +) + # These are functions which the generator skips completly - no python # or C code is generated. Generally should not be used for any more @@ -428,37 +468,54 @@ skip_function = ( "virStorageVolGetConnect", ) +qemu_skip_function = ( + #"virDomainQemuAttach", +) + # Generate C code, but skip python impl function_skip_python_impl = ( "virStreamFree", # Needed in custom virStream __del__, but free shouldn't # be exposed in bindings ) +qemu_function_skip_python_impl = () + function_skip_index_one = ( "virDomainRevertToSnapshot", ) - -def print_function_wrapper(name, output, export, include): +def print_function_wrapper(module, name, output, export, include): global py_types global unknown_types global functions + global qemu_functions global skipped_modules global function_skip_python_impl try: - (desc, ret, args, file, cond) = functions[name] + if module == "libvirt": + (desc, ret, args, file, mod, cond) = functions[name] + if module == "libvirt-qemu": + (desc, ret, args, file, mod, cond) = qemu_functions[name] except: - print "failed to get function %s infos" + print "failed to get function %s infos" % name return - if skipped_modules.has_key(file): - return 0 - if name in skip_function: + if skipped_modules.has_key(module): return 0 - if name in skip_impl: - # Don't delete the function entry in the caller. - return 1 + + if module == "libvirt": + if name in skip_function: + return 0 + if name in skip_impl: + # Don't delete the function entry in the caller. + return 1 + elif module == "libvirt-qemu": + if name in qemu_skip_function: + return 0 + if name in qemu_skip_impl: + # Don't delete the function entry in the caller. + return 1 c_call = ""; format="" @@ -549,10 +606,14 @@ def print_function_wrapper(name, output, export, include): output.write("#if %s\n" % cond) include.write("PyObject * ") - include.write("libvirt_%s(PyObject *self, PyObject *args);\n" % (name)); - - export.write(" { (char *)\"%s\", libvirt_%s, METH_VARARGS, NULL },\n" % - (name, name)) + if module == "libvirt": + include.write("libvirt_%s(PyObject *self, PyObject *args);\n" % (name)); + export.write(" { (char *)\"%s\", libvirt_%s, METH_VARARGS, NULL },\n" % + (name, name)) + elif module == "libvirt-qemu": + include.write("libvirt_qemu_%s(PyObject *self, PyObject *args);\n" % (name)); + export.write(" { (char *)\"%s\", libvirt_qemu_%s, METH_VARARGS, NULL },\n" % + (name, name)) if file == "python": # Those have been manually generated @@ -570,7 +631,10 @@ def print_function_wrapper(name, output, export, include): return 1 output.write("PyObject *\n") - output.write("libvirt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) + if module == "libvirt": + output.write("libvirt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) + elif module == "libvirt-qemu": + output.write("libvirt_qemu_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) output.write(" PyObject *args") if format == "": output.write(" ATTRIBUTE_UNUSED") @@ -586,11 +650,11 @@ def print_function_wrapper(name, output, export, include): (format, format_args)) output.write(" return(NULL);\n") if c_convert != "": - output.write(c_convert) + output.write(c_convert + "\n") - output.write("LIBVIRT_BEGIN_ALLOW_THREADS;\n"); + output.write(" LIBVIRT_BEGIN_ALLOW_THREADS;"); output.write(c_call); - output.write("LIBVIRT_END_ALLOW_THREADS;\n"); + output.write(" LIBVIRT_END_ALLOW_THREADS;\n"); output.write(ret_convert) output.write("}\n\n") if cond != None and cond != "": @@ -598,24 +662,43 @@ def print_function_wrapper(name, output, export, include): export.write("#endif /* %s */\n" % cond) output.write("#endif /* %s */\n" % cond) - if name in function_skip_python_impl: - return 0 + if module == "libvirt": + if name in function_skip_python_impl: + return 0 + elif module == "libvirt-qemu": + if name in qemu_function_skip_python_impl: + return 0 return 1 -def buildStubs(): +def buildStubs(module): global py_types global py_return_types global unknown_types + if module not in ["libvirt", "libvirt-qemu"]: + print "ERROR: Unknown module type: %s" % module + return None + + if module == "libvirt": + funcs = functions + funcs_failed = functions_failed + funcs_skipped = functions_skipped + elif module == "libvirt-qemu": + funcs = qemu_functions + funcs_failed = qemu_functions_failed + funcs_skipped = functions_skipped + + api_xml = "%s-api.xml" % module + try: - f = open(os.path.join(srcPref,"libvirt-api.xml")) + f = open(os.path.join(srcPref,api_xml)) data = f.read() (parser, target) = getparser() parser.feed(data) parser.close() except IOError, msg: try: - f = open(os.path.join(srcPref,"..","docs","libvirt-api.xml")) + f = open(os.path.join(srcPref,"..","docs",api_xml)) data = f.read() (parser, target) = getparser() parser.feed(data) @@ -624,13 +707,15 @@ def buildStubs(): print file, ":", msg sys.exit(1) - n = len(functions.keys()) + n = len(funcs.keys()) if not quiet: - print "Found %d functions in libvirt-api.xml" % (n) + print "Found %d functions in %s" % ((n), api_xml) + override_api_xml = "%s-override-api.xml" % module py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject") + try: - f = open(os.path.join(srcPref,"libvirt-override-api.xml")) + f = open(os.path.join(srcPref, override_api_xml)) data = f.read() (parser, target) = getparser() parser.feed(data) @@ -639,32 +724,41 @@ def buildStubs(): print file, ":", msg if not quiet: - print "Found %d functions in libvirt-override-api.xml" % ( - len(functions.keys()) - n) + # XXX: This is not right, same function already in @functions + # will be overwritten. + print "Found %d functions in %s" % ((len(funcs.keys()) - n), override_api_xml) nb_wrap = 0 failed = 0 skipped = 0 - include = open("libvirt.h", "w") + header_file = "%s.h" % module + export_file = "%s-export.c" % module + wrapper_file = "%s.c" % module + + include = open(header_file, "w") include.write("/* Generated */\n\n") - export = open("libvirt-export.c", "w") + + export = open(export_file, "w") export.write("/* Generated */\n\n") - wrapper = open("libvirt.c", "w") + + wrapper = open(wrapper_file, "w") wrapper.write("/* Generated */\n\n") wrapper.write("#include <Python.h>\n") - wrapper.write("#include <libvirt/libvirt.h>\n") + wrapper.write("#include <libvirt/" + module + ".h>\n") wrapper.write("#include \"typewrappers.h\"\n") - wrapper.write("#include \"libvirt.h\"\n\n") - for function in functions.keys(): - ret = print_function_wrapper(function, wrapper, export, include) + wrapper.write("#include \"" + module + ".h\"\n\n") + + for function in funcs.keys(): + # Skip the functions which are not for the module + ret = print_function_wrapper(module, function, wrapper, export, include) if ret < 0: failed = failed + 1 - functions_failed.append(function) - del functions[function] + funcs_failed.append(function) + del funcs[function] if ret == 0: skipped = skipped + 1 - functions_skipped.append(function) - del functions[function] + funcs_skipped.append(function) + del funcs[function] if ret == 1: nb_wrap = nb_wrap + 1 include.close() @@ -679,7 +773,7 @@ def buildStubs(): for type in unknown_types.keys(): print "%s:%d " % (type, len(unknown_types[type])), - for f in functions_failed: + for f in funcs_failed: print "ERROR: failed %s" % f if failed > 0: @@ -734,6 +828,7 @@ primary_classes = ["virDomain", "virNetwork", "virInterface", classes_ancestor = { } + classes_destructors = { "virDomain": "virDomainFree", "virNetwork": "virNetworkFree", @@ -956,8 +1051,8 @@ def nameFixup(name, classe, type, file): def functionCompare(info1, info2): - (index1, func1, name1, ret1, args1, file1) = info1 - (index2, func2, name2, ret2, args2, file2) = info2 + (index1, func1, name1, ret1, args1, file1, mod1) = info1 + (index2, func2, name2, ret2, args2, file2, mod2) = info2 if file1 == file2: if func1 < func2: return -1 @@ -973,10 +1068,14 @@ def functionCompare(info1, info2): return 1 return 0 -def writeDoc(name, args, indent, output): - if functions[name][0] is None or functions[name][0] == "": +def writeDoc(module, name, args, indent, output): + if module == "libvirt": + funcs = functions + elif module == "libvirt-qemu": + funcs = qemu_functions + if funcs[name][0] is None or funcs[name][0] == "": return - val = functions[name][0] + val = funcs[name][0] val = string.replace(val, "NULL", "None"); output.write(indent) output.write('"""') @@ -990,7 +1089,7 @@ def writeDoc(name, args, indent, output): output.write(val) output.write(' """\n') -def buildWrappers(): +def buildWrappers(module): global ctypes global py_types global py_return_types @@ -1005,10 +1104,13 @@ def buildWrappers(): global classes_ancestor global converter_type global primary_classes - global classes_ancestor global classes_destructors global functions_noexcept + if not module == "libvirt": + print "ERROR: Unknown module type: %s" % module + return None + for type in classes_type.keys(): function_classes[classes_type[type][2]] = [] @@ -1041,30 +1143,35 @@ def buildWrappers(): for name in functions.keys(): found = 0; - (desc, ret, args, file, cond) = functions[name] + (desc, ret, args, file, mod, cond) = functions[name] for type in ctypes: classe = classes_type[type][2] if name[0:3] == "vir" and len(args) >= 1 and args[0][1] == type: found = 1 func = nameFixup(name, classe, type, file) - info = (0, func, name, ret, args, file) + info = (0, func, name, ret, args, file, mod) function_classes[classe].append(info) elif name[0:3] == "vir" and len(args) >= 2 and args[1][1] == type \ and file != "python_accessor" and not name in function_skip_index_one: found = 1 func = nameFixup(name, classe, type, file) - info = (1, func, name, ret, args, file) + info = (1, func, name, ret, args, file, mod) function_classes[classe].append(info) if found == 1: continue func = nameFixup(name, "None", file, file) - info = (0, func, name, ret, args, file) + info = (0, func, name, ret, args, file, mod) function_classes['None'].append(info) - classes = open("libvirt.py", "w") + classes_file = "%s.py" % module + extra_file = "%s-override.py" % module + extra = None + + classes = open(classes_file, "w") - extra = open(os.path.join(srcPref,"libvirt-override.py"), "r") + if os.path.exists(extra_file): + extra = open(os.path.join(srcPref,extra_file), "r") classes.write("#! " + python + " -i\n") classes.write("#\n") classes.write("# WARNING WARNING WARNING WARNING\n") @@ -1072,26 +1179,28 @@ def buildWrappers(): classes.write("# This file is automatically written by generator.py. Any changes\n") classes.write("# made here will be lost.\n") classes.write("#\n") - classes.write("# To change the manually written methods edit libvirt-override.py\n") + classes.write("# To change the manually written methods edit " + module + "-override.py\n") classes.write("# To change the automatically written methods edit generator.py\n") classes.write("#\n") classes.write("# WARNING WARNING WARNING WARNING\n") classes.write("#\n") - classes.writelines(extra.readlines()) + if extra != None: + classes.writelines(extra.readlines()) classes.write("#\n") classes.write("# WARNING WARNING WARNING WARNING\n") classes.write("#\n") classes.write("# Automatically written part of python bindings for libvirt\n") classes.write("#\n") classes.write("# WARNING WARNING WARNING WARNING\n") - extra.close() + if extra != None: + extra.close() if function_classes.has_key("None"): flist = function_classes["None"] flist.sort(functionCompare) oldfile = "" for info in flist: - (index, func, name, ret, args, file) = info + (index, func, name, ret, args, file, mod) = info if file != oldfile: classes.write("#\n# Functions from module %s\n#\n\n" % file) oldfile = file @@ -1103,7 +1212,7 @@ def buildWrappers(): classes.write("%s" % arg[0]) n = n + 1 classes.write("):\n") - writeDoc(name, args, ' ', classes); + writeDoc(module, name, args, ' ', classes); for arg in args: if classes_type.has_key(arg[1]): @@ -1235,7 +1344,7 @@ def buildWrappers(): flist.sort(functionCompare) oldfile = "" for info in flist: - (index, func, name, ret, args, file) = info + (index, func, name, ret, args, file, mod) = info # # Do not provide as method the destructors for the class # to avoid double free @@ -1258,7 +1367,7 @@ def buildWrappers(): classes.write(", %s" % arg[0]) n = n + 1 classes.write("):\n") - writeDoc(name, args, ' ', classes); + writeDoc(module, name, args, ' ', classes); n = 0 for arg in args: if classes_type.has_key(arg[1]): @@ -1272,8 +1381,8 @@ def buildWrappers(): classes.write(" ret = "); else: classes.write(" "); - classes.write("libvirtmod.%s(" % name) n = 0 + classes.write("libvirtmod.%s(" % name) for arg in args: if n != 0: classes.write(", "); @@ -1501,7 +1610,123 @@ def buildWrappers(): classes.close() -if buildStubs() < 0: +def qemuBuildWrappers(module): + global qemu_functions + + if not module == "libvirt-qemu": + print "ERROR: only libvirt-qemu is supported" + return None + + extra_file = "%s-override.py" % module + extra = None + + fd = open("libvirt_qemu.py", "w") + + if os.path.exists(extra_file): + extra = open(os.path.join(srcPref,extra_file), "r") + fd.write("#! " + python + " -i\n") + fd.write("#\n") + fd.write("# WARNING WARNING WARNING WARNING\n") + fd.write("#\n") + fd.write("# This file is automatically written by generator.py. Any changes\n") + fd.write("# made here will be lost.\n") + fd.write("#\n") + fd.write("# To change the manually written methods edit " + module + "-override.py\n") + fd.write("# To change the automatically written methods edit generator.py\n") + fd.write("#\n") + fd.write("# WARNING WARNING WARNING WARNING\n") + fd.write("#\n") + if extra != 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 != None: + extra.close() + + fd.write("try:\n") + fd.write(" import libvirtmod_qemu\n") + fd.write("except ImportError, lib_e:\n") + fd.write(" try:\n") + fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n") + fd.write(" except ImportError, cyg_e:\n") + fd.write(" if str(cyg_e).count(\"No module named\"):\n") + fd.write(" raise lib_e\n\n") + + fd.write("import libvirt\n\n"); + fd.write("#\n# Functions from module %s\n#\n\n" % module) + # + # Generate functions directly, no classes + # + for name in qemu_functions.keys(): + func = nameFixup(name, 'None', None, None) + (desc, ret, args, file, mod, cond) = qemu_functions[name] + fd.write("def %s(" % func) + n = 0 + for arg in args: + if n != 0: + fd.write(", ") + fd.write("%s" % arg[0]) + n = n + 1 + fd.write("):\n") + writeDoc(module, name, args, ' ', fd); + + if ret[0] != "void": + fd.write(" ret = "); + else: + fd.write(" "); + fd.write("libvirtmod_qemu.%s(" % name) + n = 0 + + conn = None + + for arg in args: + if arg[1] == "virConnectPtr": + conn = arg[0] + + if n != 0: + fd.write(", "); + if arg[1] in ["virDomainPtr", "virConnectPtr"]: + # FIXME: This might have problem if the function + # has multiple args which are objects. + fd.write("%s.%s" % (arg[0], "_o")) + else: + fd.write("%s" % arg[0]) + n = n + 1 + fd.write(")\n"); + + if ret[0] != "void": + fd.write(" if ret is None: raise libvirt.libvirtError('" + name + "() failed')\n") + if ret[0] == "virDomainPtr": + fd.write(" __tmp = virDomain(" + conn + ",_obj=ret)\n") + fd.write(" return __tmp\n") + else: + fd.write(" return ret\n") + + fd.write("\n") + + # + # Generate enum constants + # + for type,enum in qemu_enums.items(): + fd.write("# %s\n" % type) + items = enum.items() + items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1]))) + for name,value in items: + fd.write("%s = %s\n" % (name,value)) + fd.write("\n"); + + fd.close() + + +quiet = 0 +if buildStubs("libvirt") < 0: + sys.exit(1) +if buildStubs("libvirt-qemu") < 0: sys.exit(1) -buildWrappers() +buildWrappers("libvirt") +qemuBuildWrappers("libvirt-qemu") sys.exit(0) -- 1.7.6

On Fri, Sep 09, 2011 at 07:24:45PM +0800, Osier Yang wrote:
It will generate: libvirt-qemu.py libvirt-qemu.h libvirt-qemu.c libvirt-qemu-export.c --- python/generator.py | 363 +++++++++++++++++++++++++++++++++++++++++----------
ACK looks fine and result too, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- python/Makefile.am | 33 ++++++++++++++++++++++++++++----- 1 files changed, 28 insertions(+), 5 deletions(-) diff --git a/python/Makefile.am b/python/Makefile.am index 5943fe8..3068eee 100644 --- a/python/Makefile.am +++ b/python/Makefile.am @@ -29,15 +29,18 @@ EXTRA_DIST = \ libvirt-override.c \ libvirt-override.py \ libvirt-override-api.xml \ + libvirt-qemu-override.c \ + libvirt-qemu-override-api.xml \ $(CLASSES_EXTRA) \ $(DOCS) if WITH_PYTHON mylibs = $(top_builddir)/src/libvirt.la +myqemulibs = $(top_builddir)/src/libvirt-qemu.la -all-local: libvirt.py +all-local: libvirt.py libvirt_qemu.py -pyexec_LTLIBRARIES = libvirtmod.la +pyexec_LTLIBRARIES = libvirtmod.la libvirtmod_qemu.la libvirtmod_la_SOURCES = libvirt-override.c typewrappers.c nodist_libvirtmod_la_SOURCES = libvirt.c libvirt.h @@ -50,6 +53,17 @@ libvirtmod_la_LDFLAGS = -module -avoid-version -shared -L$(top_builddir)/src/.li libvirtmod_la_LIBADD = $(mylibs) \ $(CYGWIN_EXTRA_LIBADD) $(CYGWIN_EXTRA_PYTHON_LIBADD) +libvirtmod_qemu_la_SOURCES = libvirt-qemu-override.c typewrappers.c +nodist_libvirtmod_qemu_la_SOURCES = libvirt-qemu.c libvirt-qemu.h +# Python <= 2.4 header files contain a redundant decl, hence we +# need extra flags here +libvirtmod_qemu_la_CFLAGS = $(WARN_PYTHON_CFLAGS) + +libvirtmod_qemu_la_LDFLAGS = -module -avoid-version -shared -L$(top_builddir)/src/.libs \ + $(CYGWIN_EXTRA_LDFLAGS) +libvirtmod_qemu_la_LIBADD = $(myqemulibs) \ + $(CYGWIN_EXTRA_LIBADD) $(CYGWIN_EXTRA_PYTHON_LIBADD) + GENERATE = generator.py API_DESC = $(top_srcdir)/docs/libvirt-api.xml $(srcdir)/libvirt-override-api.xml GENERATED= libvirt-export.c \ @@ -57,25 +71,34 @@ GENERATED= libvirt-export.c \ libvirt.h \ libvirt.py -$(GENERATE).stamp: $(srcdir)/$(GENERATE) $(API_DESC) +QEMU_API_DESC = $(top_srcdir)/docs/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-override-api.xml +QEMU_GENERATED= libvirt-qemu-export.c \ + libvirt-qemu.c \ + libvirt-qemu.h \ + libvirt_qemu.py + +$(GENERATE).stamp: $(srcdir)/$(GENERATE) $(API_DESC) $(QEMU_API_DESC) $(AM_V_GEN)$(PYTHON) $(srcdir)/$(GENERATE) $(PYTHON) && \ touch $@ -$(GENERATED): $(GENERATE).stamp +$(GENERATED) $(QEMU_GENERATED): $(GENERATE).stamp $(libvirtmod_la_OBJECTS): $(GENERATED) +$(libvirtmod_qemu_la_OBJECTS): $(QEMU_GENERATED) install-data-local: $(mkinstalldirs) $(DESTDIR)$(pyexecdir) $(INSTALL) -m 0644 libvirt.py $(DESTDIR)$(pyexecdir) + $(INSTALL) -m 0644 libvirt_qemu.py $(DESTDIR)$(pyexecdir) $(mkinstalldirs) $(DESTDIR)$(DOCS_DIR) @(for doc in $(DOCS) ; \ do $(INSTALL) -m 0644 $$doc $(DESTDIR)$(DOCS_DIR) ; done) uninstall-local: rm -f $(DESTDIR)$(pyexecdir)/libvirt.py + rm -f $(DESTDIR)$(pyexecdir)/libvirt_qemu.py -CLEANFILES= $(GENERATED) $(GENERATE).stamp +CLEANFILES= $(GENERATED) $(QEMU_GENERATED) $(GENERATE).stamp else all: -- 1.7.6

On Fri, Sep 09, 2011 at 07:24:46PM +0800, Osier Yang wrote:
--- python/Makefile.am | 33 ++++++++++++++++++++++++++++----- 1 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/python/Makefile.am b/python/Makefile.am index 5943fe8..3068eee 100644 --- a/python/Makefile.am +++ b/python/Makefile.am @@ -29,15 +29,18 @@ EXTRA_DIST = \ libvirt-override.c \ libvirt-override.py \ libvirt-override-api.xml \ + libvirt-qemu-override.c \ + libvirt-qemu-override-api.xml \ $(CLASSES_EXTRA) \ $(DOCS)
if WITH_PYTHON mylibs = $(top_builddir)/src/libvirt.la +myqemulibs = $(top_builddir)/src/libvirt-qemu.la
-all-local: libvirt.py +all-local: libvirt.py libvirt_qemu.py
-pyexec_LTLIBRARIES = libvirtmod.la +pyexec_LTLIBRARIES = libvirtmod.la libvirtmod_qemu.la
libvirtmod_la_SOURCES = libvirt-override.c typewrappers.c nodist_libvirtmod_la_SOURCES = libvirt.c libvirt.h @@ -50,6 +53,17 @@ libvirtmod_la_LDFLAGS = -module -avoid-version -shared -L$(top_builddir)/src/.li libvirtmod_la_LIBADD = $(mylibs) \ $(CYGWIN_EXTRA_LIBADD) $(CYGWIN_EXTRA_PYTHON_LIBADD)
+libvirtmod_qemu_la_SOURCES = libvirt-qemu-override.c typewrappers.c +nodist_libvirtmod_qemu_la_SOURCES = libvirt-qemu.c libvirt-qemu.h +# Python <= 2.4 header files contain a redundant decl, hence we +# need extra flags here +libvirtmod_qemu_la_CFLAGS = $(WARN_PYTHON_CFLAGS) + +libvirtmod_qemu_la_LDFLAGS = -module -avoid-version -shared -L$(top_builddir)/src/.libs \ + $(CYGWIN_EXTRA_LDFLAGS) +libvirtmod_qemu_la_LIBADD = $(myqemulibs) \ + $(CYGWIN_EXTRA_LIBADD) $(CYGWIN_EXTRA_PYTHON_LIBADD) + GENERATE = generator.py API_DESC = $(top_srcdir)/docs/libvirt-api.xml $(srcdir)/libvirt-override-api.xml GENERATED= libvirt-export.c \ @@ -57,25 +71,34 @@ GENERATED= libvirt-export.c \ libvirt.h \ libvirt.py
-$(GENERATE).stamp: $(srcdir)/$(GENERATE) $(API_DESC) +QEMU_API_DESC = $(top_srcdir)/docs/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-override-api.xml +QEMU_GENERATED= libvirt-qemu-export.c \ + libvirt-qemu.c \ + libvirt-qemu.h \ + libvirt_qemu.py + +$(GENERATE).stamp: $(srcdir)/$(GENERATE) $(API_DESC) $(QEMU_API_DESC) $(AM_V_GEN)$(PYTHON) $(srcdir)/$(GENERATE) $(PYTHON) && \ touch $@
-$(GENERATED): $(GENERATE).stamp +$(GENERATED) $(QEMU_GENERATED): $(GENERATE).stamp
$(libvirtmod_la_OBJECTS): $(GENERATED) +$(libvirtmod_qemu_la_OBJECTS): $(QEMU_GENERATED)
install-data-local: $(mkinstalldirs) $(DESTDIR)$(pyexecdir) $(INSTALL) -m 0644 libvirt.py $(DESTDIR)$(pyexecdir) + $(INSTALL) -m 0644 libvirt_qemu.py $(DESTDIR)$(pyexecdir) $(mkinstalldirs) $(DESTDIR)$(DOCS_DIR) @(for doc in $(DOCS) ; \ do $(INSTALL) -m 0644 $$doc $(DESTDIR)$(DOCS_DIR) ; done)
uninstall-local: rm -f $(DESTDIR)$(pyexecdir)/libvirt.py + rm -f $(DESTDIR)$(pyexecdir)/libvirt_qemu.py
-CLEANFILES= $(GENERATED) $(GENERATE).stamp +CLEANFILES= $(GENERATED) $(QEMU_GENERATED) $(GENERATE).stamp
else all:
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- libvirt.spec.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/libvirt.spec.in b/libvirt.spec.in index 9decc31..648b50f 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1134,6 +1134,7 @@ fi %doc AUTHORS NEWS README COPYING.LIB %{_libdir}/python*/site-packages/libvirt.py* +%{_libdir}/python*/site-packages/libvirt_qemu.py* %{_libdir}/python*/site-packages/libvirtmod* %doc python/tests/*.py %doc python/TODO -- 1.7.6

On Fri, Sep 09, 2011 at 07:24:47PM +0800, Osier Yang wrote:
--- libvirt.spec.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in index 9decc31..648b50f 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1134,6 +1134,7 @@ fi
%doc AUTHORS NEWS README COPYING.LIB %{_libdir}/python*/site-packages/libvirt.py* +%{_libdir}/python*/site-packages/libvirt_qemu.py* %{_libdir}/python*/site-packages/libvirtmod* %doc python/tests/*.py %doc python/TODO
And ACK, just pull in the small fix for patch 2 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

于 2011年09月14日 10:55, Daniel Veillard 写道:
On Fri, Sep 09, 2011 at 07:24:47PM +0800, Osier Yang wrote:
--- libvirt.spec.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in index 9decc31..648b50f 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1134,6 +1134,7 @@ fi
%doc AUTHORS NEWS README COPYING.LIB %{_libdir}/python*/site-packages/libvirt.py* +%{_libdir}/python*/site-packages/libvirt_qemu.py* %{_libdir}/python*/site-packages/libvirtmod* %doc python/tests/*.py %doc python/TODO And ACK, just pull in the small fix for patch 2
Daniel
Pushed with the fixing on patch 2/7, thanks for the reviewing. Regards, Osier

On Fri, Sep 09, 2011 at 07:24:40PM +0800, Osier Yang wrote:
This patchset is to expose QEMU APIs to Python binding, as we don't intend to support the QEMU APIs officially, it's exposed seperately with general libvirt APIs with standalone libvirt_qemu.py and libvirtmod_qemu.so. And there is no class for QEMU APIs, there are written directly as function in libvirt_qemu.py.
How to use the APIs.
#! /usr/bin/python -u import libvirt import libvirt_qemu
conn = libvirt.open(None) dom = conn.lookupByName('test')
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1) libvirt_qemu.qemuAttach(conn, 2307, 0)
This feels like rather a strange way to expose this in Python. We currently have 'libvirt.Connection' and 'libvirt.Domain' objects in the Python binding.
conn = libvirt.open(None)
This is giving us a libvirt.Connection object.
dom = conn.lookupByName('test')
This is giving us a libvirt.Domain object.
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1)
And this is just wierd. What I think is that we should have a 'libvirt_qemu.QemuConnection' object which is a subclass of 'libvirt.Connection', and 'libvirt_qemu.QemuDomain' object which is a subclass of libvirt.Domain' which adds the new QEMU specific method 'qemuMonitorCommand'. So the example usage would end up being
#! /usr/bin/python -u import libvirt import libvirt_qemu
conn = libvirt_qemu.open(None)
This would be a libvirt_qemu.QemuConnection object.
dom = conn.lookupByName('test')
And this would thus now be a libvirt_qemu.QemuDomain object, so that finally you can simply do
dom.qemuMonitorCommand('info blockstats', 1)
# cat libvirt_qemu.py def open(name) ....call libvirt.open and turn the result into a libvirt_qemu.QemuConnection object class QemuConnection(libvirt.Connection): def __init__(....) ... def lookupByName(name) ...call original lookupByName method and turn the result into a libvirt_qemu.Domain object instead class QemuDomain(libvirt.Domain): def __init__(....) ... def qemuMonitorCommand(cmd, flags) ... Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Mon, Sep 12, 2011 at 03:29:32PM +0100, Daniel P. Berrange wrote:
On Fri, Sep 09, 2011 at 07:24:40PM +0800, Osier Yang wrote:
This patchset is to expose QEMU APIs to Python binding, as we don't intend to support the QEMU APIs officially, it's exposed seperately with general libvirt APIs with standalone libvirt_qemu.py and libvirtmod_qemu.so. And there is no class for QEMU APIs, there are written directly as function in libvirt_qemu.py.
How to use the APIs.
#! /usr/bin/python -u import libvirt import libvirt_qemu
conn = libvirt.open(None) dom = conn.lookupByName('test')
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1) libvirt_qemu.qemuAttach(conn, 2307, 0)
This feels like rather a strange way to expose this in Python.
We currently have 'libvirt.Connection' and 'libvirt.Domain' objects in the Python binding.
conn = libvirt.open(None)
This is giving us a libvirt.Connection object.
dom = conn.lookupByName('test')
This is giving us a libvirt.Domain object.
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1)
And this is just wierd.
Yes, but bypassing libvirt API by using the monitor direct is weird. Let's repeat that the goal is to provide the functionality until a correct long term supported API for the feature is provided in libvirt itself.
What I think is that we should have a 'libvirt_qemu.QemuConnection' object which is a subclass of 'libvirt.Connection', and 'libvirt_qemu.QemuDomain' object which is a subclass of libvirt.Domain' which adds the new QEMU specific method 'qemuMonitorCommand'.
And then you completely blur the lines of what is supported normal libvirt APIs and what is bypassing them. qemuMonitorCommand has no structure, not the same kind of long term garantees like libvirt has and IMHO if it is to be used in client code it should be done in a separate module to well identify the separation. Blurring the fundamental difference by using a subclass at creation is the best way to garantee that code bypassing libvirt APIs will be intermixed with normal API code. And that's precisely why I suggested osier to not use inheritance here. The goal is not to make nice code, the goal is to allow temporary code but make sure people switch to the libvirt APIs once they are implemented. That's also the reason why we want a separate import libvirt_qemu instead of just making it available from import libvirt which from a coding perspective would also be nicer. So I really prefer version 2, even if it looks less nice from a coding perspective. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Sep 13, 2011 at 01:08:00PM +0800, Daniel Veillard wrote:
On Mon, Sep 12, 2011 at 03:29:32PM +0100, Daniel P. Berrange wrote:
On Fri, Sep 09, 2011 at 07:24:40PM +0800, Osier Yang wrote:
This patchset is to expose QEMU APIs to Python binding, as we don't intend to support the QEMU APIs officially, it's exposed seperately with general libvirt APIs with standalone libvirt_qemu.py and libvirtmod_qemu.so. And there is no class for QEMU APIs, there are written directly as function in libvirt_qemu.py.
How to use the APIs.
#! /usr/bin/python -u import libvirt import libvirt_qemu
conn = libvirt.open(None) dom = conn.lookupByName('test')
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1) libvirt_qemu.qemuAttach(conn, 2307, 0)
This feels like rather a strange way to expose this in Python.
We currently have 'libvirt.Connection' and 'libvirt.Domain' objects in the Python binding.
conn = libvirt.open(None)
This is giving us a libvirt.Connection object.
dom = conn.lookupByName('test')
This is giving us a libvirt.Domain object.
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1)
And this is just wierd.
Yes, but bypassing libvirt API by using the monitor direct is weird. Let's repeat that the goal is to provide the functionality until a correct long term supported API for the feature is provided in libvirt itself.
What I think is that we should have a 'libvirt_qemu.QemuConnection' object which is a subclass of 'libvirt.Connection', and 'libvirt_qemu.QemuDomain' object which is a subclass of libvirt.Domain' which adds the new QEMU specific method 'qemuMonitorCommand'.
And then you completely blur the lines of what is supported normal libvirt APIs and what is bypassing them. qemuMonitorCommand has no structure, not the same kind of long term garantees like libvirt has and IMHO if it is to be used in client code it should be done in a separate module to well identify the separation. Blurring the fundamental difference by using a subclass at creation is the best way to garantee that code bypassing libvirt APIs will be intermixed with normal API code. And that's precisely why I suggested osier to not use inheritance here. The goal is not to make nice code, the goal is to allow temporary code but make sure people switch to the libvirt APIs once they are implemented. That's also the reason why we want a separate import libvirt_qemu instead of just making it available from import libvirt which from a coding perspective would also be nicer.
Err, my example *was* still requiring that apps use 'import libvirt_qemu' in order to get access to the QEMU specific APIs, and use that separate objects to get their connection handle. I don't think the support distinction merits avoiding the natural inheritance model for the python code. We just need to make sure that app developers need to make an explicit decision to use the 'libvirt_qemu' package, instead of 'libvirt' package in their code. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Sep 13, 2011 at 10:07:37AM +0100, Daniel P. Berrange wrote:
On Tue, Sep 13, 2011 at 01:08:00PM +0800, Daniel Veillard wrote:
On Mon, Sep 12, 2011 at 03:29:32PM +0100, Daniel P. Berrange wrote:
On Fri, Sep 09, 2011 at 07:24:40PM +0800, Osier Yang wrote:
This patchset is to expose QEMU APIs to Python binding, as we don't intend to support the QEMU APIs officially, it's exposed seperately with general libvirt APIs with standalone libvirt_qemu.py and libvirtmod_qemu.so. And there is no class for QEMU APIs, there are written directly as function in libvirt_qemu.py.
How to use the APIs.
#! /usr/bin/python -u import libvirt import libvirt_qemu
conn = libvirt.open(None) dom = conn.lookupByName('test')
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1) libvirt_qemu.qemuAttach(conn, 2307, 0)
This feels like rather a strange way to expose this in Python.
We currently have 'libvirt.Connection' and 'libvirt.Domain' objects in the Python binding.
conn = libvirt.open(None)
This is giving us a libvirt.Connection object.
dom = conn.lookupByName('test')
This is giving us a libvirt.Domain object.
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1)
And this is just wierd.
Yes, but bypassing libvirt API by using the monitor direct is weird. Let's repeat that the goal is to provide the functionality until a correct long term supported API for the feature is provided in libvirt itself.
What I think is that we should have a 'libvirt_qemu.QemuConnection' object which is a subclass of 'libvirt.Connection', and 'libvirt_qemu.QemuDomain' object which is a subclass of libvirt.Domain' which adds the new QEMU specific method 'qemuMonitorCommand'.
And then you completely blur the lines of what is supported normal libvirt APIs and what is bypassing them. qemuMonitorCommand has no structure, not the same kind of long term garantees like libvirt has and IMHO if it is to be used in client code it should be done in a separate module to well identify the separation. Blurring the fundamental difference by using a subclass at creation is the best way to garantee that code bypassing libvirt APIs will be intermixed with normal API code. And that's precisely why I suggested osier to not use inheritance here. The goal is not to make nice code, the goal is to allow temporary code but make sure people switch to the libvirt APIs once they are implemented. That's also the reason why we want a separate import libvirt_qemu instead of just making it available from import libvirt which from a coding perspective would also be nicer.
Err, my example *was* still requiring that apps use 'import libvirt_qemu' in order to get access to the QEMU specific APIs, and use that separate objects to get their connection handle.
yes but from that point on if you use inheritance, the fact of using the qemu tainted objects instead of the normal ones disapear completely. The fact of using those temporary APIs get hidden in an import and a new() somewhere. I would really prefer to see something explicit at the place where it is used, something that people can't miss where reading the code using it. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Sep 13, 2011 at 05:18:40PM +0800, Daniel Veillard wrote:
On Tue, Sep 13, 2011 at 10:07:37AM +0100, Daniel P. Berrange wrote:
On Tue, Sep 13, 2011 at 01:08:00PM +0800, Daniel Veillard wrote: Err, my example *was* still requiring that apps use 'import libvirt_qemu' in order to get access to the QEMU specific APIs, and use that separate objects to get their connection handle.
yes but from that point on if you use inheritance, the fact of using the qemu tainted objects instead of the normal ones disapear completely. The fact of using those temporary APIs get hidden in an import and a new() somewhere. I would really prefer to see something explicit at the place where it is used, something that people can't miss where reading the code using it.
Okay, the two Dan disagree but none want to force the issue, can other people voice in so that we can go with the majority :-) ? Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

于 2011年09月13日 18:07, Daniel Veillard 写道:
On Tue, Sep 13, 2011 at 01:08:00PM +0800, Daniel Veillard wrote: Err, my example *was* still requiring that apps use 'import libvirt_qemu' in order to get access to the QEMU specific APIs, and use that separate objects to get their connection handle. yes but from that point on if you use inheritance, the fact of using
On Tue, Sep 13, 2011 at 10:07:37AM +0100, Daniel P. Berrange wrote: the qemu tainted objects instead of the normal ones disapear completely. The fact of using those temporary APIs get hidden in an import and a new() somewhere. I would really prefer to see something explicit at the place where it is used, something that people can't miss where reading the code using it. Okay, the two Dan disagree but none want to force the issue, can other
On Tue, Sep 13, 2011 at 05:18:40PM +0800, Daniel Veillard wrote: people voice in so that we can go with the majority :-) ?
Daniel
I have ever did a first version as what danpb suggested. But when talked with DV on Friday morning, I was persuaed, so, I vote for defining the function without class in libvirt_qemu.py, note that this will ease my work. :-) Regards, Osier

On 09/13/2011 03:18 AM, Daniel Veillard wrote:
yes but from that point on if you use inheritance, the fact of using the qemu tainted objects instead of the normal ones disapear completely. The fact of using those temporary APIs get hidden in an import and a new() somewhere. I would really prefer to see something explicit at the place where it is used, something that people can't miss where reading the code using it.
I like the idea of making the unsupported qemu-tainted objects explicit at every use point rather than hidden behind the import and new() hundreds of lines earlier in the file; at any rate, it means when you later revisit the file to clean out the unsupported qemu direct use with newly added libvirt features, you know every line that needs fixing. But I'm not enough of a python coder to know if this is typically done anywhere else, so I don't know if my vote counts as a tie-breaker. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Tue, Sep 13, 2011 at 04:44:50PM -0600, Eric Blake wrote:
On 09/13/2011 03:18 AM, Daniel Veillard wrote:
yes but from that point on if you use inheritance, the fact of using the qemu tainted objects instead of the normal ones disapear completely. The fact of using those temporary APIs get hidden in an import and a new() somewhere. I would really prefer to see something explicit at the place where it is used, something that people can't miss where reading the code using it.
I like the idea of making the unsupported qemu-tainted objects explicit at every use point rather than hidden behind the import and new() hundreds of lines earlier in the file; at any rate, it means when you later revisit the file to clean out the unsupported qemu direct use with newly added libvirt features, you know every line that needs fixing. But I'm not enough of a python coder to know if this is typically done anywhere else, so I don't know if my vote counts as a tie-breaker.
sure, guess that between your feedback and Osier one, we should go for the second solution, thanks ! Daniel BTW it's trivial for the user to make a superset class and use that, but then it's a concious design decision on their part and shows up in their class hierarchy -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, Sep 09, 2011 at 07:24:40PM +0800, Osier Yang wrote:
This patchset is to expose QEMU APIs to Python binding, as we don't intend to support the QEMU APIs officially, it's exposed seperately with general libvirt APIs with standalone libvirt_qemu.py and libvirtmod_qemu.so. And there is no class for QEMU APIs, there are written directly as function in libvirt_qemu.py.
How to use the APIs.
#! /usr/bin/python -u import libvirt import libvirt_qemu
conn = libvirt.open(None) dom = conn.lookupByName('test')
print libvirt_qemu.qemuMonitorCommand(dom, 'info blockstats', 1) libvirt_qemu.qemuAttach(conn, 2307, 0)
PS: make check/make dist/make rpm are passed.
I found another problem when running 'make dist', I had to apply the following patch to avoid an error due to the fact the 2 files are not generated. I looked and generating them would require to patch the XSLT files and docs/Makefile.am . So as a temporary mesure I just removed them but we probably ought to fix this Daniel diff --git a/docs/Makefile.am b/docs/Makefile.am index 0eb69b2..0b8f226 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -17,7 +17,6 @@ BUILT_SOURCES=hvsupport.html.in apihtml = \ html/index.html \ html/libvirt-libvirt.html \ - html/libvirt-libvirt-qemu.html \ html/libvirt-virterror.html apipng = \ @@ -31,7 +30,6 @@ devhelphtml = \ devhelp/index.html \ devhelp/general.html \ devhelp/libvirt-libvirt.html \ - devhelp/libvirt-libvirt-qemu.html \ devhelp/libvirt-virterror.html css = \ -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (5)
-
Daniel P. Berrange
-
Daniel Veillard
-
Eric Blake
-
Jiri Denemark
-
Osier Yang