import logging import yaml from util.license import LICENSE_FILENAME, LicenseDecodeError, decode_license logger = logging.getLogger(__name__) class CannotWriteConfigException(Exception): """ Exception raised when the config cannot be written. """ pass class SetupIncompleteException(Exception): """ Exception raised when attempting to verify config that has not yet been setup. """ pass def import_yaml(config_obj, config_file): with open(config_file) as f: c = yaml.safe_load(f) if not c: logger.debug('Empty YAML config file') return if isinstance(c, str): raise Exception('Invalid YAML config file: ' + str(c)) for key in c.iterkeys(): if key.isupper(): config_obj[key] = c[key] return config_obj def get_yaml(config_obj): return yaml.safe_dump(config_obj, encoding='utf-8', allow_unicode=True) def export_yaml(config_obj, config_file): try: with open(config_file, 'w') as f: f.write(get_yaml(config_obj)) except IOError as ioe: raise CannotWriteConfigException(str(ioe)) class BaseProvider(object): """ A configuration provider helps to load, save, and handle config override in the application. """ def __init__(self): self.license = None @property def provider_id(self): raise NotImplementedError def update_app_config(self, app_config): """ Updates the given application config object with the loaded override config. """ raise NotImplementedError def get_config(self): """ Returns the contents of the config override file, or None if none. """ raise NotImplementedError def save_config(self, config_object): """ Updates the contents of the config override file to those given. """ raise NotImplementedError def config_exists(self): """ Returns true if a config override file exists in the config volume. """ raise NotImplementedError def volume_exists(self): """ Returns whether the config override volume exists. """ raise NotImplementedError def volume_file_exists(self, filename): """ Returns whether the file with the given name exists under the config override volume. """ raise NotImplementedError def get_volume_file(self, filename, mode='r'): """ Returns a Python file referring to the given name under the config override volume. """ raise NotImplementedError def write_volume_file(self, filename, contents): """ Writes the given contents to the config override volumne, with the given filename. """ raise NotImplementedError def save_volume_file(self, filename, flask_file): """ Saves the given flask file to the config override volume, with the given filename. """ raise NotImplementedError def requires_restart(self, app_config): """ If true, the configuration loaded into memory for the app does not match that on disk, indicating that this container requires a restart. """ raise NotImplementedError def _get_license_file(self): """ Returns the contents of the license file. """ if not self.has_license_file(): msg = 'Could not find license file. Please make sure it is in your config volume.' raise LicenseDecodeError(msg) try: return self.get_volume_file(LICENSE_FILENAME) except IOError: msg = 'Could not open license file. Please make sure it is in your config volume.' raise LicenseDecodeError(msg) def get_license(self): """ Returns the decoded license, if any. """ with self._get_license_file() as f: license_file_contents = f.read() return decode_license(license_file_contents) def save_license(self, license_file_contents): """ Saves the given contents as the license file. """ self.write_volume_file(LICENSE_FILENAME, license_file_contents) def has_license_file(self): """ Returns true if a license file was found in the config directory. """ return self.volume_file_exists(LICENSE_FILENAME)