blob: 997748f3cd94e749faba5b1256cc217f68eb53b3 [file] [log] [blame]
Wei-Yu Chenad55cb82022-02-15 20:07:01 +08001# SPDX-FileCopyrightText: 2020 The Magma Authors.
2# SPDX-FileCopyrightText: 2022 Open Networking Foundation <support@opennetworking.org>
3#
4# SPDX-License-Identifier: BSD-3-Clause
Wei-Yu Chen49950b92021-11-08 19:19:18 +08005
6from abc import ABC, abstractmethod
7from collections import namedtuple
8from typing import Any, Callable, Dict, List, Optional
9
10from data_models.data_model_parameters import ParameterName
11
12TrParam = namedtuple('TrParam', ['path', 'is_invasive', 'type', 'is_optional'])
13
14# We may want to model nodes in the datamodel that are derived from other fields
15# in the datamodel and thus maynot have a representation in tr69.
16# e.g PTP_STATUS in FreedomFiOne is True iff GPS is in sync and SyncStatus is
17# True.
18# Explicitly map these params to invalid paths so setters and getters know they
19# should not try to read or write these nodes on the eNB side.
20InvalidTrParamPath = "INVALID_TR_PATH"
21
22
23class DataModel(ABC):
24 """
25 Class to represent relevant data model parameters.
26
27 Also should contain transform functions for certain parameters that are
28 represented differently in the eNodeB device than it is in Magma.
29
30 Subclass this for each data model implementation.
31
32 This class is effectively read-only.
33 """
34
35 def __init__(self):
36 self._presence_by_param = {}
37
38 def are_param_presences_known(self) -> bool:
39 """
40 True if all optional parameters' presence are known in data model
41 """
42 optional_params = self.get_names_of_optional_params()
43 for param in optional_params:
44 if param not in self._presence_by_param:
45 return False
46 return True
47
48 def is_parameter_present(self, param_name: ParameterName) -> bool:
49 """ Is the parameter missing from the device's data model """
50 param_info = self.get_parameter(param_name)
51 if param_info is None:
52 return False
53 if not param_info.is_optional:
54 return True
55 if param_name not in self._presence_by_param:
56 raise KeyError(
57 'Parameter presence not yet marked in data '
58 'model: %s' % param_name,
59 )
60 return self._presence_by_param[param_name]
61
62 def set_parameter_presence(
63 self,
64 param_name: ParameterName,
65 is_present: bool,
66 ) -> None:
67 """ Mark optional parameter as either missing or not """
68 self._presence_by_param[param_name] = is_present
69
70 def get_missing_params(self) -> List[ParameterName]:
71 """
72 Return optional params confirmed to be missing from data model.
73 NOTE: Make sure we already know which parameters are present or not
74 """
75 all_missing = []
76 for param in self.get_names_of_optional_params():
77 if self.is_parameter_present(param):
78 all_missing.append(param)
79 return all_missing
80
81 def get_present_params(self) -> List[ParameterName]:
82 """
83 Return optional params confirmed to be present in data model.
84 NOTE: Make sure we already know which parameters are present or not
85 """
86 all_optional = self.get_names_of_optional_params()
87 all_present = self.get_parameter_names()
88 for param in all_optional:
89 if not self.is_parameter_present(param):
90 all_present.remove(param)
91 return all_present
92
93 @classmethod
94 def get_names_of_optional_params(cls) -> List[ParameterName]:
95 all_optional_params = []
96 for name in cls.get_parameter_names():
97 if cls.get_parameter(name).is_optional:
98 all_optional_params.append(name)
99 return all_optional_params
100
101 @classmethod
102 def transform_for_magma(
103 cls,
104 param_name: ParameterName,
105 enb_value: Any,
106 ) -> Any:
107 """
108 Convert a parameter from its device specific formatting to the
109 consistent format that magma understands.
110 For the same parameter, different data models have their own
111 idiosyncrasies. For this reason, it's important to nominalize these
112 values before processing them in Magma code.
113
114 Args:
115 param_name: The parameter name
116 enb_value: Native value of the parameter
117
118 Returns:
119 Returns the nominal value of the parameter that is understood
120 by Magma code.
121 """
122 transforms = cls._get_magma_transforms()
123 if param_name in transforms:
124 transform_function = transforms[param_name]
125 return transform_function(enb_value)
126 return enb_value
127
128 @classmethod
129 def transform_for_enb(
130 cls,
131 param_name: ParameterName,
132 magma_value: Any,
133 ) -> Any:
134 """
135 Convert a parameter from the format that Magma understands to
136 the device specific formatting.
137 For the same parameter, different data models have their own
138 idiosyncrasies. For this reason, it's important to nominalize these
139 values before processing them in Magma code.
140
141 Args:
142 param_name: The parameter name. The transform is dependent on the
143 exact parameter.
144 magma_value: Nominal value of the parameter.
145
146 Returns:
147 Returns the native value of the parameter that will be set in the
148 CPE data model configuration.
149 """
150 transforms = cls._get_enb_transforms()
151 if param_name in transforms:
152 transform_function = transforms[param_name]
153 return transform_function(magma_value)
154 return magma_value
155
156 @classmethod
157 def get_parameter_name_from_path(
158 cls,
159 param_path: str,
160 ) -> Optional[ParameterName]:
161 """
162 Args:
163 param_path: Parameter path,
164 eg. "Device.DeviceInfo.X_BAICELLS_COM_GPS_Status"
165 Returns:
166 ParameterName or None if there is no ParameterName matching
167 """
168 all_param_names = cls.get_parameter_names()
169 numbered_param_names = cls.get_numbered_param_names()
170 for _obj_name, param_name_list in numbered_param_names.items():
171 all_param_names = all_param_names + param_name_list
172
173 for param_name in all_param_names:
174 param_info = cls.get_parameter(param_name)
175 if param_info is not None and param_path == param_info.path:
176 return param_name
177 return None
178
179 @classmethod
180 @abstractmethod
181 def get_parameter(cls, param_name: ParameterName) -> Optional[TrParam]:
182 """
183 Args:
184 param_name: String of the parameter name
185
186 Returns:
187 TrParam or None if it doesn't exist
188 """
189 pass
190
191 @classmethod
192 @abstractmethod
193 def _get_magma_transforms(
194 cls,
195 ) -> Dict[ParameterName, Callable[[Any], Any]]:
196 """
197 For the same parameter, different data models have their own
198 idiosyncrasies. For this reason, it's important to nominalize these
199 values before processing them in Magma code.
200
201 Returns:
202 Dictionary with key of parameter name, and value of a transform
203 function taking the device-specific value of the parameter and
204 returning the value in format understood by Magma.
205 """
206 pass
207
208 @classmethod
209 @abstractmethod
210 def _get_enb_transforms(
211 cls,
212 ) -> Dict[ParameterName, Callable[[Any], Any]]:
213 """
214 For the same parameter, different data models have their own
215 idiosyncrasies. For this reason, it's important to nominalize these
216 values before processing them in Magma code.
217
218 Returns:
219 Dictionary with key of parameter name, and value of a transform
220 function taking the nominal value of the parameter and returning
221 the device-understood value.
222 """
223 pass
224
225 @classmethod
226 @abstractmethod
227 def get_load_parameters(cls) -> List[ParameterName]:
228 """
229 Returns:
230 List of all parameters to query when reading eNodeB state
231 """
232 pass
233
234 @classmethod
235 @abstractmethod
236 def get_num_plmns(cls) -> int:
237 """
238 Returns:
239 The number of PLMNs in the configuration.
240 """
241 pass
242
243 @classmethod
244 @abstractmethod
245 def get_parameter_names(cls) -> List[ParameterName]:
246 """
247 Returns:
248 A list of all parameter names that are neither numbered objects,
249 or belonging to numbered objects
250 """
251 pass
252
253 @classmethod
254 @abstractmethod
255 def get_numbered_param_names(
256 cls,
257 ) -> Dict[ParameterName, List[ParameterName]]:
258 """
259 Returns:
260 A key for all parameters that are numbered objects, and the value
261 is the list of parameters that belong to that numbered object
262 """
263 pass