Add configuration-change API
[ric-plt/xapp-frame-py.git] / ricxappframe / xapp_sdl.py
1 # ==================================================================================
2 #       Copyright (c) 2020 Nokia
3 #       Copyright (c) 2020 AT&T Intellectual Property.
4 #
5 #   Licensed under the Apache License, Version 2.0 (the "License");
6 #   you may not use this file except in compliance with the License.
7 #   You may obtain a copy of the License at
8 #
9 #          http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #   Unless required by applicable law or agreed to in writing, software
12 #   distributed under the License is distributed on an "AS IS" BASIS,
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 #   See the License for the specific language governing permissions and
15 #   limitations under the License.
16 # ==================================================================================
17
18 """
19 sdl functionality
20 """
21
22 import msgpack
23 from ricsdl.syncstorage import SyncStorage
24
25
26 class SDLWrapper:
27     """
28     Provides convenient wrapper methods for using the SDL Python interface.
29     Optionally uses msgpack for binary (de)serialization:
30     see https://msgpack.org/index.html
31
32     Published as a standalone module (and kept separate from the Xapp
33     framework classes) so these features can be used outside Xapps.
34     """
35
36     def __init__(self, use_fake_sdl=False):
37         """
38         init
39
40         Parameters
41         ----------
42         use_fake_sdl: bool (optional, default False)
43             if this is True, then use SDL's in-memory backend,
44             which is very useful for testing since it allows use
45             of SDL without a running SDL or Redis instance.
46             This can be used while developing an xapp and also
47             for monkeypatching during unit testing; e.g., the xapp
48             framework unit tests do this.
49         """
50         if use_fake_sdl:
51             self._sdl = SyncStorage(fake_db_backend="dict")
52         else:
53             self._sdl = SyncStorage()
54
55     def set(self, ns, key, value, usemsgpack=True):
56         """
57         Stores a key-value pair,
58         optionally serializing the value to bytes using msgpack.
59
60         TODO: discuss whether usemsgpack should *default* to True or
61         False here. This seems like a usage statistic question (that we
62         don't have enough data for yet). Are more uses for an xapp to
63         write/read their own data, or will more xapps end up reading data
64         written by some other thing? I think it's too early to know.
65
66         Parameters
67         ----------
68         ns: string
69             SDL namespace
70         key: string
71             SDL key
72         value:
73             Object or byte array to store.  See the `usemsgpack` parameter.
74         usemsgpack: boolean (optional, default is True)
75             Determines whether the value is serialized using msgpack before storing.
76             If usemsgpack is True, the msgpack function `packb` is invoked
77             on the value to yield a byte array that is then sent to SDL.
78             Stated differently, if usemsgpack is True, the value can be anything
79             that is serializable by msgpack.
80             If usemsgpack is False, the value must be bytes.
81         """
82         if usemsgpack:
83             value = msgpack.packb(value, use_bin_type=True)
84         self._sdl.set(ns, {key: value})
85
86     def get(self, ns, key, usemsgpack=True):
87         """
88         Gets the value for the specified namespace and key,
89         optionally deserializing stored bytes using msgpack.
90
91         Parameters
92         ----------
93         ns: string
94             SDL namespace
95         key: string
96             SDL key
97         usemsgpack: boolean (optional, default is True)
98             If usemsgpack is True, the byte array stored by SDL is deserialized
99             using msgpack to yield the original object that was stored.
100             If usemsgpack is False, the byte array stored by SDL is returned
101             without further processing.
102
103         Returns
104         -------
105         Value
106             See the usemsgpack parameter for an explanation of the returned value type.
107             Answers None if the key is not found.
108         """
109         result = None
110         ret_dict = self._sdl.get(ns, {key})
111         if key in ret_dict:
112             result = ret_dict[key]
113             if usemsgpack:
114                 result = msgpack.unpackb(result, raw=False)
115         return result
116
117     def find_and_get(self, ns, prefix, usemsgpack=True):
118         """
119         Gets all key-value pairs in the specified namespace
120         with keys that start with the specified prefix,
121         optionally deserializing stored bytes using msgpack.
122
123         Parameters
124         ----------
125         ns: string
126            SDL namespace
127         prefix: string
128             the key prefix
129         usemsgpack: boolean (optional, default is True)
130             If usemsgpack is True, every byte array stored by SDL is deserialized
131             using msgpack to yield the original value that was stored.
132             If usemsgpack is False, every byte array stored by SDL is returned
133             without further processing.
134
135         Returns
136         -------
137         Dictionary of key-value pairs
138             Each key has the specified prefix.
139             See the usemsgpack parameter for an explanation of the returned value types.
140             Answers an empty dictionary if no keys matched the prefix.
141         """
142
143         # note: SDL "*" usage is inconsistent with real python regex, where it would be ".*"
144         ret_dict = self._sdl.find_and_get(ns, "{0}*".format(prefix))
145         if usemsgpack:
146             ret_dict = {k: msgpack.unpackb(v, raw=False) for k, v in ret_dict.items()}
147         return ret_dict
148
149     def delete(self, ns, key):
150         """
151         Deletes the key-value pair with the specified key in the specified namespace.
152
153         Parameters
154         ----------
155         ns: string
156            SDL namespace
157         key: string
158             SDL key
159         """
160         self._sdl.remove(ns, {key})
161
162     def healthcheck(self):
163         """
164         Checks if the sdl connection is healthy.
165
166         Returns
167         -------
168         bool
169         """
170         return self._sdl.is_active()