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/entrypoint.py

135 lines
4.1 KiB
Python

9 years ago
#!/usr/bin/env python
"""
Smart docker-entrypoint
"""
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import os
9 years ago
from subprocess import PIPE
from subprocess import Popen
from sys import argv
from sys import exit
from sys import stdout
9 years ago
from jinja2 import Environment
from jinja2 import FileSystemLoader
from .config import Config
8 years ago
from .constants import ENTRYPOINT_FILE
from .docker_links import DockerLinks
from .logs import Logs
__all__ = ['Entrypoint', 'main']
9 years ago
class Entrypoint(object):
"""Entrypoint class."""
def _set_logguer(self):
self.log = Logs().log
9 years ago
8 years ago
def __init__(self, conf=ENTRYPOINT_FILE, args=[]):
9 years ago
self._set_logguer()
if 'ENTRYPOINT_CONFIG' in os.environ:
conf = os.environ['ENTRYPOINT_CONFIG']
9 years ago
try:
8 years ago
self.config = Config(conf=conf, args=args)
9 years ago
except Exception as err:
self.log.error(err)
self.log.critical('Fail to initialize config, exiting now')
exit(1)
else:
if self.config.debug:
Logs.set_debug()
9 years ago
self.args = args
@property
def is_handled(self):
"""Is command handled by entrypoint"""
return self.config.command.is_handled
@property
def should_config(self):
"""Check environment to tell if config should apply anyway"""
return 'ENTRYPOINT_FORCE' in os.environ
@property
def raw_output(self):
"""Check if command output should be displayed using logging or not"""
return 'ENTRYPOINT_RAW' in os.environ
9 years ago
def apply_conf(self):
"""Apply config to template files"""
9 years ago
env = Environment(loader=FileSystemLoader('/'))
for template, conf_file in self.config.get_templates():
9 years ago
temp = env.get_template(template)
with open(conf_file, mode='w') as f:
self.log.debug('Applying conf to {}'.format(conf_file))
9 years ago
f.write(temp.render(config=self.config,
links=self.config.links,
env=os.environ,
environ=os.environ,
containers=DockerLinks().to_containers()))
9 years ago
def run_conf_cmd(self, cmd):
8 years ago
self.log.debug('run command: {}'.format(cmd))
9 years ago
proc = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
out, err = proc.communicate()
def dispout(output, cb):
enc = stdout.encoding or 'UTF-8'
output = output.decode(enc).split('\n')
l = len(output)
for c, line in enumerate(output):
if c + 1 == l and not len(line):
# Do not display last empty line
break
cb(line)
if out:
display_cb = self.log.info if not self.raw_output else print
dispout(out, display_cb)
if err:
display_cb = self.log.warning if not self.raw_output else print
dispout(err, display_cb)
9 years ago
if proc.returncode:
raise Exception('Command exit code: {}'.format(proc.returncode))
def run_pre_conf_cmds(self):
for cmd in self.config.pre_conf_commands:
self.run_conf_cmd(cmd)
if 'ENTRYPOINT_PRECONF_COMMAND' in os.environ:
self.run_conf_cmd(os.environ['ENTRYPOINT_PRECONF_COMMAND'])
def run_post_conf_cmds(self):
for cmd in self.config.post_conf_commands:
self.run_conf_cmd(cmd)
if 'ENTRYPOINT_POSTCONF_COMMAND' in os.environ:
self.run_conf_cmd(os.environ['ENTRYPOINT_POSTCONF_COMMAND'])
9 years ago
def launch(self):
self.config.command.run()
9 years ago
def main(argv):
argv.pop(0)
entry = Entrypoint(args=argv)
9 years ago
try:
if not entry.is_handled and not entry.should_config:
entry.log.warning("Running command without config")
entry.launch()
entry.log.debug("Starting config")
entry.run_pre_conf_cmds()
9 years ago
entry.apply_conf()
entry.run_post_conf_cmds()
9 years ago
entry.launch()
except Exception as e:
entry.log.error(str(e))
if __name__ == '__main__':
main(argv)