2
0
mirror of https://github.com/cmehay/pyentrypoint synced 2024-10-30 15:21:11 +00:00

Add post_run_commands

This commit is contained in:
Christophe Mehay 2016-12-30 19:52:12 +01:00
parent 72e44abe8c
commit c0dbfce4c2
11 changed files with 150 additions and 61 deletions

12
.travis.yml Normal file
View File

@ -0,0 +1,12 @@
sudo: required
services:
- docker
language: python
before_install:
- pip install -r requirements-dev.txt
script:
- make test

2
CHANGELOG Normal file
View File

@ -0,0 +1,2 @@
v0.5.0:
- add post_run_commands in entrypoint-config.yml

View File

@ -3,8 +3,17 @@
build:
@docker-compose build
test: build
@docker-compose up --force-recreate testpython2 testpython3
clean:
docker-compose down --remove-orphans
test: build test-python2 test-python3 clean
test-python2:
@docker-compose run --rm testpython2
test-python3:
@docker-compose run --rm testpython3
test_debug: build
@docker-compose up --force-recreate testpython2_debug testpython3_debug

View File

@ -6,6 +6,7 @@ import os
from fnmatch import fnmatch
from .logs import Logs
from .runner import Runner
class Command(object):
@ -21,6 +22,8 @@ class Command(object):
self.log.debug('Arguments are: "{args}"'.format(
args='" "'.join(self.args)
))
self.runner = Runner(config=self.config,
cmds=self.config.post_run_commands)
def _rm_dockerenv(self):
"""Delete '/.dockerenv' and '/.dockerinit' files"""
@ -88,6 +91,11 @@ class Command(object):
self.log.debug('Launching reloader process')
self.config.reload.run_in_process()
def _run_post_commands(self):
if self.config.post_run_commands:
self.log.debug('Running post run commands')
self.runner.run_in_process()
def run(self):
if not self.is_handled:
self._exec()
@ -107,4 +115,5 @@ class Command(object):
[p for p in subcom if fnmatch(self.args[0], p)]:
self.args.insert(0, self.command)
self._run_reloader()
self._run_post_commands()
self._exec()

View File

