diff options
| author | jason | 2018-07-17 15:45:16 -0600 |
|---|---|---|
| committer | jason | 2018-07-17 15:53:48 -0600 |
| commit | 74df38d78e8bb3393c39c73d286874752b85511b (patch) | |
| tree | 11843c989fee471bc7f611d8e4dd0883ee61704e | |
| parent | d7138b32ce88b39edb0138b8fd3e5f54d51dfa7f (diff) | |
| download | eventmq-74df38d78e8bb3393c39c73d286874752b85511b.tar.gz eventmq-74df38d78e8bb3393c39c73d286874752b85511b.zip | |
Allow configuration options to be specified as environment variables
| -rw-r--r-- | docs/settings_file.rst | 12 | ||||
| -rw-r--r-- | etc/eventmq.conf-dist | 5 | ||||
| -rw-r--r-- | eventmq/__init__.py | 2 | ||||
| -rw-r--r-- | eventmq/tests/test_router.py | 13 | ||||
| -rw-r--r-- | eventmq/utils/settings.py | 68 | ||||
| -rw-r--r-- | setup.py | 2 |
6 files changed, 67 insertions, 35 deletions
diff --git a/docs/settings_file.rst b/docs/settings_file.rst index d09f124..04fe451 100644 --- a/docs/settings_file.rst +++ b/docs/settings_file.rst | |||
| @@ -1,7 +1,13 @@ | |||
| 1 | ############################## | 1 | ############################## |
| 2 | Server Settings (eventmq.conf) | 2 | Server Settings (eventmq.conf) |
| 3 | ############################## | 3 | ############################## |
| 4 | EventMQ uses a standard INI style config file found at ``/etc/eventmq.conf``. | 4 | EventMQ uses a standard INI style config file with the default |
| 5 | location of ``/etc/eventmq.conf``. If you would like to specify a custom path | ||
| 6 | you can use the ``EVENTMQ_CONFIG_FILE`` environment variable. | ||
| 7 | |||
| 8 | All of these options can be defined via environment variables by converting | ||
| 9 | them to upper case and prefixing them with ``EVENTMQ_``. For example | ||
| 10 | ``EVENTMQ_MAX_SOCKETS=2048``. | ||
| 5 | 11 | ||
| 6 | ****** | 12 | ****** |
| 7 | Global | 13 | Global |
| @@ -37,7 +43,7 @@ Default: 'tcp://127.0.0.1:47291' | |||
| 37 | The address used to listen for connections from workers | 43 | The address used to listen for connections from workers |
| 38 | 44 | ||
| 39 | wal | 45 | wal |
| 40 | ======= | 46 | === |
| 41 | Default: '/var/log/eventmq/wal.log' | 47 | Default: '/var/log/eventmq/wal.log' |
| 42 | 48 | ||
| 43 | Write-ahead Log for replaying messages received by the Router. Will | 49 | Write-ahead Log for replaying messages received by the Router. Will |
| @@ -45,7 +51,7 @@ try to create the directory specified and append to the filename given. | |||
| 45 | Requires correct permissions to write to the given file. | 51 | Requires correct permissions to write to the given file. |
| 46 | 52 | ||
| 47 | wal_enabled | 53 | wal_enabled |
| 48 | =============== | 54 | =========== |
| 49 | Default: False | 55 | Default: False |
| 50 | 56 | ||
| 51 | Enable or disable the Write-ahead Log | 57 | Enable or disable the Write-ahead Log |
diff --git a/etc/eventmq.conf-dist b/etc/eventmq.conf-dist index 9a59f2a..96dbad4 100644 --- a/etc/eventmq.conf-dist +++ b/etc/eventmq.conf-dist | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | # Enable message output at different stages in the app. | 2 | # Enable message output at different stages in the app. |
| 3 | super_debug = true | 3 | super_debug = true |
| 4 | 4 | ||
| 5 | # Number of maximum sockets to open per context/process. | ||
| 6 | max_sockets = 1024 | ||
| 7 | |||
| 5 | # Hide the heartbeat logs when super_debug is enabled. Showing them will generate a lot of messages. | 8 | # Hide the heartbeat logs when super_debug is enabled. Showing them will generate a lot of messages. |
| 6 | hide_heartbeat_logs = True | 9 | hide_heartbeat_logs = True |
| 7 | 10 | ||
| @@ -37,4 +40,4 @@ concurrent_jobs=2 | |||
| 37 | 40 | ||
| 38 | [publisher] | 41 | [publisher] |
| 39 | publisher_incoming_addr=tcp://0.0.0.0:47298 | 42 | publisher_incoming_addr=tcp://0.0.0.0:47298 |
| 40 | publisher_outgoing_addr=tcp://0.0.0.0:47299 \ No newline at end of file | 43 | publisher_outgoing_addr=tcp://0.0.0.0:47299 |
diff --git a/eventmq/__init__.py b/eventmq/__init__.py index c3ffd05..ed64a39 100644 --- a/eventmq/__init__.py +++ b/eventmq/__init__.py | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | __author__ = 'EventMQ Contributors' | 1 | __author__ = 'EventMQ Contributors' |
| 2 | __version__ = '0.3.7' | 2 | __version__ = '0.3.8' |
| 3 | 3 | ||
| 4 | PROTOCOL_VERSION = 'eMQP/1.0' | 4 | PROTOCOL_VERSION = 'eMQP/1.0' |
| 5 | 5 | ||
diff --git a/eventmq/tests/test_router.py b/eventmq/tests/test_router.py index e9efa25..cf7c9ef 100644 --- a/eventmq/tests/test_router.py +++ b/eventmq/tests/test_router.py | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | # | 12 | # |
| 13 | # You should have received a copy of the GNU Lesser General Public License | 13 | # You should have received a copy of the GNU Lesser General Public License |
| 14 | # along with eventmq. If not, see <http://www.gnu.org/licenses/>. | 14 | # along with eventmq. If not, see <http://www.gnu.org/licenses/>. |
| 15 | from imp import reload | ||
| 15 | import json | 16 | import json |
| 16 | import unittest | 17 | import unittest |
| 17 | 18 | ||
| @@ -35,6 +36,10 @@ class TestCase(unittest.TestCase): | |||
| 35 | @mock.patch('eventmq.receiver.zmq.Socket.bind') | 36 | @mock.patch('eventmq.receiver.zmq.Socket.bind') |
| 36 | @mock.patch('eventmq.router.Router._start_event_loop') | 37 | @mock.patch('eventmq.router.Router._start_event_loop') |
| 37 | def test_start(self, event_loop_mock, zsocket_bind_mock): | 38 | def test_start(self, event_loop_mock, zsocket_bind_mock): |
| 39 | # set the config file back to defaults. prevents tests from failing | ||
| 40 | # when there is a config file on the filesystem | ||
| 41 | reload(conf) | ||
| 42 | |||
| 38 | # Test default args | 43 | # Test default args |
| 39 | self.router.start() | 44 | self.router.start() |
| 40 | self.router.incoming.listen.assert_called_with(conf.FRONTEND_ADDR) | 45 | self.router.incoming.listen.assert_called_with(conf.FRONTEND_ADDR) |
| @@ -671,11 +676,9 @@ class TestCase(unittest.TestCase): | |||
| 671 | self.router.process_client_message( | 676 | self.router.process_client_message( |
| 672 | (s1, '', constants.PROTOCOL_VERSION, command, msgid) + | 677 | (s1, '', constants.PROTOCOL_VERSION, command, msgid) + |
| 673 | msg) | 678 | msg) |
| 674 | self.assertNotIn(s1, self.router.scheduler_queue, | 679 | self.assertNotIn( |
| 675 | 'Scheduler not ' | 680 | s1, self.router.scheduler_queue, |
| 676 | 'removed. {' | 681 | 'Scheduler not removed. {}'.format(self.router.scheduler_queue)) |
| 677 | '}'.format( | ||
| 678 | self.router.scheduler_queue)) | ||
| 679 | 682 | ||
| 680 | def test_handle_kbye_from_worker(self): | 683 | def test_handle_kbye_from_worker(self): |
| 681 | msgid = 'msg10' | 684 | msgid = 'msg10' |
diff --git a/eventmq/utils/settings.py b/eventmq/utils/settings.py index 30c4dee..9365bff 100644 --- a/eventmq/utils/settings.py +++ b/eventmq/utils/settings.py | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | :mod:`settings` -- Settings Utilities | 16 | :mod:`settings` -- Settings Utilities |
| 17 | ===================================== | 17 | ===================================== |
| 18 | """ | 18 | """ |
| 19 | from configparser import ConfigParser | 19 | from configparser import ConfigParser, NoOptionError |
| 20 | import json | 20 | import json |
| 21 | import logging | 21 | import logging |
| 22 | import os | 22 | import os |
| @@ -30,26 +30,51 @@ logger = logging.getLogger(__name__) | |||
| 30 | 30 | ||
| 31 | def import_settings(section='global'): | 31 | def import_settings(section='global'): |
| 32 | """ | 32 | """ |
| 33 | Import settings and apply to configuration globals | 33 | Import settings and apply to configuration globals. This function will |
| 34 | also read from the environment variables and override any value defined | ||
| 35 | in the file. | ||
| 34 | 36 | ||
| 35 | Args: | 37 | Args: |
| 36 | section (str): Name of the INI section to import | 38 | section (str): Name of the INI section to import |
| 37 | """ | 39 | """ |
| 38 | config = ConfigParser() | 40 | config = ConfigParser() |
| 39 | 41 | ||
| 40 | if os.path.exists(conf.CONFIG_FILE): | 42 | config_path = os.environ.get('EVENTMQ_CONFIG_FILE', conf.CONFIG_FILE) |
| 41 | config.read(conf.CONFIG_FILE) | 43 | use_config_file = False |
| 42 | 44 | ||
| 43 | if not config.has_section(section): | 45 | if os.path.exists(config_path): |
| 46 | config.read(config_path) | ||
| 47 | if config.has_section(section): | ||
| 48 | use_config_file = True | ||
| 49 | else: | ||
| 44 | logger.warning( | 50 | logger.warning( |
| 45 | 'Tried to read nonexistent section {}'.format(section)) | 51 | 'Tried to read nonexistent section {} from {}'.format( |
| 46 | return | 52 | section, config_path)) |
| 47 | 53 | ||
| 48 | for name, value in config.items(section): | 54 | for name in dir(conf): |
| 49 | if hasattr(conf, name.upper()): | 55 | if name.startswith('_'): |
| 50 | default_value = getattr(conf, name.upper()) | 56 | continue |
| 51 | t = type(default_value) | 57 | |
| 52 | if isinstance(default_value, (list, tuple)): | 58 | value = None |
| 59 | found_value = False | ||
| 60 | default_value = getattr(conf, name) | ||
| 61 | |||
| 62 | # Favor environment variables over the config file definition | ||
| 63 | try: | ||
| 64 | value = os.environ['EVENTMQ_{}'.format(name)] | ||
| 65 | found_value = True | ||
| 66 | except KeyError: | ||
| 67 | if use_config_file: | ||
| 68 | try: | ||
| 69 | value = config.get(section, name) | ||
| 70 | found_value = True | ||
| 71 | except NoOptionError: | ||
| 72 | found_value = False | ||
| 73 | |||
| 74 | if found_value: | ||
| 75 | t = type(getattr(conf, name)) | ||
| 76 | |||
| 77 | if t in (list, tuple): | ||
| 53 | try: | 78 | try: |
| 54 | value = t(json.loads(value)) | 79 | value = t(json.loads(value)) |
| 55 | except ValueError: | 80 | except ValueError: |
| @@ -60,19 +85,14 @@ def import_settings(section='global'): | |||
| 60 | # convert those elements, otherwise whatever it's type is | 85 | # convert those elements, otherwise whatever it's type is |
| 61 | # correct | 86 | # correct |
| 62 | if isinstance(default_value[0], tuple): | 87 | if isinstance(default_value[0], tuple): |
| 63 | setattr(conf, name.upper(), | 88 | setattr(conf, name, t(map(tuplify, value))) |
| 64 | t(map(tuplify, value))) | ||
| 65 | else: | 89 | else: |
| 66 | setattr(conf, name.upper(), t(value)) | 90 | setattr(conf, name, t(value)) |
| 67 | elif isinstance(default_value, bool): | 91 | elif isinstance(default_value, bool): |
| 68 | setattr(conf, name.upper(), | 92 | setattr(conf, name, |
| 69 | True if 't' in value.lower() else False) | 93 | True if 't' in value.lower() else False) |
| 70 | else: | 94 | else: |
| 71 | setattr(conf, name.upper(), t(value)) | 95 | setattr(conf, name, t(value)) |
| 72 | logger.debug("Setting conf.{} to {}".format( | 96 | |
| 73 | name.upper(), getattr(conf, name.upper()))) | 97 | logger.debug("Setting conf.{} to {}".format( |
| 74 | else: | 98 | name, getattr(conf, name))) |
| 75 | logger.warning('Tried to set invalid setting: %s' % name) | ||
| 76 | else: | ||
| 77 | logger.warning('Config file at {} not found. Continuing with ' | ||
| 78 | 'defaults.'.format(conf.CONFIG_FILE)) | ||
| @@ -7,7 +7,7 @@ from setuptools import find_packages, setup | |||
| 7 | 7 | ||
| 8 | setup( | 8 | setup( |
| 9 | name='eventmq', | 9 | name='eventmq', |
| 10 | version='0.3.7', | 10 | version='0.3.8', |
| 11 | description='EventMQ job execution and messaging system based on ZeroMQ', | 11 | description='EventMQ job execution and messaging system based on ZeroMQ', |
| 12 | packages=find_packages(), | 12 | packages=find_packages(), |
| 13 | install_requires=['pyzmq==15.4.0', | 13 | install_requires=['pyzmq==15.4.0', |