blob: 199a7caced27ccf8e28be37057168b07d9c16062 [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
6import logging
7import os
8from typing import Optional # noqa: lint doesn't handle inline typehints
9from typing import Any, Dict
10
11import yaml
12from configuration.exceptions import LoadConfigError
13
14# Location of configs (both service config and mconfig)
15CONFIG_DIR = './magma_configs'
16CONFIG_OVERRIDE_DIR = './override_configs'
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +080017ENB_COMMON_FILE = './magma_configs/acs_common.yml'
18ENB_CONFIG_DIR = './magma_configs/serial_number'
Wei-Yu Chen49950b92021-11-08 19:19:18 +080019
20def load_override_config(service_name: str) -> Optional[Any]:
21 """
22 Load override service configuration from the file in the override
23 directory.
24
25 Args:
26 service_name: service to pull configs for; name of config file
27
28 Returns: json-decoded value of the service config, None if it's not found
29
30 Raises:
31 LoadConfigError:
32 Unable to load config due to missing file or missing key
33 """
34 override_file_name = _override_file_name(service_name)
35 if os.path.isfile(override_file_name):
36 return _load_yaml_file(override_file_name)
37 return None
38
39
40def save_override_config(service_name: str, cfg: Any):
41 """
42 Write the configuration object to its corresponding file in the override
43 directory.
44
45 Args:
46 service_name: service to write config object to; name of config file
47 cfg: json-decoded value of the service config
48 """
49 override_file_name = _override_file_name(service_name)
50 os.makedirs(CONFIG_OVERRIDE_DIR, exist_ok=True)
51 with open(override_file_name, 'w', encoding='utf-8') as override_file:
52 yaml.dump(cfg, override_file, default_flow_style=False)
53
54
55def load_service_config(service_name: str) -> Any:
56 """
57 Load service configuration from file. Also check override directory,
58 and, if service file present there, override the values.
59
60 Args:
61 service_name: service to pull configs for; name of config file
62
63 Returns: json-decoded value of the service config
64
65 Raises:
66 LoadConfigError:
67 Unable to load config due to missing file or missing key
68 """
Wei-Yu Chen49950b92021-11-08 19:19:18 +080069 cfg_file_name = os.path.join(CONFIG_DIR, '%s.yml' % service_name)
70 cfg = _load_yaml_file(cfg_file_name)
71
72 overrides = load_override_config(service_name)
73 if overrides is not None:
74 # Update the keys in the config if they are present in the override
75 cfg.update(overrides)
76 return cfg
77
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +080078def load_enb_config() -> Any:
79 """
Wei-Yu Chen8d064162022-05-27 21:06:55 +080080 Load the specific serial number enoode configuration as a dictionary
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +080081
82 Args:
83 None
84
85 Returns: json-decoded value of the service config
86 """
87
88 ret = dict()
Wei-Yu Chencb8ebb82022-06-09 21:01:00 +080089 if not os.path.exists(ENB_CONFIG_DIR):
90 return ret
91
Wei-Yu Chen31ebdb52022-06-27 16:53:11 +080092 for fname in filter(lambda x: x.endswith(".yml") or x.endswith(".yaml"), os.listdir(ENB_CONFIG_DIR)):
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +080093 sn = fname.replace(".yml", "")
94 cfg_file_name = os.path.join(ENB_CONFIG_DIR, fname)
Wei-Yu Chenb91af852022-03-15 22:24:49 +080095 sn_yaml = _load_yaml_file(cfg_file_name)
96
97 enb_cfg = dict()
98 for category in sn_yaml.values():
99 for key, value in category.items():
100 enb_cfg[key] = value
101
102 ret[sn] = enb_cfg
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +0800103
104 return ret
105
106def load_common_config() -> Any:
107 """
108 Load enb common configuration.
109
110 Args:
111 None
112
113 Returns: json-decoded value of the service config
114 """
115
116 return _load_yaml_file(ENB_COMMON_FILE)
117
Wei-Yu Chen49950b92021-11-08 19:19:18 +0800118
119cached_service_configs = {} # type: Dict[str, Any]
120
121
122def get_service_config_value(service: str, param: str, default: Any) -> Any:
123 """
124 Get a config value for :service:, falling back to a :default: value.
125
126 Log error if the default config is returned.
127
128 Args:
129 service: name of service to get config for
130 param: config key to fetch the value for
131 default: default value to return on failure
132
133 Returns:
134 value of :param: in the config files for :service:
135 """
136 service_configs = cached_service_configs.get(service)
137 try:
138 service_configs = service_configs or load_service_config(service)
139 except LoadConfigError as e:
140 logging.error('Error retrieving config: %s', e)
141 return default
142
143 # Handle empty file
144 if not service_configs:
145 logging.error('Error retrieving config, file empty for: %s', service)
146 return default
147
148 cached_service_configs[service] = service_configs
149
150 config_value = service_configs.get(param)
151 if config_value is not None:
152 return config_value
153 else:
154 logging.error(
155 'Error retrieving config for %s, key not found: %s',
156 service, param,
157 )
158 return default
159
160
161def _override_file_name(service_name: str) -> str:
162 return os.path.join(CONFIG_OVERRIDE_DIR, '%s.yml' % service_name)
163
164
165def _load_yaml_file(file_name: str) -> Any:
166 """
167 Load the yaml file and returns the python object.
168
169 Args:
170 file_name: name of the .yml file
171
172 Returns:
173 Contents of the yml file deserialized into a Python object
174
175 Raises:
176 LoadConfigError: on error
177 """
178
179 try:
180 with open(file_name, 'r', encoding='utf-8') as stream:
181 data = yaml.safe_load(stream)
182 return data
183 except (OSError, yaml.YAMLError) as e:
184 raise LoadConfigError('Error loading yml config') from e