You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pyentrypoint/pyentrypoint/config.py

296 lines
9.2 KiB
Python

9 years ago
"""
Configuration object
9 years ago
"""
9 years ago
import os
from distutils.util import strtobool
from fnmatch import fnmatch
9 years ago
from grp import getgrnam
from io import open
from pwd import getpwnam
9 years ago
from six import string_types
from yaml import safe_load
9 years ago
from .command import Command
8 years ago
from .constants import ENTRYPOINT_FILE
from .docker_links import DockerLinks
from .links import Links
from .logs import Logs
8 years ago
from .reloader import Reloader
__all__ = ['Config']
9 years ago
def envtobool(key, default):
return bool(strtobool(os.environ.get(key, str(default))))
class ConfigMeta(object):
9 years ago
def _return_item_lst(self, item):
"""Return item as a list"""
if item in self._config:
if isinstance(self._config[item], string_types):
return [self._config[item]]
return self._config[item]
return []
def get_templates(self):
"""Returns iterator of tuple (template, config_file)"""
config_files = self.config_files
if isinstance(config_files, list):
for item in config_files:
if isinstance(item, string_types):
template = item
outfile = item[:-4] if item.endswith('.tpl') else item
if isinstance(item, dict):
template = list(item.keys())[0]
outfile = item[template]
yield (template, outfile)
8 years ago
else:
raise Exception("config_files setup missformated.")
8 years ago
def get_reloader(self):
"""Setup and get reloader"""
config_files = [file[1] for file in self.get_templates()]
reload = self._config['reload']
if isinstance(reload, bool):
return Reloader(files=config_files)
if isinstance(reload, dict):
signal = reload.get('signal', 'SIGHUP')
watch_config_files = bool(reload.get('watch_config_files'))
files = reload.get('files', [])
if not isinstance(files, list):
raise Exception('Reload files is not a list')
if watch_config_files:
files.extend(config_files)
return Reloader(files=files, sig=signal)
def _check_config(self):
for key in self._config:
if not hasattr(Config, key) or key == '__init__':
self.log.warning(
'"{key}" is not a valid option'.format(key=key)
)
def _get_from_env(self, env, key):
val = os.environ.get(env, None)
if val is None:
return None
try:
val = int(val)
except ValueError:
pass
self._config[key] = val
def set_to_env(self):
self.log.debug('Add conf to environment')
for attr in [a for a in dir(self) if not a.startswith('_')]:
setup = getattr(self, attr)
env = 'ENTRYPOINT_{attr}'.format(attr=attr.upper())
if type(setup) is bool and setup:
self.log.debug('set env {env} with "true"'.format(
env=env
))
os.environ[env] = 'true'
if type(setup) is int or type(setup) is str:
if env not in os.environ:
self.log.debug('set env {env} with "{val}"'.format(
env=env,
val=str(setup),
))
os.environ[env] = str(setup)
class Config(ConfigMeta):
"""
Get entrypoint config
Parse entrypoint-config.yml
Config file should always be in WORKDIR and named entrypoint-config.yml
"""
8 years ago
def __init__(self, conf=ENTRYPOINT_FILE, args=[]):
9 years ago
self._config = {}
self.log = Logs().log
self._args = args
9 years ago
self._links = None
self._command = None
8 years ago
self._reload = None
8 years ago
self._config_file = conf
9 years ago
if not os.path.isfile(self._config_file):
self.log.critical('Entrypoint config file does not provided')
9 years ago
return
with open(self._config_file) as f:
self._config = safe_load(stream=f)
self._check_config()
9 years ago
@property
def has_config(self):
9 years ago
"Has config file provided."
return len(self._config) != 0
@property
def commands(self):
"Handled commands"
rtn = self._return_item_lst('commands')
return rtn
9 years ago
@property
def command(self):
"Main command to run."
if self._command:
return self._command
9 years ago
cmd = self._args[0] if self._args else ''
if 'commands' in self._config:
commands = self._return_item_lst('commands')
if [p for p in commands if fnmatch(self._args[0], p)]:
self._command = Command(cmd, self, self._args)
return self._command
9 years ago
for key in ['command', 'cmd']:
if key in self._config:
self.log.warning(
'"command" is deprecated, use "commands" instead',
)
9 years ago
cmd = self._config[key]
self._command = Command(cmd, self, self._args)
return self._command
9 years ago
@property
def subcommands(self):
"""Subcommands to handle as arguments."""
rtn = self._return_item_lst('subcommands')
if rtn:
self.log.warning(
'"subcommands" is deprecated, '
'subcommands will not be handled anymore.',
)
if self.commands:
self.log.warning(
'"subcommands" is ignored as long "commands" in present',
)
return rtn
else:
return ['-*']
9 years ago
@property
def user(self):
"Unix user or uid to run command."
self._get_from_env(env='ENTRYPOINT_USER', key='user')
9 years ago
if 'user' in self._config:
if isinstance(self._config['user'], int):
return self._config['user']
return getpwnam(self._config['user']).pw_uid
9 years ago
return os.getuid()
@property
def group(self):
"Unix group or gid to run command."
self._get_from_env(env='ENTRYPOINT_GROUP', key='group')
9 years ago
if 'group' in self._config:
if isinstance(self._config['group'], int):
return self._config['group']
return getgrnam(self._config['group']).gr_gid
9 years ago
return os.getgid()
@property
def config_files(self):
"List of template config files."
return self._return_item_lst('config_files')
@property
def secret_env(self):
"""Environment variables to delete before running command."""
return self._return_item_lst('secret_env')
@property
def links(self):
9 years ago
"""Links configs singleton."""
if self._links:
return self._links
9 years ago
if 'links' not in self._config:
self._links = Links(links=DockerLinks())
9 years ago
return self._links
self._links = Links(config=self._config['links'], links=DockerLinks())
9 years ago
for name in self._config['links']:
9 years ago
self._links._add_name(name)
return self._links
@property
def pre_conf_commands(self):
"""Return list of preconf commands"""
return self._return_item_lst('pre_conf_commands')
9 years ago
@property
9 years ago
def post_conf_commands(self):
"""Return list of postconf commands"""
return self._return_item_lst('post_conf_commands')
9 years ago
@property
def post_run_commands(self):
"""Return list of post run commands"""
return self._return_item_lst('post_run_commands')
8 years ago
@property
def reload(self):
"""Return Reloader object if reload is set"""
8 years ago
if self._reload:
return self._reload
if (not self._config.get('reload') or
envtobool('ENTRYPOINT_DISABLE_RELOAD', False)):
8 years ago
return None
self._reload = self.get_reloader()
return self._reload
9 years ago
@property
9 years ago
def clean_env(self):
"""Clean env from linked containers before running command"""
if 'clean_env' in self._config:
return bool(self._config['clean_env'])
return True
9 years ago
@property
def remove_dockerenv(self):
"""Remove dockerenv and dockerinit files"""
if 'remove_dockerenv' in self._config:
return bool(self._config['remove_dockerenv'])
return True
9 years ago
@property
def debug(self):
"""Enable debug logs."""
if envtobool('ENTRYPOINT_DEBUG', False):
return True
9 years ago
if 'debug' in self._config:
return bool(self._config['debug'])
return False
8 years ago
@property
def quiet(self):
"""Disable logging"""
if self.debug:
return False
if envtobool('ENTRYPOINT_QUIET', False):
8 years ago
return True
return bool(self._config.get('quiet', False))
@property
def is_disabled(self):
"""Return if service is disabled using environment"""
return envtobool('ENTRYPOINT_DISABLE_SERVICE', False)
@property
def should_config(self):
"""Check environment to tell if config should apply anyway"""
return envtobool('ENTRYPOINT_FORCE', False)
@property
def raw_output(self):
"""Check if command output should be displayed using logging or not"""
if envtobool('ENTRYPOINT_RAW', False):
return True
return bool(self._config.get('raw_output', False))