Python API: Preparation for RPM/DEB packaging.
Recheck.
Repackage the Python API binding to include all
necessary modules in a single Python package.
Change-Id: I5e35141d413bfb1aad650217e1ca07d85646c349
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec
index 96e6f0f..35964b6 100644
--- a/build-root/rpm/vpp.spec
+++ b/build-root/rpm/vpp.spec
@@ -6,6 +6,17 @@
%define _version %(../scripts/version rpm-version)
%define _release %(../scripts/version rpm-release)
+# Failsafe backport of Python2-macros for RHEL <= 6
+%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
+%{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
+%{!?python_version: %global python_version %(%{__python} -c "import sys; sys.stdout.write(sys.version[:3])")}
+%{!?__python2: %global __python2 %{__python}}
+%{!?python2_sitelib: %global python2_sitelib %{python_sitelib}}
+%{!?python2_sitearch: %global python2_sitearch %{python_sitearch}}
+%{!?python2_version: %global python2_version %{python_version}}
+
+%{!?python2_minor_version: %define python2_minor_version %(%{__python} -c "import sys ; print sys.version[2:3]")}
+
Name: vpp
Summary: Vector Packet Processing
License: MIT
@@ -56,6 +67,14 @@
%description plugins
This package contains VPP plugins
+%package python-api
+Summary: VPP api python bindings
+Group: Development/Libraries
+Requires: vpp = %{_version}-%{_release}, vpp-lib = %{_version}-%{_release}, devel = %{_version}-%{_release}
+
+%description python-api
+This package contains the python bindings for the vpp api
+
%pre
# Add the vpp group
groupadd -f -r vpp
@@ -68,6 +87,7 @@
mkdir -p -m755 %{buildroot}%{_unitdir}
install -p -m 755 %{_vpp_install_dir}/*/bin/* %{buildroot}%{_bindir}
install -p -m 755 %{_vpp_build_dir}/vppapigen/vppapigen %{buildroot}%{_bindir}
+install -p -m 755 ../../vppapigen/pyvppapigen.py %{buildroot}%{_bindir}
#
# configs
#
@@ -93,6 +113,13 @@
ln -fs $file $(echo $file | sed -e 's/\(\.so\)\.[0-9]\+.*/\1/') )
done
+# Python bindings
+mkdir -p -m755 %{buildroot}%{python2_sitelib}/vpp_papi
+for file in $(find %{_vpp_install_dir}/*/lib/python2.7/site-packages/ -type f -print | grep -v pyc | grep -v pyo)
+do
+ install -p -m 666 $file %{buildroot}%{python2_sitelib}/vpp_papi/
+done
+
#
# devel
#
@@ -162,10 +189,15 @@
%exclude %{_libdir}/vpp_api_test_plugins
%{_libdir}/*
+%files python-api
+%defattr(644,root,root)
+%{python2_sitelib}/vpp_papi/*
+
%files devel
%defattr(-,bin,bin)
/usr/bin/vppapigen
/usr/bin/jvpp_gen.py
+/usr/bin/pyvppapigen.py
%{_includedir}/*
%{python2_sitelib}/jvppgen/*
/usr/share/doc/vpp/examples/sample-plugin
diff --git a/vpp-api/python/Makefile.am b/vpp-api/python/Makefile.am
index eb58933..59b1b92 100644
--- a/vpp-api/python/Makefile.am
+++ b/vpp-api/python/Makefile.am
@@ -25,42 +25,41 @@
#
# Python / C extension
#
-lib_LTLIBRARIES += vpp_api.la
-vpp_api_la_SOURCES = pneum/pneum.c vpp_papi/pneum_wrap.c
-vpp_api_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt
-vpp_api_la_LDFLAGS = -module $(shell python-config --ldflags)
-vpp_api_la_CPPFLAGS = $(shell python-config --includes)
-
-# Kept around for setuptools based install.
lib_LTLIBRARIES += libpneum.la
-libpneum_la_SOURCES = pneum/pneum.c setup.py
-libpneum_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt
+libpneum_la_SOURCES = pneum/pneum.c
+libpneum_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread \
+ -lm -lrt
libpneum_la_LDFLAGS = -module
libpneum_la_CPPFLAGS =
#
# Core VPP API
#
-BUILT_SOURCES += \
- $(prefix)/../vpp/vpp-api/vpe.py \
- $(prefix)/../vlib-api/vlibmemory/memclnt.py
-
-%.py: %.api
+$(srcdir)/vpp_papi/vpe.py: $(prefix)/../vpp/vpp-api/vpe.api
$(info Creating Python binding for $@)
$(CC) $(CPPFLAGS) -E -P -C -x c $< \
| vppapigen --input - --python - \
- | pyvppapigen.py --input - > $@
+ | pyvppapigen.py --input - > $(srcdir)/vpp_papi/$(notdir $@)
-#
+$(srcdir)/vpp_papi/memclnt.py: $(prefix)/../vlib-api/vlibmemory/memclnt.api
+ $(info Creating Python binding for $@)
+ $(CC) $(CPPFLAGS) -E -P -C -x c $< \
+ | vppapigen --input - --python - \
+ | pyvppapigen.py --input - > $(srcdir)/vpp_papi/$(notdir $@)
+
# TODO: Support both Python 2 and 3.
-install-exec-local:
- cd $(srcdir); \
- mkdir -p $(prefix)/lib/python2.7/site-packages; \
- PYTHONUSERBASE=$(prefix) python setup.py install --user
+install-exec-local: $(srcdir)/vpp_papi/vpe.py $(srcdir)/vpp_papi/memclnt.py
+ cd $(srcdir); \
+ mkdir -p $(prefix)/lib/python2.7/site-packages; \
+ PYTHONUSERBASE=$(prefix) \
+ python setup.py build_ext -L $(prefix)/lib64 install --user
#
# Test client
#
noinst_PROGRAMS += test_pneum
test_pneum_SOURCES = pneum/pneum.c pneum/test_pneum.c
-test_pneum_LDADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt
+test_pneum_LDADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread \
+ -lm -lrt
+
+
diff --git a/vpp-api/python/pneum/pneum.c b/vpp-api/python/pneum/pneum.c
index 2637d43..7250cf6 100644
--- a/vpp-api/python/pneum/pneum.c
+++ b/vpp-api/python/pneum/pneum.c
@@ -150,8 +150,6 @@
api_main_t *am = &api_main;
pneum_main_t *pm = &pneum_main;
- fformat (stdout,"disconnecting from vpe \n");
-
if (pm->rx_thread_jmpbuf_valid) {
vl_api_rx_thread_exit_t *ep;
uword junk;
diff --git a/vpp-api/python/setup.cfg b/vpp-api/python/setup.cfg
index 5e19e8c..d645be7 100644
--- a/vpp-api/python/setup.cfg
+++ b/vpp-api/python/setup.cfg
@@ -3,5 +3,3 @@
# 3. If at all possible, it is good practice to do this. If you cannot, you
# will need to generate wheels for each Python version that you support.
universal=0
-
-
diff --git a/vpp-api/python/setup.py b/vpp-api/python/setup.py
index e369a0c..a2eeff3 100644
--- a/vpp-api/python/setup.py
+++ b/vpp-api/python/setup.py
@@ -1,16 +1,34 @@
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
try:
- from setuptools import setup
+ from setuptools import setup, command, Extension
except ImportError:
from distutils.core import setup
setup (name = 'vpp_papi',
- version = '1.1',
+ version = '1.2',
description = 'VPP Python binding',
author = 'Ole Troan',
author_email = 'ot@cisco.com',
- #url = 'https://docs.python.org/extending/building',
test_suite = 'tests',
packages=['vpp_papi'],
- long_description = '''
-VPP Python language binding.
-''',)
+ ext_modules = [
+ Extension(
+ 'vpp_api',
+ sources = ['vpp_papi/pneum_wrap.c'],
+ libraries = ['pneum'],
+ )],
+ long_description = '''VPP Python language binding.''',
+)
diff --git a/vpp-api/python/tests/test_base.py b/vpp-api/python/tests/test_base.py
deleted file mode 100644
index 8ff5dd4..0000000
--- a/vpp-api/python/tests/test_base.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Manipulate sys.path to allow tests be run inside the build environment.
-import os, sys, glob
-scriptdir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vpp-api/lib64/vpp_api.so')[0]))
-sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vlib-api/vlibmemory/memclnt.py')[0]))
-sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vpp/vpp-api/vpe.py')[0]))
-sys.path.append(glob.glob(scriptdir+'/../../../build-root/install*/plugins/vpp_papi_plugins')[0])
diff --git a/vpp-api/python/tests/test_modules.py b/vpp-api/python/tests/test_modules.py
index 48df175..fdcd092 100755
--- a/vpp-api/python/tests/test_modules.py
+++ b/vpp-api/python/tests/test_modules.py
@@ -1,7 +1,5 @@
-#!/usr/bin/env python
from __future__ import print_function
import unittest
-import test_base
import vpp_papi
import pot, snat
print('Plugins:')
diff --git a/vpp-api/python/tests/test_papi.py b/vpp-api/python/tests/test_papi.py
index ab90eea..8cbbfc5 100755
--- a/vpp-api/python/tests/test_papi.py
+++ b/vpp-api/python/tests/test_papi.py
@@ -1,13 +1,10 @@
-#!/usr/bin/env python
-
from __future__ import print_function
-import unittest, sys, time, threading, struct, logging
-import test_base
+import unittest, sys, time, threading, struct, logging, os
import vpp_papi
from ipaddress import *
-
+scriptdir = os.path.dirname(os.path.realpath(__file__))
papi_event = threading.Event()
-print(vpp_papi.VL_API_SW_INTERFACE_SET_FLAGS)
+print(vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS)
def papi_event_handler(result):
if result.vl_msg_id == vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS:
return
@@ -27,7 +24,7 @@
def setUpClass(cls):
#
# Start main VPP process
- cls.vpp_bin = glob.glob(test_base.scriptdir+'/../../../build-root/install-vpp*-native/vpp/bin/vpp')[0]
+ cls.vpp_bin = glob.glob(scriptdir+'/../../../build-root/install-vpp*-native/vpp/bin/vpp')[0]
print("VPP BIN:", cls.vpp_bin)
cls.vpp = subprocess.Popen([cls.vpp_bin, "unix", "nodaemon"], stderr=subprocess.PIPE)
print('Started VPP')
@@ -89,7 +86,7 @@
self.assertEqual(t.retval, 0)
ifindex = t.sw_if_index
- addr = str(IPv6Address('1::1').packed)
+ addr = str(IPv6Address(u'1::1').packed)
t = vpp_papi.sw_interface_add_del_address(ifindex, 1, 1, 0, 16, addr)
print(t)
self.assertEqual(t.retval, 0)
diff --git a/vpp-api/python/tests/test_version.py b/vpp-api/python/tests/test_version.py
new file mode 100755
index 0000000..de39cc2
--- /dev/null
+++ b/vpp-api/python/tests/test_version.py
@@ -0,0 +1,35 @@
+from __future__ import print_function
+import unittest, sys, time, threading, struct
+
+import vpp_papi
+from ipaddress import *
+import glob, subprocess
+class TestPAPI(unittest.TestCase):
+ def setUp(self):
+ print("Connecting API")
+ r = vpp_papi.connect("test_papi")
+ self.assertEqual(r, 0)
+
+ def tearDown(self):
+ r = vpp_papi.disconnect()
+ self.assertEqual(r, 0)
+
+ #
+ # The tests themselves
+ #
+
+ #
+ # Basic request / reply
+ #
+ def test_show_version(self):
+ print(vpp_papi.show_version())
+
+ #
+ # Details / Dump
+ #
+ def test_details_dump(self):
+ t = vpp_papi.sw_interface_dump(0, b'')
+ print('Dump/details T', t)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/vpp-api/python/vpp_papi/__init__.py b/vpp-api/python/vpp_papi/__init__.py
index 19d78a3..6688ffb 100644
--- a/vpp-api/python/vpp_papi/__init__.py
+++ b/vpp-api/python/vpp_papi/__init__.py
@@ -1,4 +1,3 @@
__import__('pkg_resources').declare_namespace(__name__)
from . vpp_papi import *
-
diff --git a/vpp-api/python/vpp_papi/vpp_api_base.py b/vpp-api/python/vpp_papi/vpp_api_base.py
index a1ef87a..227257f 100644
--- a/vpp-api/python/vpp_papi/vpp_api_base.py
+++ b/vpp-api/python/vpp_papi/vpp_api_base.py
@@ -58,7 +58,7 @@
results[context]['e'].clear()
def results_event_wait(context, timeout):
- results[context]['e'].wait(timeout)
+ return (results[context]['e'].wait(timeout))
def results_set(context, r):
results[context]['r'] = r
diff --git a/vpp-api/python/vpp_papi/vpp_papi.py b/vpp-api/python/vpp_papi/vpp_papi.py
index 174e61d..42ddcdc 100644
--- a/vpp-api/python/vpp_papi/vpp_papi.py
+++ b/vpp-api/python/vpp_papi/vpp_papi.py
@@ -20,15 +20,15 @@
import signal, os, sys
from struct import *
-scriptdir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(scriptdir)
import vpp_api
from vpp_api_base import *
# Import API definitions. The core VPE API is imported into main namespace
import memclnt
+
+# Cheating a bit, importing it into this namespace as well as a module.
+import vpe
from vpe import *
-vpe = sys.modules['vpe']
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
@@ -67,7 +67,7 @@
#
# Collect results until control ping
#
- if id[0] == vpe.VL_API_CONTROL_PING_REPLY:
+ if id[0] == VL_API_CONTROL_PING_REPLY:
results_event_set(context)
waiting_for_reply_clear()
return
@@ -82,7 +82,14 @@
results_event_set(context)
waiting_for_reply_clear()
+def handler(signum, frame):
+ print('Signal handler called with signal', signum)
+ raise IOError("Couldn't connect to VPP!")
+
def connect(name):
+ # Set the signal handler
+ signal.signal(signal.SIGALRM, handler)
+
signal.alarm(3) # 3 second
rv = vpp_api.connect(name, msg_handler)
signal.alarm(0)
@@ -90,20 +97,16 @@
#
# Assign message id space for plugins
#
- plugin_map_plugins()
-
+ try:
+ plugin_map_plugins()
+ except:
+ return -1
return rv
def disconnect():
rv = vpp_api.disconnect()
return rv
-# CLI convenience wrapper
-def cli_exec(cmd):
- cmd += '\n'
- r = cli_inband(len(cmd), cmd)
- return r.reply[0].decode().rstrip('\x00')
-
def register_event_callback(callback):
event_callback_set(callback)
@@ -112,6 +115,7 @@
m = globals()[plugin]
except KeyError:
m = sys.modules[plugin]
+
for name in name_to_id_table:
setattr(m, name, name_to_id_table[name] + base)
@@ -126,11 +130,10 @@
#
version = plugins[p]['version']
name = p + '_' + format(version, '08x')
- r = memclnt.get_first_msg_id(name.encode('ascii'))
- ## TODO: Add error handling / raise exception
+ r = memclnt.get_first_msg_id(name)
if r.retval != 0:
- eprint('Failed getting first msg id for:', p)
- continue
+ eprint('Failed getting first msg id for:', p, r, name)
+ raise
# Set base
base = r.first_msg_id
@@ -153,6 +156,8 @@
#
memclnt.msg_id_base_set(1)
plugins['memclnt']['base'] = 1
+
+# vpe
msg_id_base_set(len(plugins['memclnt']['func_table']) + 1)
plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1
api_func_table = []
@@ -160,3 +165,4 @@
api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table']
plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1)
plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base'])
+plugin_name_to_id(__name__, plugins['vpe']['name_to_id_table'], plugins['vpe']['base'])