[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH,RFC]: libxl python binding
Attached patch is the first-cut of a libxl python binding. Presently only list_domains, domid_to_name, domain_shutdown and domain_destroy are implemented. The code takes advantage of Ian Campbells libxl IDL work to make 178 lines of python generate 4,460 lines of boilerplate. All that remains is: - support marshalling of other than integer types - call auto-generated C destructors when python objects are free'd - flatten out unions, structs etc. for libxl-type marshalling - manually implement a xen.lowlevel.xl.ctx method for each libxl function Here's an example of what current code can do: $ sudo python >>> from xen.lowlevel import xl >>> xl <module 'xen.lowlevel.xl' from '/usr/lib/python2.6/dist-packages/xen/lowlevel/xl.so'> >>> dir(xl) ['Error', '__doc__', '__file__', '__name__', '__package__', 'ctx', 'device_console', 'device_disk', 'device_model_info', 'device_net2', 'device_nic', 'device_pci', 'device_vfb', 'device_vkb', 'diskinfo', 'domain_build_info', 'domain_build_state', 'domain_create_info', 'dominfo', 'file_reference', 'net2info', 'nicinfo', 'physinfo', 'poolinfo', 'sched_credit', 'vcpuinfo', 'version_info', 'vminfo'] >>> ctx = xl.ctx() >>> dir(ctx) ['domain_destroy', 'domain_shutdown', 'domid_to_name', 'list_domains'] >>> ctx.list_domains() [<xen.lowlevel.xl.dominfo object at 0x7f6765492a08>, <xen.lowlevel.xl.dominfo object at 0x7f6765492a50>, <xen.lowlevel.xl.dominfo object at 0x7f6765492a98>] >>> map(lambda x:x.domid, ctx.list_domains()) [0L, 133L, 136L] >>> map(ctx.domid_to_name, map(lambda x:x.domid, ctx.list_domains())) ['Domain-0', 'netbsd', 'lenny'] >>> ctx.domain_destroy(136) >>> map(ctx.domid_to_name, map(lambda x:x.domid, ctx.list_domains())) ['Domain-0', 'netbsd'] ----- tools/python/genwrap.py | 178 +++++++++++++++++++++++ tools/python/xen/lowlevel/xl/xl.c | 269 ++++++++++++++++++++++++++++++++++++ tools/libxl/libxl.idl | 10 - tools/libxl/libxltypes.py | 23 ++- tools/python/Makefile | 1 tools/python/setup.py | 19 ++ 6 files changed, 486 insertions(+), 14 deletions(-) ----8<----------------------------------------------------------------- diff -r d11a52daace3 tools/libxl/libxl.idl --- a/tools/libxl/libxl.idl Mon Sep 06 15:16:03 2010 +0100 +++ b/tools/libxl/libxl.idl Tue Sep 07 15:22:24 2010 +0100 @@ -6,11 +6,11 @@ libxl_ctx = Builtin("ctx") libxl_uuid = Builtin("uuid") libxl_mac = Builtin("mac") -libxl_qemu_machine_type = Builtin("qemu_machine_type") -libxl_console_consback = Builtin("console_consback") -libxl_console_constype = Builtin("console_constype") -libxl_disk_phystype = Builtin("disk_phystype") -libxl_nic_type = Builtin("nic_type") +libxl_qemu_machine_type = Number("qemu_machine_type", namespace="libxl_") +libxl_console_consback = Number("console_consback", namespace="libxl_") +libxl_console_constype = Number("console_constype", namespace="libxl_") +libxl_disk_phystype = Number("disk_phystype", namespace="libxl_") +libxl_nic_type = Number("nic_type", namespace="libxl_") libxl_string_list = Builtin("string_list", destructor_fn="libxl_string_list_destroy", passby=PASS_BY_REFERENCE) libxl_key_value_list = Builtin("key_value_list", destructor_fn="libxl_key_value_list_destroy", passby=PASS_BY_REFERENCE) diff -r d11a52daace3 tools/libxl/libxltypes.py --- a/tools/libxl/libxltypes.py Mon Sep 06 15:16:03 2010 +0100 +++ b/tools/libxl/libxltypes.py Tue Sep 07 15:22:24 2010 +0100 @@ -14,10 +14,13 @@ class Type(object): if typename is None: # Anonymous type self.typename = None + self.rawname = None elif self.namespace is None: # e.g. system provided types self.typename = typename + self.rawname = typename else: self.typename = self.namespace + typename + self.rawname = typename if self.typename is not None: self.destructor_fn = kwargs.setdefault('destructor_fn', self.typename + "_destroy") @@ -32,11 +35,17 @@ class Builtin(Type): kwargs.setdefault('destructor_fn', None) Type.__init__(self, typename, **kwargs) -class UInt(Type): +class Number(Builtin): + def __init__(self, ctype, **kwargs): + kwargs.setdefault('namespace', None) + kwargs.setdefault('destructor_fn', None) + Builtin.__init__(self, ctype, **kwargs) + +class UInt(Number): def __init__(self, w, **kwargs): kwargs.setdefault('namespace', None) kwargs.setdefault('destructor_fn', None) - Type.__init__(self, "uint%d_t" % w, **kwargs) + Number.__init__(self, "uint%d_t" % w, **kwargs) self.width = w @@ -128,12 +137,12 @@ class Reference(Type): void = Builtin("void *", namespace = None) bool = Builtin("bool", namespace = None) -size_t = Builtin("size_t", namespace = None) +size_t = Number("size_t", namespace = None) -integer = Builtin("int", namespace = None) -unsigned_integer = Builtin("unsigned int", namespace = None) -unsigned = Builtin("unsigned int", namespace = None) -unsigned_long = Builtin("unsigned long", namespace = None) +integer = Number("int", namespace = None) +unsigned_integer = Number("unsigned int", namespace = None) +unsigned = Number("unsigned int", namespace = None) +unsigned_long = Number("unsigned long", namespace = None) uint8 = UInt(8) uint16 = UInt(16) diff -r d11a52daace3 tools/python/Makefile --- a/tools/python/Makefile Mon Sep 06 15:16:03 2010 +0100 +++ b/tools/python/Makefile Tue Sep 07 15:22:24 2010 +0100 @@ -59,6 +59,7 @@ refresh-po: $(POTFILE) .PHONY: install install: install-messages install-dtd + PYTHONPATH=$(XEN_ROOT)/tools/libxl $(PYTHON) genwrap.py $(XEN_ROOT)/tools/libxl/libxl.idl __pyxl_types.h CC="$(CC)" CFLAGS="$(CFLAGS)" $(PYTHON) setup.py install \ $(PYTHON_PREFIX_ARG) --root="$(DESTDIR)" --force diff -r d11a52daace3 tools/python/genwrap.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/genwrap.py Tue Sep 07 15:22:24 2010 +0100 @@ -0,0 +1,178 @@ +#!/usr/bin/python + +import sys +import re + +import libxltypes + +def py_wrapstruct(ty): + l = [] + l.append("typedef struct {") + l.append(" PyObject_HEAD;") + l.append(" %s obj;"%ty.typename); + l.append("}Py_%s;"%ty.rawname) + l.append("") + return "\n".join(l) + "\n\n" + +def py_type(ty): + if ty == libxltypes.bool or isinstance(ty, libxltypes.BitField) and ty.width == 1: + return "Bool" + if isinstance(ty, libxltypes.Number): + # FIXME: support unsigned properly + return "Int" + if ty == libxltypes.string: + return "String" + return None + +def py_attrib_get(ty, f): + if f.name == None: + return "" + t = py_type(f.type) + l = [] + l.append("static PyObject *py_%s_%s_get(Py_%s *self, void *priv)"%(ty.rawname, f.name, ty.rawname)) + l.append("{") + if t == "Int": + l.append(" return PyLong_FromUnsignedLong(self->obj.%s);"%f.name) + else: + l.append(" // %s"%t) + l.append(" return NULL;") + l.append("}") + return '\n'.join(l) + "\n\n" + +def py_attrib_set(ty, f): + if f.name == None: + return "" + t = py_type(f.type) + l = [] + l.append("static int py_%s_%s_set(Py_%s *self, PyObject *v, void *priv)"%(ty.rawname, f.name, ty.rawname)) + l.append("{") + if t == "Int": + l.append(" self->obj.%s = PyLong_AsLongLong(v);"%f.name) + l.append(" return 0;") + else: + l.append(" // %s"%t) + l.append(" return -1;") + l.append("}") + return '\n'.join(l) + "\n\n" + +def py_object_def(ty): + l = [] + funcs=""" +static void Py%s_dealloc(Py_%s *self) +{ + self->ob_type->tp_free((PyObject *)self); +} + +static int Py%s_init(Py_%s *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +static PyObject *Py%s_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Py_%s *self = (Py_%s *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + memset(&self->obj, 0, sizeof(self->obj)); + return (PyObject *)self; +} +"""%tuple(ty.rawname for x in range(7)) + + l.append("static PyGetSetDef Py%s_getset[] = {"%ty.rawname) + for f in ty.fields: + if f.name == None: + continue + l.append(" { .name = \"%s\", "%f.name) + l.append(" .get = (getter)py_%s_%s_get, "%(ty.rawname, f.name)) + l.append(" .set = (setter)py_%s_%s_set },"%(ty.rawname, f.name)) + l.append(" { .name = NULL }") + l.append("};") + struct=""" +static PyTypeObject Py%s_Type= { + PyObject_HEAD_INIT(NULL) + 0, + PKG ".%s", + sizeof(Py_%s), + 0, + (destructor)Py%s_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "%s", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + NULL, /* tp_methods */ + NULL, /* tp_members */ + Py%s_getset, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Py%s_init, /* tp_init */ + NULL, /* tp_alloc */ + Py%s_new, /* tp_new */ +}; + +"""%tuple(ty.rawname for x in range(8)) + return funcs + '\n'.join(l) + "\n\n" + struct + +def py_initfuncs(types): + l = [] + l.append("static void gentypes__init(PyObject *m)") + l.append("{") + for ty in types: + l.append(" if (PyType_Ready(&Py%s_Type) >= 0) {"%ty.rawname) + l.append(" Py_INCREF(&Py%s_Type);"%ty.rawname) + l.append(" PyModule_AddObject(m, \"%s\", (PyObject *)&Py%s_Type);"%(ty.rawname, ty.rawname)) + l.append(" }") + l.append("}") + return '\n'.join(l) + "\n\n" + +if __name__ == '__main__': + if len(sys.argv) < 3: + print >>sys.stderr, "Usage: genwrap.py <idl> <pythonwrapper>" + sys.exit(1) + + idl = sys.argv[1] + (_,types) = libxltypes.parse(idl) + + wrapper = sys.argv[2] + f = open(wrapper, "w") + f.write("""#ifndef __PYXL_TYPES_H +#define __PYXL_TYPES_H + +/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +""" % " ".join(sys.argv)) + for ty in types: + f.write("/* Attribute get/set functions for %s */\n"%ty.typename) + f.write(py_wrapstruct(ty)) + for a in ty.fields: + f.write(py_attrib_get(ty,a)) + f.write(py_attrib_set(ty,a)) + f.write(py_object_def(ty)) + f.write(py_initfuncs(types)) + f.write("""#endif /* __PYXL_TYPES_H */\n""") + f.close() diff -r d11a52daace3 tools/python/setup.py --- a/tools/python/setup.py Mon Sep 06 15:16:03 2010 +0100 +++ b/tools/python/setup.py Tue Sep 07 15:22:24 2010 +0100 @@ -9,14 +9,23 @@ extra_compile_args = [ "-fno-strict-ali include_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", XEN_ROOT + "/tools/include", + XEN_ROOT + "/tools/libxl", ] library_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", + XEN_ROOT + "/tools/libxl", + XEN_ROOT + "/tools/blktap2/control", ] libraries = [ "xenctrl", "xenguest", "xenstore" ] +plat = os.uname()[0] +if plat == 'Linux': + uuid_libs = ["uuid"] +else: + uuid_libs = [] + xc = Extension("xc", extra_compile_args = extra_compile_args, include_dirs = include_dirs + [ "xen/lowlevel/xc" ], @@ -83,8 +92,14 @@ netlink = Extension("netlink", sources = [ "xen/lowlevel/netlink/netlink.c", "xen/lowlevel/netlink/libnetlink.c"]) -modules = [ xc, xs, ptsname, acm, flask ] -plat = os.uname()[0] +xl = Extension("xl", + extra_compile_args = extra_compile_args, + include_dirs = include_dirs + [ "xen/lowlevel/xl" ], + library_dirs = library_dirs, + libraries = libraries + ["xenlight", "blktapctl" ] + uuid_libs, + sources = [ "xen/lowlevel/xl/xl.c" ]) + +modules = [ xc, xs, ptsname, acm, flask, xl ] if plat == 'SunOS': modules.extend([ scf, process ]) if plat == 'Linux': diff -r d11a52daace3 tools/python/xen/lowlevel/xl/xl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/lowlevel/xl/xl.c Tue Sep 07 15:22:24 2010 +0100 @@ -0,0 +1,269 @@ +/****************************************************************************** + * xl.c + * + * Copyright (c) 2010 Citrix Ltd. + * Author: Gianni Tedesco + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General Public + * License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <Python.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <arpa/inet.h> +#include <xenctrl.h> +#include <ctype.h> +#include <inttypes.h> + + +#include <libxl.h> +#include <libxl_utils.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +#define PKG "xen.lowlevel.xl" +#define CLS "ctx" + +static PyObject *xl_error_obj; + +#include "_pyxl_types.h" + +typedef struct { + PyObject_HEAD; + libxl_ctx ctx; + xentoollog_logger_stdiostream *logger; + xentoollog_level minmsglevel; +} XlObject; + +static PyObject *pyxl_list_domains(XlObject *self) +{ + libxl_dominfo *cur, *info; + PyObject *list; + int nr_dom, i; + + info = libxl_list_domain(&self->ctx, &nr_dom); + if ( NULL == info ) + return PyList_New(0); + + list = PyList_New(nr_dom); + if ( NULL == list ) + goto err_mem; + + for(i = 0, cur = info; i < nr_dom; i++, cur++) { + Py_dominfo *di; + di = (Py_dominfo *)Pydominfo_new(&Pydominfo_Type, NULL, NULL); + if ( NULL == di ) + goto err_mem; + memcpy(&di->obj, cur, sizeof(di->obj)); + PyList_SetItem(list, i, (PyObject *)di); + } + + free(info); + return list; +err_mem: + Py_DECREF(list); + PyErr_SetString(PyExc_MemoryError, "Allocating domain list"); + return NULL; +} + +static PyObject *pyxl_domid_to_name(XlObject *self, PyObject *args) +{ + char *domname; + int domid; + PyObject *ret; + + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + + domname = libxl_domid_to_name(&self->ctx, domid); + ret = PyString_FromString(domname); + free(domname); + + return ret; +} + +static PyObject *pyxl_domain_shutdown(XlObject *self, PyObject *args) +{ + int domid, req = 0; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &req) ) + return NULL; + if ( libxl_domain_shutdown(&self->ctx, domid, req) ) { + PyErr_SetString(xl_error_obj, "cannot shutdown domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_destroy(XlObject *self, PyObject *args) +{ + int domid, force = 1; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &force) ) + return NULL; + if ( libxl_domain_destroy(&self->ctx, domid, force) ) { + PyErr_SetString(xl_error_obj, "cannot destroy domain"); + return NULL; + } + return Py_None; +} + +static PyMethodDef pyxl_methods[] = { + {"list_domains", (PyCFunction)pyxl_list_domains, METH_NOARGS, + "List domains"}, + {"domid_to_name", (PyCFunction)pyxl_domid_to_name, METH_VARARGS, + "Retrieve name from domain-id"}, + {"domain_shutdown", (PyCFunction)pyxl_domain_shutdown, METH_VARARGS, + "Shutdown a domain"}, + {"domain_destroy", (PyCFunction)pyxl_domain_destroy, METH_VARARGS, + "Destroy a domain"}, + { NULL, NULL, 0, NULL } +}; + +static PyObject *PyXl_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(pyxl_methods, obj, name); +} + +static PyObject *PyXl_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + XlObject *self = (XlObject *)type->tp_alloc(type, 0); + + if (self == NULL) + return NULL; + + memset(&self->ctx, 0, sizeof(self->ctx)); + self->logger = NULL; + self->minmsglevel = XTL_PROGRESS; + + return (PyObject *)self; +} + +static int +PyXl_init(XlObject *self, PyObject *args, PyObject *kwds) +{ + self->logger = xtl_createlogger_stdiostream(stderr, self->minmsglevel, 0); + if (!self->logger) { + PyErr_SetString(xl_error_obj, "cannot init xl logger"); + return -1; + } + + if ( libxl_ctx_init(&self->ctx, LIBXL_VERSION, + (xentoollog_logger*)self->logger) ) { + PyErr_SetString(xl_error_obj, "cannot init xl context"); + return -1; + } + + return 0; +} + +static void PyXl_dealloc(XlObject *self) +{ + libxl_ctx_free(&self->ctx); + if ( self->logger ) + xtl_logger_destroy((xentoollog_logger*)self->logger); + + self->ob_type->tp_free((PyObject *)self); +} + +static PyTypeObject PyXlType = { + PyObject_HEAD_INIT(NULL) + 0, + PKG "." CLS, + sizeof(XlObject), + 0, + (destructor)PyXl_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + PyXl_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "libxenlight connection", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + pyxl_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyXl_init, /* tp_init */ + NULL, /* tp_alloc */ + PyXl_new, /* tp_new */ +}; + +static PyMethodDef xl_methods[] = { { NULL } }; + +PyMODINIT_FUNC initxl(void) +{ + PyObject *m; + + if (PyType_Ready(&PyXlType) < 0) + return; + + m = Py_InitModule(PKG, xl_methods); + + if (m == NULL) + return; + + xl_error_obj = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); + + Py_INCREF(&PyXlType); + PyModule_AddObject(m, CLS, (PyObject *)&PyXlType); + + Py_INCREF(xl_error_obj); + PyModule_AddObject(m, "Error", xl_error_obj); + + gentypes__init(m); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + */ _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |