blob: f2d0f248b931563a9d32add1f7716390108c1e78 [file] [log] [blame]
Wei-Yu Chen49950b92021-11-08 19:19:18 +08001"""
2Copyright 2020 The Magma Authors.
3
4This source code is licensed under the BSD-style license found in the
5LICENSE file in the root directory of this source tree.
6
7Unless required by applicable law or agreed to in writing, software
8distributed under the License is distributed on an "AS IS" BASIS,
9WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10See the License for the specific language governing permissions and
11limitations under the License.
12"""
13
14import logging
15import os
16from typing import Optional # noqa: lint doesn't handle inline typehints
17from typing import Any, Dict
18
19import yaml
20from configuration.exceptions import LoadConfigError
21
22# Location of configs (both service config and mconfig)
23CONFIG_DIR = './magma_configs'
24CONFIG_OVERRIDE_DIR = './override_configs'
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +080025ENB_COMMON_FILE = './magma_configs/acs_common.yml'
26ENB_CONFIG_DIR = './magma_configs/serial_number'
Wei-Yu Chen49950b92021-11-08 19:19:18 +080027
28def load_override_config(service_name: str) -> Optional[Any]:
29 """
30 Load override service configuration from the file in the override
31 directory.
32
33 Args:
34 service_name: service to pull configs for; name of config file
35
36 Returns: json-decoded value of the service config, None if it's not found
37
38 Raises:
39 LoadConfigError:
40 Unable to load config due to missing file or missing key
41 """
42 override_file_name = _override_file_name(service_name)
43 if os.path.isfile(override_file_name):
44 return _load_yaml_file(override_file_name)
45 return None
46
47
48def save_override_config(service_name: str, cfg: Any):
49 """
50 Write the configuration object to its corresponding file in the override
51 directory.
52
53 Args:
54 service_name: service to write config object to; name of config file
55 cfg: json-decoded value of the service config
56 """
57 override_file_name = _override_file_name(service_name)
58 os.makedirs(CONFIG_OVERRIDE_DIR, exist_ok=True)
59 with open(override_file_name, 'w', encoding='utf-8') as override_file:
60 yaml.dump(cfg, override_file, default_flow_style=False)
61
62
63def load_service_config(service_name: str) -> Any:
64 """
65 Load service configuration from file. Also check override directory,
66 and, if service file present there, override the values.
67
68 Args:
69 service_name: service to pull configs for; name of config file
70
71 Returns: json-decoded value of the service config
72
73 Raises:
74 LoadConfigError:
75 Unable to load config due to missing file or missing key
76 """
Wei-Yu Chen49950b92021-11-08 19:19:18 +080077 cfg_file_name = os.path.join(CONFIG_DIR, '%s.yml' % service_name)
78 cfg = _load_yaml_file(cfg_file_name)
79
80 overrides = load_override_config(service_name)
81 if overrides is not None:
82 # Update the keys in the config if they are present in the override
83 cfg.update(overrides)
84 return cfg
85
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +080086def load_enb_config() -> Any:
87 """
88 Load enb configurations from directory.
89
90 Args:
91 None
92
93 Returns: json-decoded value of the service config
94 """
95
96 ret = dict()
97 for fname in os.listdir(ENB_CONFIG_DIR):
98 sn = fname.replace(".yml", "")
99 cfg_file_name = os.path.join(ENB_CONFIG_DIR, fname)
100 ret[sn] = _load_yaml_file(cfg_file_name)
101
102 return ret
103
104def load_common_config() -> Any:
105 """
106 Load enb common configuration.
107
108 Args:
109 None
110
111 Returns: json-decoded value of the service config
112 """
113
114 return _load_yaml_file(ENB_COMMON_FILE)
115
Wei-Yu Chen49950b92021-11-08 19:19:18 +0800116
117cached_service_configs = {} # type: Dict[str, Any]
118
119
120def get_service_config_value(service: str, param: str, default: Any) -> Any:
121 """
122 Get a config value for :service:, falling back to a :default: value.
123
124 Log error if the default config is returned.
125
126 Args:
127 service: name of service to get config for
128 param: config key to fetch the value for
129 default: default value to return on failure
130
131 Returns:
132 value of :param: in the config files for :service:
133 """
134 service_configs = cached_service_configs.get(service)
135 try:
136 service_configs = service_configs or load_service_config(service)
137 except LoadConfigError as e:
138 logging.error('Error retrieving config: %s', e)
139 return default
140
141 # Handle empty file
142 if not service_configs:
143 logging.error('Error retrieving config, file empty for: %s', service)
144 return default
145
146 cached_service_configs[service] = service_configs
147
148 config_value = service_configs.get(param)
149 if config_value is not None:
150 return config_value
151 else:
152 logging.error(
153 'Error retrieving config for %s, key not found: %s',
154 service, param,
155 )
156 return default
157
158
159def _override_file_name(service_name: str) -> str:
160 return os.path.join(CONFIG_OVERRIDE_DIR, '%s.yml' % service_name)
161
162
163def _load_yaml_file(file_name: str) -> Any:
164 """
165 Load the yaml file and returns the python object.
166
167 Args:
168 file_name: name of the .yml file
169
170 Returns:
171 Contents of the yml file deserialized into a Python object
172
173 Raises:
174 LoadConfigError: on error
175 """
176
177 try:
178 with open(file_name, 'r', encoding='utf-8') as stream:
179 data = yaml.safe_load(stream)
180 return data
181 except (OSError, yaml.YAMLError) as e:
182 raise LoadConfigError('Error loading yml config') from e