blob: c60c340e276d805a318689723ba29a6e37e20fb3 [file] [log] [blame]
"""
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