Source code for prestoadmin.util.base_config
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# 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.
"""
Module for common configuration stuff.
"""
import abc
from functools import wraps
from fabric.context_managers import settings
from fabric.operations import prompt
from prestoadmin import config
from prestoadmin.config import ConfigFileNotFoundError
from prestoadmin.util.exception import ConfigurationError
[docs]class SingleConfigItem(object):
def __init__(self, key, prompt, default=None, validate=None):
self.key = key
self.prompt = prompt
self.default = default
self.validate = validate
[docs] def prompt_user(self, conf):
conf[self.key] = prompt(self.prompt,
default=conf.get(self.key, self.default),
validate=self.validate)
[docs] def collect_prompts(self, l):
l.append((self.prompt, self.key))
[docs]class MultiConfigItem(object):
def __init__(self, items, validate, validate_keys,
validate_failed_text):
self.items = items
self.validate = validate
self.validate_keys = validate_keys
self.validate_failed_text = validate_failed_text
[docs] def prompt_user(self, conf):
while True:
for item in self.items:
item.prompt_user(conf)
validate_args = [conf[k] for k in self.validate_keys]
if self.validate(*validate_args):
break
print (self.validate_failed_text % self.validate_keys) % conf
[docs] def collect_prompts(self, l):
for item in self.items:
item.collect_prompts(l)
[docs]def requires_config(config_class):
def wrap(func):
config_instance = config_class()
func.pa_config_callback = config_instance.get_config
@wraps(func)
def wrapper(*args, **kwargs):
if not config_instance.is_config_loaded():
raise ConfigurationError('Required config not loaded at task '
'execution time.')
return func(*args, **kwargs)
return wrapper
return wrap
[docs]class BaseConfig(object):
'''
BaseConfig provides the common config functionality for loading
configuration files for presto-admin and going through the interactive
config process if a config file isn't present.
Instances of classes that subclass BaseConfig are intended to be used with
the @requires_config decorator, which is responsible for adding an
attribute to the task that tells main() how to load the configuration
and subsequently for enforcing that the configuration has been loaded at
the time the task is actually run.
In order to be compatible with @requires_config, subclasses must define
a no-arguments constructor.
'''
__metaclass__ = abc.ABCMeta
def __init__(self, config_path, config_items):
self.config_path = config_path
self.config_items = config_items
self.config = {}
def __getitem__(self, key):
return self.config[key]
def __setitem__(self, key, value):
self.config[key] = value
def __delitem__(self, key):
del self.config[key]
[docs] def read_conf(self):
return config.get_conf_from_json_file(self.config_path)
[docs] def write_conf(self, conf):
config.write(config.json_to_string(conf), self.config_path)
return self.config_path
[docs] def get_conf_interactive(self):
conf = {}
for item in self.config_items:
item.prompt_user(conf)
return conf
[docs] def get_config(self):
with settings(parallel=False):
if not self.is_config_loaded():
conf = {}
try:
conf = self.read_conf()
except ConfigFileNotFoundError:
conf = self.get_conf_interactive()
self.write_conf(conf)
self.set_env_from_conf(conf)
self.set_config_loaded()
return self.config_path
@abc.abstractmethod
[docs] def is_config_loaded(self):
pass
@abc.abstractmethod
[docs] def set_config_loaded(self):
pass
@abc.abstractmethod
[docs] def set_env_from_conf(self, conf):
pass