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>
This commit is contained in:
Ole Troan
2016-09-12 22:00:32 +02:00
committed by Damjan Marion
parent 5fef9e523d
commit 57c3d66c55
12 changed files with 139 additions and 66 deletions

View File

@ -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 @@ Requires: vpp = %{_version}-%{_release}
%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}%{_bindir}
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 @@ do
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 @@ sysctl --system
%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

View File

@ -25,42 +25,41 @@ nobase_include_HEADERS = pneum/pneum.h
#
# 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

View File

@ -150,8 +150,6 @@ pneum_disconnect (void)
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;

View File

@ -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

View File

@ -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.''',
)

View File

@ -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])

View File

@ -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:')

View File

@ -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 @@ class TestPAPI(unittest.TestCase):
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 @@ class TestPAPI(unittest.TestCase):
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)

View File

@ -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()

View File

@ -1,4 +1,3 @@
__import__('pkg_resources').declare_namespace(__name__)
from . vpp_papi import *

View File

@ -58,7 +58,7 @@ def results_event_clear(context):
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

View File

@ -20,15 +20,15 @@ from __future__ import print_function
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 @@ def msg_handler(msg):
#
# 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 @@ def msg_handler(msg):
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 @@ def connect(name):
#
# 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 @@ def plugin_name_to_id(plugin, name_to_id_table, base):
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 @@ def plugin_map_plugins():
#
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 @@ def plugin_map_plugins():
#
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.append(None)
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'])