From c935e22252e22ea04ebafa83243b8376fcdd3190 Mon Sep 17 00:00:00 2001 From: Christophe Mehay Date: Sat, 19 Nov 2016 17:19:10 +0100 Subject: [PATCH] Fix setgid, add env to disable reloader --- Dockerfile.py2 | 3 +++ Dockerfile.py3 | 3 +++ README.md | 6 ++++++ docs/extra.rst | 14 +++++++++----- pyentrypoint/config.py | 22 ++++++++++++++++++---- setup.py | 2 +- tests/configs/usernames.yml | 4 ++-- tests/main_test.py | 4 ++-- tests/pyentrypoint_test.py | 35 ++++++++++++++++++++++++++++++++++- tests/reloader_test.py | 19 +++++++++++++++++++ 10 files changed, 97 insertions(+), 15 deletions(-) diff --git a/Dockerfile.py2 b/Dockerfile.py2 index d0e5529..23838ca 100644 --- a/Dockerfile.py2 +++ b/Dockerfile.py2 @@ -4,6 +4,9 @@ FROM python:2 RUN pip install pytest six pyyaml jinja2 colorlog watchdog pytest-mock +RUN adduser --uid 1009 --system testuser +RUN addgroup --gid 1010 testgroup + ENV PYTHONPATH /opt/ ADD tests/test_template.yml.tpl /tmp/test_template.yml diff --git a/Dockerfile.py3 b/Dockerfile.py3 index 62eec5d..fb87626 100644 --- a/Dockerfile.py3 +++ b/Dockerfile.py3 @@ -4,6 +4,9 @@ FROM python:3 RUN pip3 install pytest six pyyaml jinja2 colorlog watchdog pytest-mock +RUN adduser --uid 1009 --system testuser +RUN addgroup --gid 1010 testgroup + ENV PYTHONPATH /opt/ ADD tests/test_template.yml.tpl /tmp/test_template.yml diff --git a/README.md b/README.md index 539e76b..abc3990 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This tool avoids writing shell scripts to: - Identify linked containers - Generate configuration using `jinja2` templates - Run commands before starting service + - Reload service when configuration has changed [![Documentation Status](https://readthedocs.org/projects/pyentrypoint/badge/?version=latest)](http://pyentrypoint.readthedocs.io/en/latest/?badge=latest) @@ -247,6 +248,11 @@ Some setups can be overridden using environment variables. - `ENTRYPOINT_DEBUG` enables debug logs. - `ENTRYPOINT_RAW` does not use logging to display pre and post conf commands. This can be useful if output is serialized. +- `ENTRYPOINT_DISABLE_RELOAD` disable reload system even if it is enabled in `entrypoint-config.yml`. +- `ENTRYPOINT_USER` overrides `user` in config. +- `ENTRYPOINT_GROUP` overrides `group` in config. + + ### Running Tests diff --git a/docs/extra.rst b/docs/extra.rst index c98940f..40b5657 100644 --- a/docs/extra.rst +++ b/docs/extra.rst @@ -7,10 +7,14 @@ Some setups can be overridden using environment variables in the container. file. - ``ENTRYPOINT_FORCE`` applies configuration and runs pre and post conf commands even if the ``command`` provided is not handled. - - ``ENTRYPOINT_PRECONF_COMMAND`` run an extra pre conf shell command after +- ``ENTRYPOINT_PRECONF_COMMAND`` run an extra pre conf shell command after all pre conf commands. - - ``ENTRYPOINT_POSTCONF_COMMAND`` run an extra post conf shell command after +- ``ENTRYPOINT_POSTCONF_COMMAND`` run an extra post conf shell command after all post conf commands. -- ``ENTRYPOINT_DEBUG`` enables debug logs. -- ``ENTRYPOINT_RAW`` does not use logging to display pre and post conf commands. - This can be useful if output is serialized. +- ``ENTRYPOINT_DEBUG`` enables debug logs. +- ``ENTRYPOINT_RAW`` does not use logging to display pre and post conf + commands. This can be useful if output is serialized. +- ``ENTRYPOINT_DISABLE_RELOAD`` disable reload system even if it is enabled + in ``entrypoint-config.yml``. +- ``ENTRYPOINT_USER`` overrides ``user`` in config. +- ``ENTRYPOINT_GROUP`` overrides ``group`` in config. diff --git a/pyentrypoint/config.py b/pyentrypoint/config.py index 5356957..31f54cb 100644 --- a/pyentrypoint/config.py +++ b/pyentrypoint/config.py @@ -71,6 +71,16 @@ class ConfigMeta(object): '"{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 + class Config(ConfigMeta): @@ -125,6 +135,7 @@ class Config(ConfigMeta): @property def user(self): "Unix user or uid to run command." + self._get_from_env(env='ENTRYPOINT_USER', key='user') if 'user' in self._config: if isinstance(self._config['user'], int): return self._config['user'] @@ -134,10 +145,11 @@ class Config(ConfigMeta): @property def group(self): "Unix group or gid to run command." + self._get_from_env(env='ENTRYPOINT_GROUP', key='group') if 'group' in self._config: - if isinstance(self._config['user'], int): - return self._config['user'] - return getgrnam(self._config['user']).gr_gid + if isinstance(self._config['group'], int): + return self._config['group'] + return getgrnam(self._config['group']).gr_gid return os.getgid() @property @@ -176,9 +188,11 @@ class Config(ConfigMeta): @property def reload(self): """Return Reloader object if reload is set""" + if self._reload: return self._reload - if not self._config.get('reload'): + if (not self._config.get('reload') or + 'ENTRYPOINT_DISABLE_RELOAD' in os.environ): return None self._reload = self.get_reloader() return self._reload diff --git a/setup.py b/setup.py index 163b288..d033664 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import setup # Thanks Sam and Max -__version__ = '0.4.0' +__version__ = '0.4.1' if __name__ == '__main__': setup( diff --git a/tests/configs/usernames.yml b/tests/configs/usernames.yml index c2dac87..ee95c4f 100644 --- a/tests/configs/usernames.yml +++ b/tests/configs/usernames.yml @@ -1,6 +1,6 @@ command: bash -user: www-data -group: www-data +user: testuser +group: testgroup debug: true diff --git a/tests/main_test.py b/tests/main_test.py index d1cca6b..ef9d731 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -49,8 +49,8 @@ def test_main(): env={'ENTRYPOINT_CONFIG': 'configs/usernames.yml'} ).run), '/tmp/CMD__8', - 33, - 33, + 1009, + 1010, ), ( Process(target=ProxyMain( args=['pyentrypoint', 'bash', '-c', 'echo OK > /tmp/CMD__9'], diff --git a/tests/pyentrypoint_test.py b/tests/pyentrypoint_test.py index 1057e88..6a5db3e 100644 --- a/tests/pyentrypoint_test.py +++ b/tests/pyentrypoint_test.py @@ -184,7 +184,7 @@ def test_command(): (Process(target=Entrypoint( conf='configs/usernames.yml', args=['bash', '-c', 'echo OK > /tmp/CMD3']).launch), - '/tmp/CMD3', 33, 33), + '/tmp/CMD3', 1009, 1010), (Process(target=Entrypoint( conf='configs/unhandled.yml', args=['bash', '-c', 'echo OK > /tmp/CMD4']).launch), @@ -246,3 +246,36 @@ def test_debug_env(): assert entry.config.debug del os.environ['ENTRYPOINT_DEBUG'] + + +def test_quiet_env(): + os.environ['ENTRYPOINT_QUIET'] = 'true' + entry = Entrypoint(conf='configs/empty.yml') + + assert entry.config.quiet + + del os.environ['ENTRYPOINT_QUIET'] + + +def test_user_env(): + os.environ['ENTRYPOINT_USER'] = '100' + entry = Entrypoint(conf='configs/base.yml') + + assert entry.config.user == 100 + + os.environ['ENTRYPOINT_USER'] = 'testuser' + entry = Entrypoint(conf='configs/base.yml') + + assert entry.config.user == 1009 + + +def test_group_env(): + os.environ['ENTRYPOINT_GROUP'] = '100' + entry = Entrypoint(conf='configs/base.yml') + + assert entry.config.group == 100 + + os.environ['ENTRYPOINT_GROUP'] = 'testgroup' + entry = Entrypoint(conf='configs/base.yml') + + assert entry.config.group == 1010 diff --git a/tests/reloader_test.py b/tests/reloader_test.py index c89068d..1162121 100644 --- a/tests/reloader_test.py +++ b/tests/reloader_test.py @@ -10,6 +10,8 @@ except ImportError: # Python3 from unittest import mock +import os + from pyentrypoint import Entrypoint import subprocess @@ -21,6 +23,9 @@ from time import sleep def test_reloader(): + if 'ENTRYPOINT_DISABLE_RELOAD' in os.environ: + os.environ.pop('ENTRYPOINT_DISABLE_RELOAD') + with mock.patch('os.kill') as os_kill: entry = Entrypoint(conf='configs/reloader/reloader.yml') entry.apply_conf() @@ -31,8 +36,22 @@ def test_reloader(): os_kill.assert_called_once_with(1, SIGHUP) +def test_disabled_reloader(): + + os.environ['ENTRYPOINT_DISABLE_RELOAD'] = 'true' + + with mock.patch('os.kill') as os_kill: + entry = Entrypoint(conf='configs/reloader/reloader.yml') + entry.apply_conf() + assert entry.config.reload is None + assert not os_kill.called + + def test_reloader_custom(): + if 'ENTRYPOINT_DISABLE_RELOAD' in os.environ: + os.environ.pop('ENTRYPOINT_DISABLE_RELOAD') + with mock.patch('os.kill') as os_kill: entry = Entrypoint(conf='configs/reloader/reloader_config.yml') entry.apply_conf()