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:
parent
72e44abe8c
commit
c0dbfce4c2
12
.travis.yml
Normal file
12
.travis.yml
Normal 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
2
CHANGELOG
Normal file
@ -0,0 +1,2 @@
|
||||
v0.5.0:
|
||||
- add post_run_commands in entrypoint-config.yml
|
13
Makefile
13
Makefile
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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))
|
||||
|
@ -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
52
pyentrypoint/runner.py
Normal 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()
|
@ -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
|
||||
|
2
setup.py
2
setup.py
@ -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
5
tests/configs/runner.yml
Normal file
@ -0,0 +1,5 @@
|
||||
post_run_commands:
|
||||
- sleep 2
|
||||
- echo 'OK' > /tmp/runner_test
|
||||
|
||||
command: sleep
|
25
tests/runner_test.py
Normal file
25
tests/runner_test.py
Normal 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
|
Loading…
Reference in New Issue
Block a user