From: Tommy Carpenter Date: Tue, 17 Mar 2020 14:32:38 +0000 (-0400) Subject: Initial QP Driver Xapp skeleton. X-Git-Tag: 1.0.1~6 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F28%2F2828%2F5;p=ric-app%2Fqp-driver.git Initial QP Driver Xapp skeleton. Issue-ID: RICAPP-47 Change-Id: Ifed1dcdc6a6ee5eaa54b978c61776055c646569e Signed-off-by: Tommy Carpenter --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d5f770 --- /dev/null +++ b/.gitignore @@ -0,0 +1,108 @@ +# misc cruft +*.log +log.txt +rmr/* +docs_and_diagrams/ + +# documentation +.tox +docs/_build/ + +# standard python ignore template +.pytest_cache/ +xunit-results.xml +.DS_Store +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +venv-tox/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + +# Test report +xunit-reports +coverage-reports diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..3797dc8 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,20 @@ +--- +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details +# Required +version: 2 + +formats: + - htmlzip + +build: + image: latest + +python: + version: 3.7 + install: + - requirements: docs/requirements-docs.txt + +sphinx: + configuration: docs/conf.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d7fd8ae --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +# ================================================================================== +# Copyright (c) 2018-2020 AT&T Intellectual Property. +# +# 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. +# ================================================================================== +FROM python:3.7-alpine + +# RMR setup +RUN mkdir -p /opt/route/ +COPY --from=nexus3.o-ran-sc.org:10004/bldr-alpine3-go:1-rmr1.13.1 /usr/local/lib64/libnng.so /usr/local/lib64/libnng.so +COPY --from=nexus3.o-ran-sc.org:10004/bldr-alpine3-go:1-rmr1.13.1 /usr/local/lib64/librmr_nng.so /usr/local/lib64/librmr_nng.so +ENV LD_LIBRARY_PATH /usr/local/lib/:/usr/local/lib64 + +# sdl needs gcc +RUN apk update && apk add gcc musl-dev bash + +# Install +COPY setup.py /tmp +COPY LICENSE.txt /tmp/ +COPY qpdriver/ /tmp/qpdriver +RUN pip install /tmp + +# Run +ENV PYTHONUNBUFFERED 1 +CMD start.py diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..69a2cef --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,29 @@ + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "Software License"); + you may not use this software except in compliance with the Software + License. You may obtain a copy of the Software License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the Software License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the Software License for the specific language governing permissions + and limitations under the Software License. + + + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the + "Documentation License"); you may not use this documentation except in + compliance with the Documentation License. You may obtain a copy of the + Documentation License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + distributed under the Documentation License is distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the Documentation License for the specific language governing + permissions and limitations under the Documentation License. diff --git a/container-tag.yaml b/container-tag.yaml new file mode 100644 index 0000000..48c5b97 --- /dev/null +++ b/container-tag.yaml @@ -0,0 +1,4 @@ +# The Jenkins job uses this string for the tag in the image name +# for example nexus3.o-ran-sc.org:10004/my-image-name:my-tag +--- +tag: 0.0.1 diff --git a/docs/_static/logo.png b/docs/_static/logo.png new file mode 100644 index 0000000..c3b6ce5 Binary files /dev/null and b/docs/_static/logo.png differ diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..974c309 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,3 @@ +from docs_conf.conf import * + +linkcheck_ignore = ["http://localhost.*", "http://127.0.0.1.*", "https://gerrit.o-ran-sc.org.*"] diff --git a/docs/conf.yaml b/docs/conf.yaml new file mode 100644 index 0000000..f3ca79a --- /dev/null +++ b/docs/conf.yaml @@ -0,0 +1,3 @@ +--- +project_cfg: oran +project: ric-app-qp-driver diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 0000000..00b0fd0 Binary files /dev/null and b/docs/favicon.ico differ diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..8fe809b --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,19 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. SPDX-License-Identifier: CC-BY-4.0 +.. Copyright (C) 2020 AT&T Intellectual Property + + +Welcome to O-RAN SC qp-driver Documentation +============================================ + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + overview.rst + release-notes.rst + installation-guide.rst + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/installation-guide.rst b/docs/installation-guide.rst new file mode 100755 index 0000000..dafaacd --- /dev/null +++ b/docs/installation-guide.rst @@ -0,0 +1,16 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. SPDX-License-Identifier: CC-BY-4.0 +.. Copyright (C) 2020 AT&T Intellectual Property + + +Installation Guide +================== + +.. contents:: + :depth: 3 + :local: + +Installation +------------ + +[to come] diff --git a/docs/overview.rst b/docs/overview.rst new file mode 100644 index 0000000..e7512d3 --- /dev/null +++ b/docs/overview.rst @@ -0,0 +1,8 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. SPDX-License-Identifier: CC-BY-4.0 +.. Copyright (C) 2020 AT&T Intellectual Property + +qp-driver Overview +================== + +[to come] diff --git a/docs/release-notes.rst b/docs/release-notes.rst new file mode 100644 index 0000000..585465d --- /dev/null +++ b/docs/release-notes.rst @@ -0,0 +1,21 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. SPDX-License-Identifier: CC-BY-4.0 +.. Copyright (C) 2020 AT&T Intellectual Property + +Release Notes +=============== + +All notable changes to this project will be documented in this file. + +The format is based on `Keep a Changelog `__ +and this project adheres to `Semantic Versioning `__. + +.. contents:: + :depth: 3 + :local: + +[0.0.1] - 3/17/2020 +------------------- +:: + + * inital skeleton creation diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt new file mode 100644 index 0000000..09a0c1c --- /dev/null +++ b/docs/requirements-docs.txt @@ -0,0 +1,5 @@ +sphinx +sphinx-rtd-theme +sphinxcontrib-httpdomain +recommonmark +lfdocs-conf diff --git a/qpdriver/__init__.py b/qpdriver/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/qpdriver/main.py b/qpdriver/main.py new file mode 100644 index 0000000..3cfe42b --- /dev/null +++ b/qpdriver/main.py @@ -0,0 +1,58 @@ +# ================================================================================== +# Copyright (c) 2020 AT&T Intellectual Property. +# +# 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. +# ================================================================================== +from ricxappframe.xapp_frame import RMRXapp + + +""" +This is only a stencil for now, will be filled in! +What is currently here was only for initial skeleton and test creation. +""" + + +def post_init(self): + self.def_hand_called = 0 + self.traffic_steering_requests = 0 + + +def default_handler(self, summary, sbuf): + self.def_hand_called += 1 + print(summary) + self.rmr_free(sbuf) + + +def steering_req_handler(self, summary, sbuf): + self.traffic_steering_requests += 1 + print(summary) + self.rmr_free(sbuf) + + +# obv some of these flags have to change +rmr_xapp = RMRXapp(default_handler, post_init=post_init, rmr_port=4562, use_fake_sdl=True) +rmr_xapp.register_callback(steering_req_handler, 60000) # no idea (yet) what the real int is here + + +def start(thread=False): + rmr_xapp.run(thread) + + +def stop(): + """can only be called if thread=True when started""" + rmr_xapp.stop() + + +def get_stats(): + # hacky for now, will evolve + return {"DefCalled": rmr_xapp.def_hand_called, "SteeringRequests": rmr_xapp.traffic_steering_requests} diff --git a/rmr-version.yaml b/rmr-version.yaml new file mode 100644 index 0000000..5808bc4 --- /dev/null +++ b/rmr-version.yaml @@ -0,0 +1,3 @@ +# CI script installs RMR from PackageCloud using this version +--- +version: 1.13.1 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..8ad0259 --- /dev/null +++ b/setup.py @@ -0,0 +1,56 @@ +# ================================================================================== +# Copyright (c) 2020 AT&T Intellectual Property. +# +# 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. +# ================================================================================== +from os.path import dirname, abspath, join as path_join +from setuptools import setup, find_packages + +SETUP_DIR = abspath(dirname(__file__)) + + +def _long_descr(): + """Yields the content of documentation files for the long description""" + try: + doc_path = path_join(SETUP_DIR, "docs/overview.rst") + with open(doc_path) as f: + return f.read() + except FileNotFoundError: # this happens during unit testing, we don't need it + return "" + + +setup( + name="qpdriver", + version="0.0.1", + packages=find_packages(exclude=["tests.*", "tests"]), + author="Tommy Carpenter", + description="QP Driver Xapp for traffic steering", + url="https://gerrit.o-ran-sc.org/r/admin/repos/ric-app/qp-driver", + install_requires=["ricxappframe>=0.4.0"], + entry_points={"console_scripts": ["start.py=qpdriver.main:start"]}, # adds a magical entrypoint for Docker + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Telecommunications Industry", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "License :: OSI Approved :: Apache Software License", + "Operating System :: POSIX :: Linux", + "Topic :: Communications", + ], + python_requires=">=3.7", + keywords="RIC xapp", + license="Apache 2.0", + data_files=[("", ["LICENSE.txt"])], + long_description=_long_descr(), + long_description_content_type="text/x-rst", +) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/test_local.rt b/tests/fixtures/test_local.rt new file mode 100644 index 0000000..2d12e18 --- /dev/null +++ b/tests/fixtures/test_local.rt @@ -0,0 +1,5 @@ +# do NOT use localhost, seems unresolved on jenkins VMs +newrt|start +mse| 60000 | -1 | 127.0.0.1:4562 +mse| 60001 | -1 | 127.0.0.1:4562 +newrt|end diff --git a/tests/test_qpd.py b/tests/test_qpd.py new file mode 100644 index 0000000..1d70821 --- /dev/null +++ b/tests/test_qpd.py @@ -0,0 +1,60 @@ +# ================================================================================== +# Copyright (c) 2020 AT&T Intellectual Property. +# +# 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. +# ================================================================================== +import json +import time +from contextlib import suppress +from qpdriver import main +from ricxappframe.xapp_frame import Xapp + +test_sender = None + + +def test_flow(): + """ + just a skeleton for now.. this will evolve when qpd evolves + """ + + # start qpd + main.start(thread=True) + + # define a test sender + def entry(self): + + val = json.dumps({"test send 60000": 1}).encode() + self.rmr_send(val, 60000) + + val = json.dumps({"test send 60001": 2}).encode() + self.rmr_send(val, 60001) + + global test_sender + test_sender = Xapp(entrypoint=entry, rmr_port=4564, use_fake_sdl=True) + test_sender.run() + + time.sleep(1) + + assert main.get_stats() == {"DefCalled": 1, "SteeringRequests": 1} + + +def teardown_module(): + """ + this is like a "finally"; the name of this function is pytest magic + safer to put down here since certain failures above can lead to pytest never returning + for example if an exception gets raised before stop is called in any test function above, pytest will hang forever + """ + with suppress(Exception): + test_sender.stop() + with suppress(Exception): + main.stop() diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..122ac82 --- /dev/null +++ b/tox.ini @@ -0,0 +1,68 @@ +# ================================================================================== +# Copyright (c) 2020 AT&T Intellectual Property. +# +# 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. +# ================================================================================== +[tox] +envlist = code,flake8,docs,docs-linkcheck +minversion = 2.0 + +[testenv:code] +basepython = python3.7 +deps= + pytest + coverage + pytest-cov +setenv = + LD_LIBRARY_PATH = /usr/local/lib/:/usr/local/lib64 + RMR_SEED_RT = tests/fixtures/test_local.rt + RMR_ASYNC_CONN = 0 + +commands = + pytest --cov qpdriver --cov-report xml --cov-report term-missing --cov-report html +# --cov-fail-under=70 + coverage xml -i + +[testenv:flake8] +basepython = python3.7 +skip_install = true +deps = flake8 +commands = flake8 setup.py qpdriver tests + +[flake8] +extend-ignore = E501,E741,E731 + +# doc jobs +[testenv:docs] +whitelist_externals = echo +skipsdist = true +basepython = python3.7 +deps = + sphinx + sphinx-rtd-theme + sphinxcontrib-httpdomain + recommonmark + lfdocs-conf +commands = + sphinx-build -W -b html -n -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/html + echo "Generated docs available in {toxinidir}/docs/_build/html" + +[testenv:docs-linkcheck] +skipsdist = true +basepython = python3.7 +deps = sphinx + sphinx-rtd-theme + sphinxcontrib-httpdomain + recommonmark + lfdocs-conf +commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/linkcheck