Init commit for standalone enodebd
Change-Id: I88eeef5135dd7ba8551ddd9fb6a0695f5325337b
diff --git a/configuration/service_configs.py b/configuration/service_configs.py
new file mode 100644
index 0000000..c60c340
--- /dev/null
+++ b/configuration/service_configs.py
@@ -0,0 +1,152 @@
+"""
+Copyright 2020 The Magma Authors.
+
+This source code is licensed under the BSD-style license found in the
+LICENSE file in the root directory of this source tree.
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import logging
+import os
+from typing import Optional # noqa: lint doesn't handle inline typehints
+from typing import Any, Dict
+
+import yaml
+from configuration.exceptions import LoadConfigError
+
+# Location of configs (both service config and mconfig)
+CONFIG_DIR = './magma_configs'
+CONFIG_OVERRIDE_DIR = './override_configs'
+
+
+def load_override_config(service_name: str) -> Optional[Any]:
+ """
+ Load override service configuration from the file in the override
+ directory.
+
+ Args:
+ service_name: service to pull configs for; name of config file
+
+ Returns: json-decoded value of the service config, None if it's not found
+
+ Raises:
+ LoadConfigError:
+ Unable to load config due to missing file or missing key
+ """
+ override_file_name = _override_file_name(service_name)
+ if os.path.isfile(override_file_name):
+ return _load_yaml_file(override_file_name)
+ return None
+
+
+def save_override_config(service_name: str, cfg: Any):
+ """
+ Write the configuration object to its corresponding file in the override
+ directory.
+
+ Args:
+ service_name: service to write config object to; name of config file
+ cfg: json-decoded value of the service config
+ """
+ override_file_name = _override_file_name(service_name)
+ os.makedirs(CONFIG_OVERRIDE_DIR, exist_ok=True)
+ with open(override_file_name, 'w', encoding='utf-8') as override_file:
+ yaml.dump(cfg, override_file, default_flow_style=False)
+
+
+def load_service_config(service_name: str) -> Any:
+ """
+ Load service configuration from file. Also check override directory,
+ and, if service file present there, override the values.
+
+ Args:
+ service_name: service to pull configs for; name of config file
+
+ Returns: json-decoded value of the service config
+
+ Raises:
+ LoadConfigError:
+ Unable to load config due to missing file or missing key
+ """
+ print(CONFIG_DIR, service_name)
+ cfg_file_name = os.path.join(CONFIG_DIR, '%s.yml' % service_name)
+ cfg = _load_yaml_file(cfg_file_name)
+
+ overrides = load_override_config(service_name)
+ if overrides is not None:
+ # Update the keys in the config if they are present in the override
+ cfg.update(overrides)
+ return cfg
+
+
+cached_service_configs = {} # type: Dict[str, Any]
+
+
+def get_service_config_value(service: str, param: str, default: Any) -> Any:
+ """
+ Get a config value for :service:, falling back to a :default: value.
+
+ Log error if the default config is returned.
+
+ Args:
+ service: name of service to get config for
+ param: config key to fetch the value for
+ default: default value to return on failure
+
+ Returns:
+ value of :param: in the config files for :service:
+ """
+ service_configs = cached_service_configs.get(service)
+ try:
+ service_configs = service_configs or load_service_config(service)
+ except LoadConfigError as e:
+ logging.error('Error retrieving config: %s', e)
+ return default
+
+ # Handle empty file
+ if not service_configs:
+ logging.error('Error retrieving config, file empty for: %s', service)
+ return default
+
+ cached_service_configs[service] = service_configs
+
+ config_value = service_configs.get(param)
+ if config_value is not None:
+ return config_value
+ else:
+ logging.error(
+ 'Error retrieving config for %s, key not found: %s',
+ service, param,
+ )
+ return default
+
+
+def _override_file_name(service_name: str) -> str:
+ return os.path.join(CONFIG_OVERRIDE_DIR, '%s.yml' % service_name)
+
+
+def _load_yaml_file(file_name: str) -> Any:
+ """
+ Load the yaml file and returns the python object.
+
+ Args:
+ file_name: name of the .yml file
+
+ Returns:
+ Contents of the yml file deserialized into a Python object
+
+ Raises:
+ LoadConfigError: on error
+ """
+
+ try:
+ with open(file_name, 'r', encoding='utf-8') as stream:
+ data = yaml.safe_load(stream)
+ return data
+ except (OSError, yaml.YAMLError) as e:
+ raise LoadConfigError('Error loading yml config') from e