Hello, Attached is a simple port of SPOA with embedded Python 2 interpreter to Python 3 following the official Python porting documentation. I tried to keep the changes at minimum. Tested on my local Debian with Python v3.7 using the provided example script.
Regards, Vedran
>From 91333957473bf47326bb11fafd38356c2c183773 Mon Sep 17 00:00:00 2001 From: Vedran Furac <vedr...@haproxy.com> Date: Fri, 19 Jul 2019 15:18:56 +0200 Subject: [PATCH] MINOR: contrib/spoa_server: Port SPOA server to Python 3 Python 2 will be EOL in 2020. This patch ports SPOA server with embedded interpreter to Python 3 --- contrib/spoa_server/Makefile | 6 +- contrib/spoa_server/ps_python.c | 123 ++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/contrib/spoa_server/Makefile b/contrib/spoa_server/Makefile index f0752829..70ccf988 100644 --- a/contrib/spoa_server/Makefile +++ b/contrib/spoa_server/Makefile @@ -23,12 +23,12 @@ endif ifneq ($(USE_PYTHON),) OBJS += ps_python.o -CFLAGS += -I/usr/include/python2.7 -LDLIBS += -lpython2.7 +CFLAGS += $(shell python3-config --cflags) -Wno-sign-compare -fPIC +LDFLAGS += $(shell python3-config --ldflags) endif spoa: $(OBJS) - $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) + $(LD) $(LDFLAGS) -o $@ $^ install: spoa install spoa $(DESTDIR)$(BINDIR) diff --git a/contrib/spoa_server/ps_python.c b/contrib/spoa_server/ps_python.c index 0a9fbffc..654bebdf 100644 --- a/contrib/spoa_server/ps_python.c +++ b/contrib/spoa_server/ps_python.c @@ -36,6 +36,10 @@ static int ps_python_start_worker(struct worker *w); static int ps_python_load_file(struct worker *w, const char *file); static int ps_python_exec_message(struct worker *w, void *ref, int nargs, struct spoe_kv *args); +struct module_state { + PyObject *error; +}; + static struct ps ps_python_bindings = { .init_worker = ps_python_start_worker, .load_file = ps_python_load_file, @@ -171,11 +175,11 @@ static PyObject *ps_python_set_var_ipv4(PyObject *self, PyObject *args) value = PyObject_GetAttrString(ipv4, "packed"); if (value == NULL) return NULL; - if (PyString_GET_SIZE(value) != sizeof(ip)) { - PyErr_Format(spoa_error, "UPv6 manipulation internal error"); + if (PyBytes_Size(value) != sizeof(ip)) { + PyErr_Format(spoa_error, "IPv4 manipulation internal error"); return NULL; } - memcpy(&ip, PyString_AS_STRING(value), PyString_GET_SIZE(value)); + memcpy(&ip, PyBytes_AsString(value), PyBytes_Size(value)); if (!set_var_ipv4(worker, name, name_len, scope, &ip)) { PyErr_SetString(spoa_error, "No space left available"); return NULL; @@ -202,11 +206,11 @@ static PyObject *ps_python_set_var_ipv6(PyObject *self, PyObject *args) value = PyObject_GetAttrString(ipv6, "packed"); if (value == NULL) return NULL; - if (PyString_GET_SIZE(value) != sizeof(ip)) { - PyErr_Format(spoa_error, "UPv6 manipulation internal error"); + if (PyBytes_Size(value) != sizeof(ip)) { + PyErr_Format(spoa_error, "IPv6 manipulation internal error"); return NULL; } - memcpy(&ip, PyString_AS_STRING(value), PyString_GET_SIZE(value)); + memcpy(&ip, PyBytes_AsString(value), PyBytes_Size(value)); if (!set_var_ipv6(worker, name, name_len, scope, &ip)) { PyErr_SetString(spoa_error, "No space left available"); return NULL; @@ -272,55 +276,31 @@ static PyMethodDef spoa_methods[] = { "Set SPOA str variable"}, {"set_var_bin", ps_python_set_var_bin, METH_VARARGS, "Set SPOA bin variable"}, - { /* end */ } + {NULL, NULL} }; -static int ps_python_start_worker(struct worker *w) +static struct PyModuleDef spoa_module = { + PyModuleDef_HEAD_INIT, + "spoa", + NULL, + sizeof(struct module_state), + spoa_methods, + NULL, + NULL, + NULL, + NULL +}; + +static PyObject *PyInit_spoa(void) { - PyObject *m; - PyObject *module_name; - PyObject *value; int ret; - - Py_SetProgramName("spoa-server"); - Py_Initialize(); - - module_name = PyString_FromString("ipaddress"); - if (module_name == NULL) { - PyErr_Print(); - return 0; - } - - module_ipaddress = PyImport_Import(module_name); - Py_DECREF(module_name); - if (module_ipaddress == NULL) { - PyErr_Print(); - return 0; - } - - ipv4_address = PyObject_GetAttrString(module_ipaddress, "IPv4Address"); - if (ipv4_address == NULL) { - PyErr_Print(); - return 0; - } - - ipv6_address = PyObject_GetAttrString(module_ipaddress, "IPv6Address"); - if (ipv4_address == NULL) { - PyErr_Print(); - return 0; - } - - m = Py_InitModule("spoa", spoa_methods); - if (m == NULL) { - PyErr_Print(); - return 0; - } + PyObject *value; + PyObject *m = PyModule_Create(&spoa_module); spoa_error = PyErr_NewException("spoa.error", NULL, NULL); Py_INCREF(spoa_error); PyModule_AddObject(m, "error", spoa_error); - value = PyLong_FromLong(SPOE_SCOPE_PROC); if (value == NULL) { PyErr_Print(); @@ -387,6 +367,43 @@ static int ps_python_start_worker(struct worker *w) return 0; } + return m; +} + +static int ps_python_start_worker(struct worker *w) +{ + PyObject *module_name; + + Py_SetProgramName(Py_DecodeLocale("spoa-server", NULL)); + + PyImport_AppendInittab("spoa", &PyInit_spoa); + Py_Initialize(); + + module_name = PyUnicode_FromString("ipaddress"); + if (module_name == NULL) { + PyErr_Print(); + return 0; + } + + module_ipaddress = PyImport_Import(module_name); + Py_DECREF(module_name); + if (module_ipaddress == NULL) { + PyErr_Print(); + return 0; + } + + ipv4_address = PyObject_GetAttrString(module_ipaddress, "IPv4Address"); + if (ipv4_address == NULL) { + PyErr_Print(); + return 0; + } + + ipv6_address = PyObject_GetAttrString(module_ipaddress, "IPv6Address"); + if (ipv4_address == NULL) { + PyErr_Print(); + return 0; + } + worker = w; return 1; } @@ -452,14 +469,14 @@ static int ps_python_exec_message(struct worker *w, void *ref, int nargs, struct /* Create the name entry */ - key = PyString_FromString("name"); + key = PyUnicode_FromString("name"); if (key == NULL) { Py_DECREF(kw_args); PyErr_Print(); return 0; } - value = PyString_FromStringAndSize(args[i].name.str, args[i].name.len); + value = PyUnicode_FromStringAndSize(args[i].name.str, args[i].name.len); if (value == NULL) { Py_DECREF(kw_args); Py_DECREF(ent); @@ -480,7 +497,7 @@ static int ps_python_exec_message(struct worker *w, void *ref, int nargs, struct /* Create th value entry */ - key = PyString_FromString("value"); + key = PyUnicode_FromString("value"); if (key == NULL) { Py_DECREF(kw_args); Py_DECREF(ent); @@ -531,7 +548,7 @@ static int ps_python_exec_message(struct worker *w, void *ref, int nargs, struct PyErr_Print(); return 0; } - ip_name = PyString_FromString("address"); + ip_name = PyUnicode_FromString("address"); if (ip_name == NULL) { Py_DECREF(kw_args); Py_DECREF(ent); @@ -564,10 +581,10 @@ static int ps_python_exec_message(struct worker *w, void *ref, int nargs, struct break; case SPOE_DATA_T_STR: - value = PyString_FromStringAndSize(args[i].value.u.buffer.str, args[i].value.u.buffer.len); + value = PyUnicode_FromStringAndSize(args[i].value.u.buffer.str, args[i].value.u.buffer.len); break; case SPOE_DATA_T_BIN: - value = PyString_FromStringAndSize(args[i].value.u.buffer.str, args[i].value.u.buffer.len); + value = PyUnicode_FromStringAndSize(args[i].value.u.buffer.str, args[i].value.u.buffer.len); break; default: value = Py_None; @@ -611,7 +628,7 @@ static int ps_python_exec_message(struct worker *w, void *ref, int nargs, struct return 0; } - key = PyString_FromString("args"); + key = PyUnicode_FromString("args"); if (key == NULL) { Py_DECREF(kw_args); Py_DECREF(fkw); -- 2.20.1