From fc17439b55327283443ea838a7e56a34baa15176 Mon Sep 17 00:00:00 2001 From: Nate Coraor Date: Wed, 31 Aug 2022 10:32:21 -0400 Subject: [PATCH] Fix setting environment vars on handlers --- README.rst | 15 +++++++-------- gravity/config_manager.py | 16 +++++++++++++--- gravity/state.py | 3 +++ tests/test_config_manager.py | 5 ++++- tests/test_process_manager.py | 12 +++++++++++- 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index 1b4c7e1..96d0a37 100644 --- a/README.rst +++ b/README.rst @@ -304,15 +304,13 @@ In ``gravity.yml`` on the job handler host:: Galaxy Job Handlers ------------------- -Gravity has limited support for reading Galaxy's job configuration: it can read statically configured job handlers in -the ``job_conf.xml`` file, but cannot read the newer YAML-format job configuration, or the job configuration inline from -``galaxy.yml``. Improved support for reading Galaxy's job configuration is planned, but for the time being, Gravity will -run standalone Galaxy job handler processes if you: +Gravity has support for reading Galaxy's job configuration: it can read statically configured job handlers in the +``job_conf.yml`` or ``job_conf.yml`` files, or the job configuration inline from the ``job_config`` option in +``galaxy.yml``. However, unless you need to statically define handlers, it is simpler to configure Gravity to run +`dynamically defined handlers`_ as detailed in the Galaxy scaling documentation. -1. Set ``job_handler_count`` to a number greater than ``0``. **NOTE:** You must also explicitly set the `job handler - assignment method`_ to ``db-skip-locked`` or ``db-transaction-isolation`` to prevent the web process from also - handling jobs. This is the preferred method for specifying job handlers. -2. Define static ```` handlers in the XML-format job configuration file. +When using dynamically defined handlers, be sure to explicitly set the `job handler assignment method`_ to +``db-skip-locked`` or ``db-transaction-isolation`` to prevent the web process from also handling jobs. Configuration Precedence ------------------------ @@ -466,5 +464,6 @@ A ``configstate.yaml`` file for a Galaxy service might look like:: .. _FastAPI: https://fastapi.tiangolo.com/ .. _unicornherder: https://github.com/alphagov/unicornherder .. _job handler assignment method: https://docs.galaxyproject.org/en/master/admin/scaling.html#job-handler-assignment-methods +.. _dynamically defined handlers: https://docs.galaxyproject.org/en/latest/admin/scaling.html#dynamically-defined-handlers .. _Ansible: http://www.ansible.com/ .. _Issue #6: https://github.com/galaxyproject/gravity/issues/6 diff --git a/gravity/config_manager.py b/gravity/config_manager.py index 444b300..3126a94 100644 --- a/gravity/config_manager.py +++ b/gravity/config_manager.py @@ -140,8 +140,12 @@ def get_config(self, conf, defaults=None): if not exists(job_config): job_config = None if config.config_type == "galaxy" and job_config: - for service_name in [x["service_name"] for x in ConfigManager.get_job_config(job_config) if x["service_name"] not in webapp_service_names]: - config.services.append(service_for_service_type("standalone")(config_type=config.config_type, service_name=service_name)) + for handler_settings in [x for x in ConfigManager.get_job_config(job_config) if x["service_name"] not in webapp_service_names]: + config.services.append(service_for_service_type("standalone")( + config_type=config.config_type, + service_name=handler_settings["service_name"], + environment=handler_settings.get("environment") + )) # Dynamic job handlers are configured using `job_handler_count` in galaxy.yml. # @@ -157,8 +161,14 @@ def create_handler_services(self, gravity_config: Settings, config): expanded_handlers = self.expand_handlers(gravity_config, config) for service_name, handler_settings in expanded_handlers.items(): pools = handler_settings.get('pools') + environment = handler_settings.get("environment") config.services.append( - service_for_service_type("standalone")(config_type=config.config_type, service_name=service_name, server_pools=pools)) + service_for_service_type("standalone")( + config_type=config.config_type, + service_name=service_name, + server_pools=pools, + environment=environment + )) def create_gxit_services(self, gravity_config: Settings, app_config, config): if app_config.get("interactivetools_enable") and gravity_config.gx_it_proxy.enable: diff --git a/gravity/state.py b/gravity/state.py index 099706c..fb6eb80 100644 --- a/gravity/state.py +++ b/gravity/state.py @@ -147,6 +147,9 @@ class GalaxyStandaloneService(Service): command_template = "{virtualenv_bin}python ./lib/galaxy/main.py -c {galaxy_conf} --server-name={server_name}{attach_to_pool_opt}" \ " --pid-file={supervisor_state_dir}/{program_name}.pid" + def get_environment(self): + return self.get("environment") or {} + class ConfigFile(AttributeDict): def __init__(self, *args, **kwargs): diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index 08bc140..7ea044d 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -42,12 +42,14 @@ def test_preload_default(galaxy_yml, default_config_manager): def test_register_non_default(galaxy_yml, default_config_manager): new_bind = 'localhost:8081' + environment = {'FOO': 'foo'} concurrency = 4 galaxy_yml.write(json.dumps({ 'galaxy': None, 'gravity': { 'gunicorn': { - 'bind': new_bind + 'bind': new_bind, + 'environment': environment }, 'celery': { 'concurrency': concurrency @@ -58,6 +60,7 @@ def test_register_non_default(galaxy_yml, default_config_manager): state = default_config_manager.state['config_files'][str(galaxy_yml)] gunicorn_attributes = state['attribs']['gunicorn'] assert gunicorn_attributes['bind'] == new_bind + assert gunicorn_attributes['environment'] == environment default_settings = Settings() assert gunicorn_attributes['workers'] == default_settings.gunicorn.workers celery_attributes = state['attribs']['celery'] diff --git a/tests/test_process_manager.py b/tests/test_process_manager.py index 7daf25c..af5428d 100644 --- a/tests/test_process_manager.py +++ b/tests/test_process_manager.py @@ -21,6 +21,8 @@ processes: handler0: handler1: + environment: + BAZ: baz sge_handler: # Restrict a handler to load specific runners, by default they will load all. plugins: ['sge'] @@ -58,10 +60,14 @@ pools: - job-handlers - workflow-schedulers + environment: + FOO: foo handler1: processes: 1 pools: - job-handlers.special + environment: + BAR: bar handler2: processes: 1 pools: @@ -123,9 +129,11 @@ def test_dynamic_handlers(default_config_manager, galaxy_yml, job_conf): handler0_config = handler_config_paths[0].open().read() assert " --server-name=handler0" in handler0_config assert " --attach-to-pool=job-handlers --attach-to-pool=workflow-schedulers" in handler0_config + assert " FOO=foo" in handler0_config handler1_config = handler_config_paths[1].open().read() assert " --server-name=handler1" in handler1_config assert " --attach-to-pool=job-handlers.special" in handler1_config + assert " BAR=bar" in handler1_config handler2_config = handler_config_paths[2].open().read() assert " --server-name=handler2" in handler2_config assert " --attach-to-pool=job-handlers --attach-to-pool=job-handlers.special" in handler2_config @@ -166,7 +174,9 @@ def test_static_handlers_yaml(default_config_manager, galaxy_yml, job_conf): assert '.yml --server-name=handler0 --pid-file=' in handler0_config_path.open().read() handler1_config_path = instance_conf_dir / 'galaxy_standalone_handler1.conf' assert handler1_config_path.exists() - assert '.yml --server-name=handler1 --pid-file=' in handler1_config_path.open().read() + handler1_config = handler1_config_path.open().read() + assert '.yml --server-name=handler1 --pid-file=' in handler1_config + assert 'BAZ=baz' in handler1_config assert (instance_conf_dir / 'galaxy_standalone_sge_handler.conf').exists() assert (instance_conf_dir / 'galaxy_standalone_special_handler0.conf').exists() assert (instance_conf_dir / 'galaxy_standalone_special_handler1.conf').exists()