Skip to content

Commits on Source 5

......@@ -44,3 +44,4 @@ class RosettaOIDCAuthenticationCallbackView(OIDCAuthenticationCallbackView):
logger.debug('No cookie-based post login redirect found, redirecting to "%s"', self.success_url)
return HttpResponseRedirect(self.success_url)
......@@ -1333,3 +1333,4 @@ class ImportRepositoryAPI(PrivateGETAPI):
import os
from .models import TaskStatuses, KeyPair, Task, Storage
from .utils import os_shell, get_ssh_access_mode_credentials, sanitize_container_env_vars, booleanize
from .utils import os_shell, get_ssh_access_mode_credentials, sanitize_container_env_vars, booleanize, setup_tunnel_and_proxy
from .exceptions import ErrorMessage, ConsistencyException
from django.conf import settings
......@@ -9,7 +9,7 @@ import logging
logger = logging.getLogger(__name__)
ROSETTA_AGENT_CHECK_SSL = booleanize(os.environ.get('ROSETTA_AGENT_CHECK_SSL', True))
CHECK_WGET_CERT_STR = '--no-check-certificate' if not ROSETTA_AGENT_CHECK_SSL else ''
CHECK_CURL_CERT_STR = '--insecure' if not ROSETTA_AGENT_CHECK_SSL else ''
class ComputingManager(object):
......@@ -131,8 +131,30 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
# User data volume
#run_command += ' -v {}/user-{}:/data'.format(settings.LOCAL_USER_DATA_DIR, task.user.id)
# Handle storages (binds)
binds = ''
storages = Storage.objects.filter(computing=self.computing)
for storage in storages:
if storage.type == 'generic_posix' and storage.bind_path:
# Expand the base path
expanded_base_path = storage.base_path
if '$USER' in expanded_base_path:
expanded_base_path = expanded_base_path.replace('$USER', task.user.username)
# Expand the bind_path
expanded_bind_path = storage.bind_path
if '$USER' in expanded_bind_path:
expanded_bind_path = expanded_bind_path.replace('$USER', task.user.username)
# Add the bind
if not binds:
binds = '-v{}:{}'.format(expanded_base_path, expanded_bind_path)
else:
binds += ' -v{}:{}'.format(expanded_base_path, expanded_bind_path)
# Host name, image entry command
run_command += ' -h task-{} --name task-{} -d -t {}/{}:{}'.format(task.short_uuid, task.short_uuid, task.container.registry, task.container.image_name, task.container.image_tag)
run_command += ' {} -h task-{} --name task-{} -d -t {}/{}:{}'.format(binds, task.short_uuid, task.short_uuid, task.container.registry, task.container.image_name, task.container.image_tag)
# Debug
logger.debug('Running new task with command="{}"'.format(run_command))
......@@ -158,6 +180,10 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
# Save
task.save()
# Setup the tunnel if using a custom protocol (otherwise it will get set up via the "connect" button)
if task.container.interface_protocol not in ['http', 'https']:
setup_tunnel_and_proxy(task)
def _stop_task(self, task):
# Delete the Docker container
......@@ -166,6 +192,10 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
out = os_shell(stop_command, capture=True)
if out.exit_code != 0:
if 'No such container' in out.stderr:
# No container was found
pass
elif 'requires at least 1 argument' in out.stderr:
# No container was found
pass
else:
raise Exception(out.stderr)
......@@ -263,7 +293,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
run_command = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_port, 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(CHECK_WGET_CERT_STR, webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid)
run_command += 'curl {} {}/api/v1/base/agent/?task_uuid={} -o /tmp/{}_data/agent.py &> /dev/null && export BASE_PORT=\$(python3 /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(CHECK_CURL_CERT_STR, 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, 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)
......@@ -326,7 +356,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
run_command = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_port, 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(CHECK_WGET_CERT_STR, webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid)
run_command += 'curl {} {}/api/v1/base/agent/?task_uuid={} -o /tmp/{}_data/agent.py &> /dev/null && export TASK_PORT=\$(python3 /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(CHECK_CURL_CERT_STR, webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid)
run_command += 'exec nohup {} {} 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 --userns=keep-id '
......@@ -356,6 +386,10 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
# Save
task.save()
# Setup the tunnel if using a custom protocol (otherwise it will get set up via the "connect" button)
if task.container.interface_protocol not in ['http', 'https']:
setup_tunnel_and_proxy(task)
def _stop_task(self, task, **kwargs):
......@@ -519,7 +553,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
binds += ',{}:{}'.format(expanded_base_path, expanded_bind_path)
run_command = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_port, 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(CHECK_WGET_CERT_STR, webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid, task.uuid)
run_command += '\'bash -c "echo \\"#!/bin/bash\ncurl {} {}/api/v1/base/agent/?task_uuid={} -o \$HOME/agent_{}.py &> \$HOME/{}.log && export BASE_PORT=\\\\\\$(python3 \$HOME/agent_{}.py 2> \$HOME/{}.log) && '.format(CHECK_CURL_CERT_STR, 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, 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)
......@@ -559,6 +593,9 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
# Save
task.save()
# Setup the tunnel if using a custom protocol (otherwise it will get set up via the "connect" button)
if task.container.interface_protocol not in ['http', 'https']:
setup_tunnel_and_proxy(task)
def _stop_task(self, task, **kwargs):
......@@ -590,4 +627,3 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
else:
return out.stdout
......@@ -137,3 +137,4 @@ def private_view(wrapped_view):
response.set_cookie('post_login_redirect', request.build_absolute_uri())
return response
return private_view_wrapper
......@@ -359,3 +359,4 @@ to provide help, news and informations on your deployment. Or you can just ignor
base_path = '/shared/data/users/$SSH_USER',
bind_path = '/storages/personal')
......@@ -398,6 +398,10 @@ class Storage(models.Model):
# Include as browsable in the file manager?
browsable = models.BooleanField('Browsable in the file manager?', default=True)
def save(self, *args, **kwargs):
if self.access_mode == 'internal' and self.browsable:
raise ValueError('A storage with "internal" access mode cannot be marked as browsable since it is not yet supported by the file manager')
super(Storage, self).save(*args, **kwargs)
class Meta:
ordering = ['name']
......@@ -457,3 +461,4 @@ class Page(models.Model):
@keyframes spin {
to {
transform: rotate(360deg);
}
}
#navigate-away-loader {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
color: white;
transition: opacity 0.4s ease-in-out;
visibility: hidden;
pointer-events: none;
display: flex;
& > svg {
animation: spin 1.5s infinite linear;
opacity: 0.5;
}
}
function showNavigationLoader() {
var navigationLoader = document.querySelector("#navigate-away-loader")
navigationLoader.style.visibility = "visible"
navigationLoader.style.opacity = 1
navigationLoader.style.pointerEvents = "all"
document.querySelector("#navigate-away-loader > svg").style.animation =
"spin 1.5s infinite linear"
}
function hideNavigationLoader() {
var navigationLoader = document.querySelector("#navigate-away-loader")
navigationLoader.style.visibility = "hidden"
navigationLoader.style.opacity = 0
navigationLoader.style.pointerEvents = "none"
}
window.addEventListener("beforeunload", function (e) {
showNavigationLoader()
return true
})
window.addEventListener("pageshow", function (e) {
hideNavigationLoader()
})