From aefaca3d27bf61698a444a192355ece82847e617 Mon Sep 17 00:00:00 2001 From: Stefano Alberto Russo <stefano.russo@gmail.com> Date: Thu, 14 May 2020 14:25:21 +0200 Subject: [PATCH] Added support for setting task extra volumes at runtime. --- .../rosetta/core_app/computing_managers.py | 29 +++++++++++++++++-- .../webapp/code/rosetta/core_app/models.py | 1 + .../core_app/templates/components/task.html | 12 ++++---- .../core_app/templates/create_task.html | 15 ++++++++-- .../webapp/code/rosetta/core_app/views.py | 8 +++-- 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/services/webapp/code/rosetta/core_app/computing_managers.py b/services/webapp/code/rosetta/core_app/computing_managers.py index b9a5936..0aeee44 100644 --- a/services/webapp/code/rosetta/core_app/computing_managers.py +++ b/services/webapp/code/rosetta/core_app/computing_managers.py @@ -134,7 +134,10 @@ class LocalComputingManager(ComputingManager): out = os_shell(stop_command, capture=True) if out.exit_code != 0: - raise Exception(out.stderr) + if 'No such container' in out.stderr: + pass + else: + raise Exception(out.stderr) # Set task as stopped task.status = TaskStatuses.stopped @@ -194,7 +197,14 @@ class RemoteComputingManager(ComputingManager): bindings = '' else: bindings = '-B {}'.format(bindings) - + + # Manage task extra volumes + if task.extra_volumes: + if not bindings: + bindings = '-B {}'.format(task.extra_volumes) + else: + bindings += ',{}'.format(task.extra_volumes) + run_command = 'ssh -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(user_keys.private_key_file, user, host) run_command += '/bin/bash -c \'"wget {}/api/v1/base/agent/?task_uuid={} -O \$HOME/agent_{}.py &> /dev/null && export BASE_PORT=\$(python \$HOME/agent_{}.py 2> \$HOME/{}.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) @@ -345,8 +355,14 @@ class SlurmComputingManager(ComputingManager): else: bindings = '-B {}'.format(bindings) - run_command = 'ssh -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(user_keys.private_key_file, user, host) + # Manage task extra volumes + if task.extra_volumes: + if not bindings: + bindings = '-B {}'.format(task.extra_volumes) + else: + bindings += ',{}'.format(task.extra_volumes) + run_command = 'ssh -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(user_keys.private_key_file, user, 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 += 'exec nohup singularity run {} --pid --writable-tmpfs --containall --cleanenv '.format(bindings) @@ -492,6 +508,13 @@ class RemotehopComputingManager(ComputingManager): else: bindings = '-B {}'.format(bindings) + # Manage task extra volumes + if task.extra_volumes: + if not bindings: + bindings = '-B {}'.format(task.extra_volumes) + else: + bindings += ',{}'.format(task.extra_volumes) + run_command = 'ssh -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(user_keys.private_key_file, first_user, first_host) run_command += '"ssh -4 -o StrictHostKeyChecking=no {}@{} /bin/bash -c \''.format(second_user, second_host) diff --git a/services/webapp/code/rosetta/core_app/models.py b/services/webapp/code/rosetta/core_app/models.py index 05d9979..933ba01 100644 --- a/services/webapp/code/rosetta/core_app/models.py +++ b/services/webapp/code/rosetta/core_app/models.py @@ -272,6 +272,7 @@ class Task(models.Model): port = models.IntegerField('Task port', blank=True, null=True) ip = models.CharField('Task ip address', max_length=36, blank=True, null=True) tunnel_port = models.IntegerField('Task tunnel port', blank=True, null=True) + extra_volumes = models.CharField('Extra volumes', max_length=4096, blank=True, null=True) # Links computing = models.ForeignKey(Computing, related_name='+', on_delete=models.CASCADE) diff --git a/services/webapp/code/rosetta/core_app/templates/components/task.html b/services/webapp/code/rosetta/core_app/templates/components/task.html index 90e6247..bc0f165 100644 --- a/services/webapp/code/rosetta/core_app/templates/components/task.html +++ b/services/webapp/code/rosetta/core_app/templates/components/task.html @@ -46,10 +46,10 @@ <td>{{ task.computing }}</td> </tr> - <!-- <tr> - <td><b>Task pid</b></td> - <td>{{ task.pid}}</td> - </tr> --> + <tr> + <td><b>Extra volumes</b></td> + <td>{{ task.extra_volumes }}</td> + </tr> <tr> <td><b>IP</b></td> @@ -72,7 +72,9 @@ <td>******</td> </tr> {% endif %} - + + + <tr> <td><b>Operations</b></td> diff --git a/services/webapp/code/rosetta/core_app/templates/create_task.html b/services/webapp/code/rosetta/core_app/templates/create_task.html index f7fb9bc..4c0b303 100644 --- a/services/webapp/code/rosetta/core_app/templates/create_task.html +++ b/services/webapp/code/rosetta/core_app/templates/create_task.html @@ -135,7 +135,7 @@ <td valign="top" style="width:180px"><b>Set custom port </b></td> <td> <input type="text" name="task_base_port" value="" placeholder="" size="23" style="margin-bottom:5px"/><br> - <p style="line-height: 0.9"><font size=-1>This container supports dynamic ports and you can thus set a custom port (>5900) to avoid clashes with services already running on the computing resource.</font></p> + <p style="line-height: 0.95"><font size=-1>This container supports dynamic ports and you can thus set a custom port (>5900) to avoid clashes with services already running on the computing resource.</font></p> </td> </tr> {% endif %} @@ -150,6 +150,17 @@ </tr> {% endif %} + + {% if data.task_container.type == 'singularity' %} + <tr> + <td valign="top" style="width:180px"><b>Extra volumes</b></td> + <td> + <input type="text" name="extra_volumes" value="" placeholder="" size="23" /><br> + <p style="line-height: 0.95"><font size=-1>Here you can set extra volume bindings on top of the ones already define by the administrator. Format is <i>host_directory:container_directory</i>, comma separated.</font></p> + </td> + </tr> + {% endif %} + <tr> <td><b>Access method</b></td><td> <select name="access_method" > @@ -184,7 +195,7 @@ <tr><td colspan=2> <table><tr><td style="border: 1px solid lightgray;" > - I understand that files saved or modified in this container, if not explicitly saved to a persistent storage, will be LOST when the task ends. + I understand that files saved or modified in this container, if not explicitly saved to a persistent volume, will be LOST when the task ends. </td><td style="border: 1px solid lightgray;" > <input class="form-check-input" type="checkbox" value="" id="invalidCheck" required> </td></table> diff --git a/services/webapp/code/rosetta/core_app/views.py b/services/webapp/code/rosetta/core_app/views.py index 3e710b8..c3fb5ce 100644 --- a/services/webapp/code/rosetta/core_app/views.py +++ b/services/webapp/code/rosetta/core_app/views.py @@ -553,14 +553,15 @@ def create_task(request): if task_base_port: task.port = task_base_port - # Cheks + # Checks if task.auth_pass and len(task.auth_pass) < 6: raise ErrorMessage('Task password must be at least 6 chars') - # Computing options # TODO: This is hardcoded thinking about Slurm + # Computing options # TODO: This is hardcoded thinking about Slurm and Singularity computing_cpus = request.POST.get('computing_cpus', None) computing_memory = request.POST.get('computing_memory', None) computing_partition = request.POST.get('computing_partition', None) + extra_volumes = request.POST.get('extra_volumes', None) computing_options = {} if computing_cpus: @@ -586,6 +587,9 @@ def create_task(request): if not task.container.supports_dynamic_ports: if task.container.ports: task.port = task.container.port + + # Set exttra volumes if any: + task.extra_volumes = extra_volumes # Save the task before starting it, or the computing manager will not be able to work properly task.save() -- GitLab