X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=a1%2Fdata.py;h=436912f8a45e9bdf6ee83e5efe16b90167c6dce4;hb=d7858cf453b4f74cd4dad0e13106218ea9a56785;hp=a98be5c15ca691d86cdb0ab8359fb5acefaba528;hpb=aa4ffa78f3e6a9430cc9ae9933165e58105c9d65;p=ric-plt%2Fa1.git diff --git a/a1/data.py b/a1/data.py index a98be5c..436912f 100644 --- a/a1/data.py +++ b/a1/data.py @@ -1,14 +1,6 @@ -""" -Represents A1s database and database access functions. -In the future, this may change to use a different backend, possibly dramatically. -Hopefully, the access functions are a good api so nothing else has to change when this happens - -For now, the database is in memory. -We use dict data structures (KV) with the expectation of having to move this into Redis -""" # ================================================================================== -# Copyright (c) 2019 Nokia -# Copyright (c) 2018-2019 AT&T Intellectual Property. +# 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. @@ -22,59 +14,33 @@ We use dict data structures (KV) with the expectation of having to move this int # See the License for the specific language governing permissions and # limitations under the License. # ================================================================================== +""" +Represents A1s database and database access functions. +""" +import distutils.util import os import time from threading import Thread -import msgpack from mdclogpy import Logger -from a1.exceptions import PolicyTypeNotFound, PolicyInstanceNotFound, PolicyTypeAlreadyExists, CantDeleteNonEmptyType - -mdc_logger = Logger(name=__name__) - +from ricxappframe.xapp_sdl import SDLWrapper +from a1.exceptions import PolicyTypeNotFound, PolicyInstanceNotFound, PolicyTypeAlreadyExists, PolicyTypeIdMismatch, CantDeleteNonEmptyType +# 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)) - - -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.POLICY_DATA = {} - - def set(self, key, value): - """set a key""" - self.POLICY_DATA[key] = msgpack.packb(value, use_bin_type=True) - - def get(self, key): - """get a key""" - if key in self.POLICY_DATA: - return msgpack.unpackb(self.POLICY_DATA[key], raw=False) - return None - - def find_and_get(self, prefix): - """get all k v pairs that start with prefix""" - return {k: msgpack.unpackb(v, raw=False) for k, v in self.POLICY_DATA.items() if k.startswith(prefix)} - - def delete(self, key): - """ delete a key""" - del self.POLICY_DATA[key] - - -SDL = SDLWrapper() - +USE_FAKE_SDL = bool(distutils.util.strtobool(os.environ.get("USE_FAKE_SDL", "False"))) +A1NS = "A1m_ns" 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__) +if USE_FAKE_SDL: + mdc_logger.debug("Using fake SDL") +SDL = SDLWrapper(use_fake_sdl=USE_FAKE_SDL) + # Internal helpers @@ -117,8 +83,8 @@ def _type_is_valid(policy_type_id): """ check that a type is valid """ - if SDL.get(_generate_type_key(policy_type_id)) is None: - raise PolicyTypeNotFound() + if SDL.get(A1NS, _generate_type_key(policy_type_id)) is None: + raise PolicyTypeNotFound(policy_type_id) def _instance_is_valid(policy_type_id, policy_instance_id): @@ -126,8 +92,8 @@ 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: - raise PolicyInstanceNotFound + if SDL.get(A1NS, _generate_instance_key(policy_type_id, policy_instance_id)) is None: + raise PolicyInstanceNotFound(policy_type_id) def _get_statuses(policy_type_id, policy_instance_id): @@ -136,7 +102,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): @@ -145,7 +111,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] @@ -154,9 +120,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): @@ -165,7 +131,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): @@ -179,8 +145,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)) @@ -191,7 +157,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] @@ -200,10 +166,12 @@ def store_policy_type(policy_type_id, body): """ store a policy type if it doesn't already exist """ + if policy_type_id != body['policy_type_id']: + raise PolicyTypeIdMismatch("{0} vs. {1}".format(policy_type_id, body['policy_type_id'])) key = _generate_type_key(policy_type_id) - if SDL.get(key) is not None: - raise PolicyTypeAlreadyExists() - SDL.set(key, body) + if SDL.get(A1NS, key) is not None: + raise PolicyTypeAlreadyExists(policy_type_id) + SDL.set(A1NS, key, body) def delete_policy_type(policy_type_id): @@ -212,9 +180,9 @@ 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() + raise CantDeleteNonEmptyType(policy_type_id) def get_policy_type(policy_type_id): @@ -222,7 +190,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 @@ -236,14 +204,18 @@ def store_policy_instance(policy_type_id, policy_instance_id, instance): creation_timestamp = time.time() # store the instance + operation = "CREATE" 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: + operation = "UPDATE" # 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}) + + return operation def get_policy_instance(policy_type_id, policy_instance_id): @@ -251,7 +223,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): @@ -263,7 +235,7 @@ def get_instance_list(policy_type_id): def delete_policy_instance(policy_type_id, policy_instance_id): """ - initially sets has_been_deleted + initially sets has_been_deleted in the status then launches a thread that waits until the relevent timer expires, and finally deletes the instance """ _instance_is_valid(policy_type_id, policy_instance_id) @@ -273,6 +245,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}, ) @@ -300,7 +273,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):