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