@ -203,6 +203,11 @@ class Config(ConfigMeta):
"""Return list of postconf commands"""
return self._return_item_lst('post_conf_commands')
@property
def post_run_commands(self):
"""Return list of post run commands"""
return self._return_item_lst('post_run_commands')
@property
def reload(self):
"""Return Reloader object if reload is set"""
@ -239,3 +244,20 @@ class Config(ConfigMeta):
if 'ENTRYPOINT_QUIET' in os.environ:
return True
return bool(self._config.get('quiet', False))
@property
def is_disabled(self):
"""Return if service is disabled using environment"""
return 'ENTRYPOINT_DISABLE_SERVICE' in os.environ
@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"""
if 'ENTRYPOINT_RAW' in os.environ:
return True
return bool(self._config.get('raw_output', False))

View File

@ -8,11 +8,8 @@ from __future__ import unicode_literals
import json
import os
from subprocess import PIPE
from subprocess import Popen
from sys import argv
from sys import exit
from sys import stdout
import yaml
from jinja2 import Environment
@ -22,6 +19,7 @@ from .config import Config
from .constants import ENTRYPOINT_FILE
from .docker_links import DockerLinks
from .logs import Logs
from .runner import Runner
__all__ = ['Entrypoint', 'main']
@ -49,6 +47,7 @@ class Entrypoint(object):
if self.config.quiet:
Logs.set_critical()
self.args = args
self.runner = Runner(config=self.config)
@property
def is_handled(self):
@ -58,21 +57,21 @@ class Entrypoint(object):
@property
def is_disabled(self):
"""Return if service is disabled using environment"""
return 'ENTRYPOINT_DISABLE_SERVICE' in os.environ
return self.config.is_disabled
@property
def should_config(self):
"""Check environment to tell if config should apply anyway"""
return 'ENTRYPOINT_FORCE' in os.environ
return self.config.should_config
@property
def raw_output(self):
"""Check if command output should be displayed using logging or not"""
return 'ENTRYPOINT_RAW' in os.environ
return self.config.raw_output
def exit_if_disabled(self):
"""Exist 0 if service is disabled"""
if not self.is_disabled:
if not self.config.is_disabled:
return
self.log.warning("Service is disabled by 'ENTRYPOINT_DISABLE_SERVICE' "
@ -94,41 +93,17 @@ class Entrypoint(object):
yaml=yaml,
containers=DockerLinks().to_containers()))
def run_conf_cmd(self, cmd):
self.log.debug('run command: {}'.format(cmd))
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)
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)
self.runner.run_cmd(cmd)
if 'ENTRYPOINT_PRECONF_COMMAND' in os.environ:
self.run_conf_cmd(os.environ['ENTRYPOINT_PRECONF_COMMAND'])
self.runner.run_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)
self.runner.run_cmd(cmd)
if 'ENTRYPOINT_POSTCONF_COMMAND' in os.environ:
self.run_conf_cmd(os.environ['ENTRYPOINT_POSTCONF_COMMAND'])
self.runner.run_cmd(os.environ['ENTRYPOINT_POSTCONF_COMMAND'])
def launch(self):
self.config.command.run()

52
pyentrypoint/runner.py Normal file
View File

@ -0,0 +1,52 @@
"Run commands"
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from multiprocessing import Process
from subprocess import PIPE
from subprocess import Popen
from sys import stdout
from .logs import Logs
class Runner(object):
'This object run commands'
def __init__(self, config, cmds=[]):
self.log = Logs().log
self.cmds = cmds
self.raw_output = config.raw_output
def run_cmd(self, cmd):
self.log.debug('run command: {}'.format(cmd))
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)
if proc.returncode:
raise Exception('Command exit code: {}'.format(proc.returncode))
def run(self):
for cmd in self.cmds:
self.run_cmd(cmd)
def run_in_process(self):
self.proc = Process(target=self.run)
self.proc.start()

View File

@ -1,23 +1 @@
argparse==1.4.0
aspy.yaml==0.2.1
blessings==1.6
bpython==0.14.2
cached-property==1.3.0
colorlog==2.6.1
curtsies==0.1.23
docker-compose==1.5.2
docker-py==1.6.0
dockerpty==0.3.4
docopt==0.6.2
greenlet==0.4.9
jsonschema==2.5.1
nodeenv==0.13.6
ordereddict==1.1
pre-commit==0.7.5
Pygments==2.0.2
PyYAML==3.11
requests==2.7.0
six==1.10.0
texttable==0.8.4
virtualenv==13.1.2
websocket-client==0.35.0
docker-compose==1.7.0

View File

@ -5,7 +5,7 @@ from setuptools import setup
# Thanks Sam and Max
__version__ = '0.4.7'
__version__ = '0.5.0'
if __name__ == '__main__':
setup(

5
tests/configs/runner.yml Normal file
View File

@ -0,0 +1,5 @@
post_run_commands:
- sleep 2
- echo 'OK' > /tmp/runner_test
command: sleep

25
tests/runner_test.py Normal file
View File

@ -0,0 +1,25 @@
"Tests for runner"
from __future__ import absolute_import
from __future__ import unicode_literals
import os
from multiprocessing import Process
from pyentrypoint import Entrypoint
def test_runner():
run = [
(Process(target=Entrypoint(
conf='configs/runner.yml',
args=['sleep', '5']).launch),
'/tmp/runner_test', 0, 0),
]
for proc, test, uid, gid in run:
proc.start()
proc.join()
with open(test, 'r') as f:
assert f.readline().startswith('OK')
assert os.stat(test).st_uid == uid
assert os.stat(test).st_gid == gid