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:
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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.''',
|
||||
)
|
||||
|
@ -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])
|
@ -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:')
|
||||
|
@ -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)
|
||||
|
35
vpp-api/python/tests/test_version.py
Executable file
35
vpp-api/python/tests/test_version.py
Executable 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()
|
@ -1,4 +1,3 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
from . vpp_papi import *
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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'])
|
||||
|
Reference in New Issue
Block a user