From 45f8f98f0e344cc253d709df23bf27311adff0bb Mon Sep 17 00:00:00 2001 From: Tommy Carpenter Date: Fri, 6 Mar 2020 09:41:57 -0500 Subject: [PATCH 1/1] Remove SDLWrapper now that it's in xapp frame. Issue-ID: RIC-228 Change-Id: I1f65d1b5a0029eb544d43c2c9294ef19c07d45d9 Signed-off-by: Tommy Carpenter --- a1/data.py | 92 +++++++++------------------------ container-tag.yaml | 2 +- docs/developer-guide.rst | 4 +- docs/release-notes.rst | 7 +++ integration_tests/a1mediator/Chart.yaml | 2 +- setup.py | 4 +- tests/test_controller.py | 7 +-- tests/test_data.py | 54 ------------------- 8 files changed, 42 insertions(+), 130 deletions(-) delete mode 100644 tests/test_data.py diff --git a/a1/data.py b/a1/data.py index d537d54..45fe5de 100644 --- a/a1/data.py +++ b/a1/data.py @@ -20,67 +20,24 @@ Represents A1s database and database access functions. import os import time from threading import Thread -import msgpack from mdclogpy import Logger -from ricsdl.syncstorage import SyncStorage +from ricxappframe.xapp_sdl import SDLWrapper from a1.exceptions import PolicyTypeNotFound, PolicyInstanceNotFound, PolicyTypeAlreadyExists, CantDeleteNonEmptyType -mdc_logger = Logger(name=__name__) - +# constants INSTANCE_DELETE_NO_RESP_TTL = int(os.environ.get("INSTANCE_DELETE_NO_RESP_TTL", 5)) INSTANCE_DELETE_RESP_TTL = int(os.environ.get("INSTANCE_DELETE_RESP_TTL", 5)) - A1NS = "A1m_ns" - - -class SDLWrapper: - """ - This is a wrapper around the expected SDL Python interface. - The usage of POLICY_DATA will be replaced with SDL when SDL for python is available. - The eventual SDL API is expected to be very close to what is here. - - We use msgpack for binary (de)serialization: https://msgpack.org/index.html - """ - - def __init__(self): - self.sdl = SyncStorage() - - def set(self, key, value): - """set a key""" - self.sdl.set(A1NS, {key: msgpack.packb(value, use_bin_type=True)}) - - def get(self, key): - """get a key""" - ret_dict = self.sdl.get(A1NS, {key}) - if key in ret_dict: - return msgpack.unpackb(ret_dict[key], raw=False) - - return None - - def find_and_get(self, prefix): - """get all k v pairs that start with prefix""" - # note: SDL "*" usage is inconsistent with real python regex, where it would be ".*" - ret_dict = self.sdl.find_and_get(A1NS, "{0}*".format(prefix)) - return {k: msgpack.unpackb(v, raw=False) for k, v in ret_dict.items()} - - def delete(self, key): - """ delete a key""" - self.sdl.remove(A1NS, {key}) - - def healthcheck(self): - """checks if the sdl connection is healthy""" - return self.sdl.is_active() - - -SDL = SDLWrapper() - TYPE_PREFIX = "a1.policy_type." INSTANCE_PREFIX = "a1.policy_instance." METADATA_PREFIX = "a1.policy_inst_metadata." HANDLER_PREFIX = "a1.policy_handler." +mdc_logger = Logger(name=__name__) +SDL = SDLWrapper() + # Internal helpers @@ -123,7 +80,7 @@ def _type_is_valid(policy_type_id): """ check that a type is valid """ - if SDL.get(_generate_type_key(policy_type_id)) is None: + if SDL.get(A1NS, _generate_type_key(policy_type_id)) is None: raise PolicyTypeNotFound() @@ -132,7 +89,7 @@ def _instance_is_valid(policy_type_id, policy_instance_id): check that an instance is valid """ _type_is_valid(policy_type_id) - if SDL.get(_generate_instance_key(policy_type_id, policy_instance_id)) is None: + if SDL.get(A1NS, _generate_instance_key(policy_type_id, policy_instance_id)) is None: raise PolicyInstanceNotFound @@ -142,7 +99,7 @@ def _get_statuses(policy_type_id, policy_instance_id): """ _instance_is_valid(policy_type_id, policy_instance_id) prefixes_for_handler = "{0}{1}.{2}.".format(HANDLER_PREFIX, policy_type_id, policy_instance_id) - return list(SDL.find_and_get(prefixes_for_handler).values()) + return list(SDL.find_and_get(A1NS, prefixes_for_handler).values()) def _get_instance_list(policy_type_id): @@ -151,7 +108,7 @@ def _get_instance_list(policy_type_id): """ _type_is_valid(policy_type_id) prefixes_for_type = "{0}{1}.".format(INSTANCE_PREFIX, policy_type_id) - instancekeys = SDL.find_and_get(prefixes_for_type).keys() + instancekeys = SDL.find_and_get(A1NS, prefixes_for_type).keys() return [k.split(prefixes_for_type)[1] for k in instancekeys] @@ -160,9 +117,9 @@ def _clear_handlers(policy_type_id, policy_instance_id): delete all the handlers for a policy instance """ all_handlers_pref = _generate_handler_prefix(policy_type_id, policy_instance_id) - keys = SDL.find_and_get(all_handlers_pref) + keys = SDL.find_and_get(A1NS, all_handlers_pref) for k in keys: - SDL.delete(k) + SDL.delete(A1NS, k) def _get_metadata(policy_type_id, policy_instance_id): @@ -171,7 +128,7 @@ def _get_metadata(policy_type_id, policy_instance_id): """ _instance_is_valid(policy_type_id, policy_instance_id) metadata_key = _generate_instance_metadata_key(policy_type_id, policy_instance_id) - return SDL.get(metadata_key) + return SDL.get(A1NS, metadata_key) def _delete_after(policy_type_id, policy_instance_id, ttl): @@ -185,8 +142,8 @@ def _delete_after(policy_type_id, policy_instance_id, ttl): # ready to delete _clear_handlers(policy_type_id, policy_instance_id) # delete all the handlers - SDL.delete(_generate_instance_key(policy_type_id, policy_instance_id)) # delete instance - SDL.delete(_generate_instance_metadata_key(policy_type_id, policy_instance_id)) # delete instance metadata + SDL.delete(A1NS, _generate_instance_key(policy_type_id, policy_instance_id)) # delete instance + SDL.delete(A1NS, _generate_instance_metadata_key(policy_type_id, policy_instance_id)) # delete instance metadata mdc_logger.debug("type {0} instance {1} deleted".format(policy_type_id, policy_instance_id)) @@ -197,7 +154,7 @@ def get_type_list(): """ retrieve all type ids """ - typekeys = SDL.find_and_get(TYPE_PREFIX).keys() + typekeys = SDL.find_and_get(A1NS, TYPE_PREFIX).keys() # policy types are ints but they get butchered to strings in the KV return [int(k.split(TYPE_PREFIX)[1]) for k in typekeys] @@ -207,9 +164,9 @@ def store_policy_type(policy_type_id, body): store a policy type if it doesn't already exist """ key = _generate_type_key(policy_type_id) - if SDL.get(key) is not None: + if SDL.get(A1NS, key) is not None: raise PolicyTypeAlreadyExists() - SDL.set(key, body) + SDL.set(A1NS, key, body) def delete_policy_type(policy_type_id): @@ -218,7 +175,7 @@ def delete_policy_type(policy_type_id): """ pil = get_instance_list(policy_type_id) if pil == []: # empty, can delete - SDL.delete(_generate_type_key(policy_type_id)) + SDL.delete(A1NS, _generate_type_key(policy_type_id)) else: raise CantDeleteNonEmptyType() @@ -228,7 +185,7 @@ def get_policy_type(policy_type_id): retrieve a type """ _type_is_valid(policy_type_id) - return SDL.get(_generate_type_key(policy_type_id)) + return SDL.get(A1NS, _generate_type_key(policy_type_id)) # Instances @@ -243,13 +200,13 @@ def store_policy_instance(policy_type_id, policy_instance_id, instance): # store the instance key = _generate_instance_key(policy_type_id, policy_instance_id) - if SDL.get(key) is not None: + if SDL.get(A1NS, key) is not None: # Reset the statuses because this is a new policy instance, even if it was overwritten _clear_handlers(policy_type_id, policy_instance_id) # delete all the handlers - SDL.set(key, instance) + SDL.set(A1NS, key, instance) metadata_key = _generate_instance_metadata_key(policy_type_id, policy_instance_id) - SDL.set(metadata_key, {"created_at": creation_timestamp, "has_been_deleted": False}) + SDL.set(A1NS, metadata_key, {"created_at": creation_timestamp, "has_been_deleted": False}) def get_policy_instance(policy_type_id, policy_instance_id): @@ -257,7 +214,7 @@ def get_policy_instance(policy_type_id, policy_instance_id): Retrieve a policy instance """ _instance_is_valid(policy_type_id, policy_instance_id) - return SDL.get(_generate_instance_key(policy_type_id, policy_instance_id)) + return SDL.get(A1NS, _generate_instance_key(policy_type_id, policy_instance_id)) def get_instance_list(policy_type_id): @@ -279,6 +236,7 @@ def delete_policy_instance(policy_type_id, policy_instance_id): metadata_key = _generate_instance_metadata_key(policy_type_id, policy_instance_id) existing_metadata = _get_metadata(policy_type_id, policy_instance_id) SDL.set( + A1NS, metadata_key, {"created_at": existing_metadata["created_at"], "has_been_deleted": True, "deleted_at": deleted_timestamp}, ) @@ -306,7 +264,7 @@ def set_policy_instance_status(policy_type_id, policy_instance_id, handler_id, s """ _type_is_valid(policy_type_id) _instance_is_valid(policy_type_id, policy_instance_id) - SDL.set(_generate_handler_key(policy_type_id, policy_instance_id, handler_id), status) + SDL.set(A1NS, _generate_handler_key(policy_type_id, policy_instance_id, handler_id), status) def get_policy_instance_status(policy_type_id, policy_instance_id): diff --git a/container-tag.yaml b/container-tag.yaml index 65db8b3..2507613 100644 --- a/container-tag.yaml +++ b/container-tag.yaml @@ -1,4 +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: 2.1.3 +tag: 2.1.4 diff --git a/docs/developer-guide.rst b/docs/developer-guide.rst index b37b2c4..3e11e19 100644 --- a/docs/developer-guide.rst +++ b/docs/developer-guide.rst @@ -29,9 +29,9 @@ This project follows semver. When changes are made, the versions are in: 4) ``integration_tests/a1mediator/Chart.yaml`` -6) ``a1/openapi.yaml`` (this is an API version, not a software version; no need to bump on patch changes) +5) ``a1/openapi.yaml`` (this is an API version, not a software version; no need to bump on patch changes) -7) in the it/dep repo that contains a1 helm chart, ``values.yaml``, ``Chart.yml`` +6) in the ric-plt repo that contains a1 helm chart, ``values.yaml``, ``Chart.yml`` Version bumping rmr diff --git a/docs/release-notes.rst b/docs/release-notes.rst index e39ec3a..0ca68d5 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -14,6 +14,13 @@ and this project adheres to `Semantic Versioning `__. :depth: 3 :local: +[2.1.4] - 3/6/2020 +------------------- +:: + + * SDL Wrapper was moved into the python xapp framework; use it from there instead. + + [2.1.3] - 2/13/2020 ------------------- :: diff --git a/integration_tests/a1mediator/Chart.yaml b/integration_tests/a1mediator/Chart.yaml index 3072609..bc20e74 100644 --- a/integration_tests/a1mediator/Chart.yaml +++ b/integration_tests/a1mediator/Chart.yaml @@ -1,4 +1,4 @@ apiVersion: v1 description: A1 Helm chart for Kubernetes name: a1mediator -version: 2.1.3 +version: 2.1.4 diff --git a/setup.py b/setup.py index db13d40..87ba3ab 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ from setuptools import setup, find_packages setup( name="a1", - version="2.1.3", + version="2.1.4", packages=find_packages(exclude=["tests.*", "tests"]), author="Tommy Carpenter", description="RIC A1 Mediator for policy/intent changes", @@ -30,9 +30,9 @@ setup( "Flask", "connexion[swagger-ui]", "gevent", - "msgpack", "rmr>=2.2.0", "mdclogpy", + "ricxappframe>=0.2.0", "ricsdl>=2.0.3,<3.0.0", ], package_data={"a1": ["openapi.yaml"]}, diff --git a/tests/test_controller.py b/tests/test_controller.py index bbfe996..0601bbc 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -20,7 +20,7 @@ tests for controller import time import json from rmr.rmr_mocks import rmr_mocks -from ricsdl.syncstorage import SyncStorage +from ricxappframe.xapp_sdl import SDLWrapper from ricsdl.exceptions import RejectedByBackend, NotConnected, BackendError from a1 import a1rmr, data @@ -232,7 +232,8 @@ def _verify_instance_and_status(client, expected_instance, expected_status, expe def setup_module(): """module level setup""" - data.SDL.sdl = SyncStorage(fake_db_backend="dict") + # swap sdl for the fake backend + data.SDL = SDLWrapper(use_fake_sdl=True) def noop(): pass @@ -351,7 +352,7 @@ def test_bad_instances(client, monkeypatch, adm_type_good): # test 503 handlers - def monkey_set(key, value): + def monkey_set(ns, key, value): # set a key override function that throws sdl errors on certain keys if key == "a1.policy_type.111": raise RejectedByBackend() diff --git a/tests/test_data.py b/tests/test_data.py deleted file mode 100644 index b148b23..0000000 --- a/tests/test_data.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -tests data functions -""" -# ================================================================================== -# Copyright (c) 2019-2020 Nokia -# 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 a1 import data -from ricsdl.syncstorage import SyncStorage - - -def setup_module(): - """module level setup""" - data.SDL.sdl = SyncStorage(fake_db_backend="dict") - - -def test_sdl_raw(): - """ - test raw sdl functions - """ - data.SDL.set("as.df1", "data") - data.SDL.set("as.df2", "data2") - assert data.SDL.get("as.df1") == "data" - assert data.SDL.get("as.df2") == "data2" - assert data.SDL.find_and_get("as.df1") == {"as.df1": "data"} - assert data.SDL.find_and_get("as.df2") == {"as.df2": "data2"} - assert data.SDL.find_and_get("as.df") == {"as.df1": "data", "as.df2": "data2"} - assert data.SDL.find_and_get("as.d") == {"as.df1": "data", "as.df2": "data2"} - assert data.SDL.find_and_get("as.") == {"as.df1": "data", "as.df2": "data2"} - assert data.SDL.find_and_get("asd") == {} - - # delete 1 - data.SDL.delete("as.df1") - assert data.SDL.get("as.df1") is None - assert data.SDL.get("as.df2") == "data2" - - # delete 2 - data.SDL.delete("as.df2") - assert data.SDL.get("as.df2") is None - - assert data.SDL.find_and_get("as.df") == {} - assert data.SDL.find_and_get("") == {} -- 2.16.6