blob: 44f89eac95515bfa86160f052f744cb58d8653ae [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 Chenb91af852022-03-15 22:24:49 +080089 for fname in filter(lambda x: x.endswith(".yml"), os.listdir(ENB_CONFIG_DIR)):
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +080090 sn = fname.replace(".yml", "")
91 cfg_file_name = os.path.join(ENB_CONFIG_DIR, fname)
Wei-Yu Chenb91af852022-03-15 22:24:49 +080092 sn_yaml = _load_yaml_file(cfg_file_name)
93
94 enb_cfg = dict()
95 for category in sn_yaml.values():
96 for key, value in category.items():
97 enb_cfg[key] = value
98
99 ret[sn] = enb_cfg
Wei-Yu Chen5cbdfbb2021-12-02 01:10:21 +0800100
101 return ret
102
103def load_common_config() -> Any:
104 """
105 Load enb common configuration.
106
107 Args:
108 None
109
110 Returns: json-decoded value of the service config
111 """
112
113 return _load_yaml_file(ENB_COMMON_FILE)
114
Wei-Yu Chen49950b92021-11-08 19:19:18 +0800115
116cached_service_configs = {} # type: Dict[str, Any]
117
118
119def get_service_config_value(service: str, param: str, default: Any) -> Any:
120 """
121 Get a config value for :service:, falling back to a :default: value.
122
123 Log error if the default config is returned.
124
125 Args:
126 service: name of service to get config for
127 param: config key to fetch the value for
128 default: default value to return on failure
129
130 Returns:
131 value of :param: in the config files for :service:
132 """
133 service_configs = cached_service_configs.get(service)
134 try:
135 service_configs = service_configs or load_service_config(service)
136 except LoadConfigError as e:
137 logging.error('Error retrieving config: %s', e)
138 return default
139
140 # Handle empty file
141 if not service_configs:
142 logging.error('Error retrieving config, file empty for: %s', service)
143 return default
144
145 cached_service_configs[service] = service_configs
146
147 config_value = service_configs.get(param)
148 if config_value is not None:
149 return config_value
150 else:
151 logging.error(
152 'Error retrieving config for %s, key not found: %s',
153 service, param,
154 )
155 return default
156
157
158def _override_file_name(service_name: str) -> str:
159 return os.path.join(CONFIG_OVERRIDE_DIR, '%s.yml' % service_name)
160
161
162def _load_yaml_file(file_name: str) -> Any:
163 """
164 Load the yaml file and returns the python object.
165
166 Args:
167 file_name: name of the .yml file
168
169 Returns:
170 Contents of the yml file deserialized into a Python object
171
172 Raises:
173 LoadConfigError: on error
174 """
175
176 try:
177 with open(file_name, 'r', encoding='utf-8') as stream:
178 data = yaml.safe_load(stream)
179 return data
180 except (OSError, yaml.YAMLError) as e:
181 raise LoadConfigError('Error loading yml config') from e