Loading services/webapp/code/rosetta/core_app/computing_managers.py +48 −6 Original line number Diff line number Diff line from .models import TaskStatuses, KeyPair, Task, Storage from .utils import os_shell, get_ssh_access_mode_credentials from .utils import os_shell, get_ssh_access_mode_credentials, sanitize_container_env_vars from .exceptions import ErrorMessage, ConsistencyException from django.conf import settings Loading Loading @@ -107,6 +107,15 @@ class InternalStandaloneComputingManager(StandaloneComputingManager): if not task.requires_proxy and task.password: run_command += ' -eAUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: run_command += ' -e{}={} '.format(env_var, env_vars[env_var]) # User data volume #run_command += ' -v {}/user-{}:/data'.format(settings.LOCAL_USER_DATA_DIR, task.user.id) Loading Loading @@ -204,7 +213,18 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana # Set pass if any authstring = '' if not task.requires_proxy_auth and task.password: authstring = ' export SINGULARITYENV_AUTH_PASS={} && '.format(task.password) authstring = ' && export SINGULARITYENV_AUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: varsstring = '' # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: varsstring += ' && export SINGULARITYENV_{}={} '.format(env_var, env_vars[env_var]) else: varsstring = '' # Handle storages (binds) binds = '' Loading Loading @@ -241,7 +261,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana run_command = 'ssh -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_keys.private_key_file, computing_user, computing_host) run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir -p /tmp/{}_data/tmp && mkdir -p /tmp/{}_data/home && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'wget {}/api/v1/base/agent/?task_uuid={} -O /tmp/{}_data/agent.py &> /dev/null && export BASE_PORT=\$(python /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\$BASE_PORT && {} '.format(authstring) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\$BASE_PORT {} {} &&'.format(authstring, varsstring) run_command += 'exec nohup singularity run {} --pid --writable-tmpfs --no-home --home=/home/metauser --workdir /tmp/{}_data/tmp -B/tmp/{}_data/home:/home --containall --cleanenv '.format(binds, task.uuid, task.uuid) # Container part Loading @@ -255,6 +275,17 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana if not task.requires_proxy_auth and task.password: authstring = ' -e AUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: varsstring = '' # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: varsstring += ' -e {}={} '.format(env_var, env_vars[env_var]) else: varsstring = '' # Handle storages (binds) binds = '' storages = Storage.objects.filter(computing=self.computing) Loading Loading @@ -293,7 +324,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana run_command = 'ssh -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_keys.private_key_file, computing_user, computing_host) run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir /tmp/{}_data && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid) run_command += 'wget {}/api/v1/base/agent/?task_uuid={} -O /tmp/{}_data/agent.py &> /dev/null && export TASK_PORT=\$(python /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid) run_command += '{} {} run -p \$TASK_PORT:{} {} {} '.format(prefix, container_engine, task.container.interface_port, authstring, binds) run_command += '{} {} run -p \$TASK_PORT:{} {} {} {} '.format(prefix, container_engine, task.container.interface_port, authstring, varsstring, binds) if container_engine == 'podman': run_command += '--network=private --uts=private ' #run_command += '-d -t {}/{}:{}'.format(task.container.registry, task.container.image_name, task.container.image_tag) Loading Loading @@ -435,7 +466,18 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag # Set pass if any authstring = '' if not task.requires_proxy_auth and task.password: authstring = ' export SINGULARITYENV_AUTH_PASS={} && '.format(task.password) authstring = ' && export SINGULARITYENV_AUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: varsstring = '' # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: varsstring += ' && export SINGULARITYENV_{}={} '.format(env_var, env_vars[env_var]) else: varsstring = '' # Handle storages (binds) binds = '' Loading Loading @@ -471,7 +513,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag run_command = 'ssh -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_keys.private_key_file, computing_user, computing_host) run_command += '\'bash -c "echo \\"#!/bin/bash\nwget {}/api/v1/base/agent/?task_uuid={} -O \$HOME/agent_{}.py &> \$HOME/{}.log && export BASE_PORT=\\\\\\$(python \$HOME/agent_{}.py 2> \$HOME/{}.log) && '.format(webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\\\\\\$BASE_PORT && {} '.format(authstring) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\\\\\\$BASE_PORT {} {} && '.format(authstring, varsstring) run_command += 'rm -rf /tmp/{}_data && mkdir -p /tmp/{}_data/tmp &>> \$HOME/{}.log && mkdir -p /tmp/{}_data/home &>> \$HOME/{}.log && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'exec nohup singularity run {} --pid --writable-tmpfs --no-home --home=/home/metauser --workdir /tmp/{}_data/tmp -B/tmp/{}_data/home:/home --containall --cleanenv '.format(binds, task.uuid, task.uuid) Loading services/webapp/code/rosetta/core_app/migrations/0031_container_env_vars.py 0 → 100644 +25 −0 Original line number Diff line number Diff line # Generated by Django 2.2.1 on 2022-01-16 18:40 from django.conf import settings from django.db import migrations # Load database-dependent JSON field if 'sqlite' in settings.DATABASES['default']['ENGINE']: from rosetta.core_app.fields import JSONField else: from django.contrib.postgres.fields import JSONField class Migration(migrations.Migration): dependencies = [ ('core_app', '0030_auto_20211218_2355'), ] operations = [ migrations.AddField( model_name='container', name='env_vars', field=JSONField(blank=True, null=True, verbose_name='Container env vars'), ), ] services/webapp/code/rosetta/core_app/models.py +3 −0 Original line number Diff line number Diff line Loading @@ -141,6 +141,9 @@ class Container(models.Model): supports_interface_auth = models.BooleanField('Supports interface auth', default=False) # AUTH_USER / AUTH_PASS interface_auth_user = models.CharField('Interface auth fixed user if any', max_length=36, blank=True, null=True) # Env vars for some container control env_vars = JSONField('Container env vars', blank=True, null=True) class Meta: ordering = ['name'] Loading services/webapp/code/rosetta/core_app/templates/add_software.html +7 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,13 @@ </td> </tr> <tr> <td><b>Environment variables</b></td> <td> <textarea name="container_env_vars" rows="2" cols="22" placeholder='JSON format: {"VAR"="VALUE"}'></textarea> </td> </tr> </table> </div> Loading services/webapp/code/rosetta/core_app/templates/components/container.html +6 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,12 @@ {% endif %} </td> </tr> {% if container.env_vars %} <tr> <td><b>Env vars</b></td> <td><pre>{{container.env_vars}}</pre></td> </tr> {% endif %} {% if container.user %} <tr> Loading Loading
services/webapp/code/rosetta/core_app/computing_managers.py +48 −6 Original line number Diff line number Diff line from .models import TaskStatuses, KeyPair, Task, Storage from .utils import os_shell, get_ssh_access_mode_credentials from .utils import os_shell, get_ssh_access_mode_credentials, sanitize_container_env_vars from .exceptions import ErrorMessage, ConsistencyException from django.conf import settings Loading Loading @@ -107,6 +107,15 @@ class InternalStandaloneComputingManager(StandaloneComputingManager): if not task.requires_proxy and task.password: run_command += ' -eAUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: run_command += ' -e{}={} '.format(env_var, env_vars[env_var]) # User data volume #run_command += ' -v {}/user-{}:/data'.format(settings.LOCAL_USER_DATA_DIR, task.user.id) Loading Loading @@ -204,7 +213,18 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana # Set pass if any authstring = '' if not task.requires_proxy_auth and task.password: authstring = ' export SINGULARITYENV_AUTH_PASS={} && '.format(task.password) authstring = ' && export SINGULARITYENV_AUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: varsstring = '' # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: varsstring += ' && export SINGULARITYENV_{}={} '.format(env_var, env_vars[env_var]) else: varsstring = '' # Handle storages (binds) binds = '' Loading Loading @@ -241,7 +261,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana run_command = 'ssh -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_keys.private_key_file, computing_user, computing_host) run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir -p /tmp/{}_data/tmp && mkdir -p /tmp/{}_data/home && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'wget {}/api/v1/base/agent/?task_uuid={} -O /tmp/{}_data/agent.py &> /dev/null && export BASE_PORT=\$(python /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\$BASE_PORT && {} '.format(authstring) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\$BASE_PORT {} {} &&'.format(authstring, varsstring) run_command += 'exec nohup singularity run {} --pid --writable-tmpfs --no-home --home=/home/metauser --workdir /tmp/{}_data/tmp -B/tmp/{}_data/home:/home --containall --cleanenv '.format(binds, task.uuid, task.uuid) # Container part Loading @@ -255,6 +275,17 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana if not task.requires_proxy_auth and task.password: authstring = ' -e AUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: varsstring = '' # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: varsstring += ' -e {}={} '.format(env_var, env_vars[env_var]) else: varsstring = '' # Handle storages (binds) binds = '' storages = Storage.objects.filter(computing=self.computing) Loading Loading @@ -293,7 +324,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana run_command = 'ssh -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_keys.private_key_file, computing_user, computing_host) run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir /tmp/{}_data && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid) run_command += 'wget {}/api/v1/base/agent/?task_uuid={} -O /tmp/{}_data/agent.py &> /dev/null && export TASK_PORT=\$(python /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid) run_command += '{} {} run -p \$TASK_PORT:{} {} {} '.format(prefix, container_engine, task.container.interface_port, authstring, binds) run_command += '{} {} run -p \$TASK_PORT:{} {} {} {} '.format(prefix, container_engine, task.container.interface_port, authstring, varsstring, binds) if container_engine == 'podman': run_command += '--network=private --uts=private ' #run_command += '-d -t {}/{}:{}'.format(task.container.registry, task.container.image_name, task.container.image_tag) Loading Loading @@ -435,7 +466,18 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag # Set pass if any authstring = '' if not task.requires_proxy_auth and task.password: authstring = ' export SINGULARITYENV_AUTH_PASS={} && '.format(task.password) authstring = ' && export SINGULARITYENV_AUTH_PASS={} '.format(task.password) # Env vars if any if task.container.env_vars: varsstring = '' # Sanitize again just in case the DB got somehow compromised: env_vars = sanitize_container_env_vars(task.container.env_vars) for env_var in env_vars: varsstring += ' && export SINGULARITYENV_{}={} '.format(env_var, env_vars[env_var]) else: varsstring = '' # Handle storages (binds) binds = '' Loading Loading @@ -471,7 +513,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag run_command = 'ssh -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_keys.private_key_file, computing_user, computing_host) run_command += '\'bash -c "echo \\"#!/bin/bash\nwget {}/api/v1/base/agent/?task_uuid={} -O \$HOME/agent_{}.py &> \$HOME/{}.log && export BASE_PORT=\\\\\\$(python \$HOME/agent_{}.py 2> \$HOME/{}.log) && '.format(webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\\\\\\$BASE_PORT && {} '.format(authstring) run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\\\\\\$BASE_PORT {} {} && '.format(authstring, varsstring) run_command += 'rm -rf /tmp/{}_data && mkdir -p /tmp/{}_data/tmp &>> \$HOME/{}.log && mkdir -p /tmp/{}_data/home &>> \$HOME/{}.log && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid, task.uuid, task.uuid, task.uuid) run_command += 'exec nohup singularity run {} --pid --writable-tmpfs --no-home --home=/home/metauser --workdir /tmp/{}_data/tmp -B/tmp/{}_data/home:/home --containall --cleanenv '.format(binds, task.uuid, task.uuid) Loading
services/webapp/code/rosetta/core_app/migrations/0031_container_env_vars.py 0 → 100644 +25 −0 Original line number Diff line number Diff line # Generated by Django 2.2.1 on 2022-01-16 18:40 from django.conf import settings from django.db import migrations # Load database-dependent JSON field if 'sqlite' in settings.DATABASES['default']['ENGINE']: from rosetta.core_app.fields import JSONField else: from django.contrib.postgres.fields import JSONField class Migration(migrations.Migration): dependencies = [ ('core_app', '0030_auto_20211218_2355'), ] operations = [ migrations.AddField( model_name='container', name='env_vars', field=JSONField(blank=True, null=True, verbose_name='Container env vars'), ), ]
services/webapp/code/rosetta/core_app/models.py +3 −0 Original line number Diff line number Diff line Loading @@ -141,6 +141,9 @@ class Container(models.Model): supports_interface_auth = models.BooleanField('Supports interface auth', default=False) # AUTH_USER / AUTH_PASS interface_auth_user = models.CharField('Interface auth fixed user if any', max_length=36, blank=True, null=True) # Env vars for some container control env_vars = JSONField('Container env vars', blank=True, null=True) class Meta: ordering = ['name'] Loading
services/webapp/code/rosetta/core_app/templates/add_software.html +7 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,13 @@ </td> </tr> <tr> <td><b>Environment variables</b></td> <td> <textarea name="container_env_vars" rows="2" cols="22" placeholder='JSON format: {"VAR"="VALUE"}'></textarea> </td> </tr> </table> </div> Loading
services/webapp/code/rosetta/core_app/templates/components/container.html +6 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,12 @@ {% endif %} </td> </tr> {% if container.env_vars %} <tr> <td><b>Env vars</b></td> <td><pre>{{container.env_vars}}</pre></td> </tr> {% endif %} {% if container.user %} <tr> Loading