Commit 3a54c605 authored by Stefano Alberto Russo's avatar Stefano Alberto Russo
Browse files

Parametrized remote tasks host and access key. Added container name. Global...

Parametrized remote tasks host and access key. Added container name. Global refactoring and cleanup.
parent d0b24086
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
from django.contrib import admin

from .models import Profile, LoginToken, Task, Container
from .models import Profile, LoginToken, Task, Container, Computing, ComputingSysConf, ComputingUserConf

admin.site.register(Profile)
admin.site.register(LoginToken)
admin.site.register(Task)
admin.site.register(Container)
admin.site.register(Computing)
admin.site.register(ComputingSysConf)
admin.site.register(ComputingUserConf)
 No newline at end of file
+2 −8
Original line number Diff line number Diff line
import logging
 
# Django imports
from django.http import HttpResponse
from django.utils import timezone
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User, Group

from rest_framework.response import Response
from rest_framework import status, serializers, viewsets
from rest_framework.views import APIView

 
# Project imports
from rosetta.common import format_exception
from rosetta.base_app.models import Profile
from .utils import format_exception
from .models import Profile
 
# Setup logging
logger = logging.getLogger(__name__)
+140 −0
Original line number Diff line number Diff line
# Imports
import inspect
from django.conf import settings
from django.shortcuts import render
from django.http import HttpResponse
from .utils import format_exception, log_user_activity
from .exceptions import ErrorMessage, ConsistencyException

# Setup logging
import logging
logger = logging.getLogger(__name__)

# Conf
SUPPORTED_CONTAINER_TYPES = ['docker', 'singularity']
SUPPORTED_REGISTRIES = ['docker_local', 'docker_hub', 'singularity_hub']
UNSUPPORTED_TYPES_VS_REGISTRIES = ['docker:singularity_hub']


# Public view
def public_view(wrapped_view):
    def public_view_wrapper(request, *argv, **kwargs):
        # -------------- START Public/private common code --------------
        try:
            log_user_activity("DEBUG", "Called", request, wrapped_view.__name__)

            # Try to get the templates from view kwargs
            # Todo: Python3 compatibility: https://stackoverflow.com/questions/2677185/how-can-i-read-a-functions-signature-including-default-argument-values

            argSpec=inspect.getargspec(wrapped_view)

            if 'template' in argSpec.args:
                template = argSpec.defaults[0]
            else:
                template = None

            # Call wrapped view
            data = wrapped_view(request, *argv, **kwargs)

            if not isinstance(data, HttpResponse):
                if template:
                    #logger.debug('using template + data ("{}","{}")'.format(template,data))
                    return render(request, template, {'data': data})
                else:
                    raise ConsistencyException('Got plain "data" output but no template defined in view')
            else:
                #logger.debug('using returned httpresponse')
                return data

        except Exception as e:
            if isinstance(e, ErrorMessage):
                error_text = str(e)
            else:

                # Raise te exception if we are in debug mode
                if settings.DEBUG:
                    raise

                # Otherwise,
                else:

                    # first log the exception
                    logger.error(format_exception(e))

                    # and then mask it.
                    error_text = 'something went wrong'

            data = {'user': request.user,
                    'title': 'Error',
                    'error' : 'Error: "{}"'.format(error_text)}

            if template:
                return render(request, template, {'data': data})
            else:
                return render(request, 'error.html', {'data': data})
        # --------------  END Public/private common code --------------
    return public_view_wrapper

# Private view
def private_view(wrapped_view):
    def private_view_wrapper(request, *argv, **kwargs):
        if request.user.is_authenticated:
            # -------------- START Public/private common code --------------
            log_user_activity("DEBUG", "Called", request, wrapped_view.__name__)
            try:

                # Try to get the templates from view kwargs
                # Todo: Python3 compatibility: https://stackoverflow.com/questions/2677185/how-can-i-read-a-functions-signature-including-default-argument-values

                argSpec=inspect.getargspec(wrapped_view)

                if 'template' in argSpec.args:
                    template = argSpec.defaults[0]
                else:
                    template = None

                # Call wrapped view
                data = wrapped_view(request, *argv, **kwargs)

                if not isinstance(data, HttpResponse):
                    if template:
                        #logger.debug('using template + data ("{}","{}")'.format(template,data))
                        return render(request, template, {'data': data})
                    else:
                        raise ConsistencyException('Got plain "data" output but no template defined in view')
                else:
                    #logger.debug('using returned httpresponse')
                    return data

            except Exception as e:
                if isinstance(e, ErrorMessage):
                    error_text = str(e)
                else:

                    # Raise te exception if we are in debug mode
                    if settings.DEBUG:
                        raise

                    # Otherwise,
                    else:

                        # first log the exception
                        logger.error(format_exception(e))

                        # and then mask it.
                        error_text = 'something went wrong'

                data = {'user': request.user,
                        'title': 'Error',
                        'error' : 'Error: "{}"'.format(error_text)}

                if template:
                    return render(request, template, {'data': data})
                else:
                    return render(request, 'error.html', {'data': data})
            # --------------  END  Public/private common code --------------

        else:
            log_user_activity("DEBUG", "Redirecting to login since not authenticated", request)
            return HttpResponseRedirect('/login')
    return private_view_wrapper
+20 −3
Original line number Diff line number Diff line
@@ -42,13 +42,23 @@ class Command(BaseCommand):
            
            # MetaDesktop Docker
            Container.objects.create(user          = None,
                                     name          = 'MetaDesktop latest',
                                     image         = 'rosetta/metadesktop',
                                     type          = 'docker',
                                     registry      = 'docker_local',
                                     service_ports = '8590')

            # MetaDesktop Singularity
            Container.objects.create(user          = None,
                                     name          = 'MetaDesktop latest',
                                     image         = 'rosetta/metadesktop',
                                     type          = 'singularity',
                                     registry      = 'docker_local',
                                     service_ports = '8590')

            # Astrocook
            Container.objects.create(user          = None,
                                     name          = 'Astrocook b2b819e',
                                     image         = 'sarusso/astrocook:b2b819e',
                                     type          = 'docker',
                                     registry      = 'docker_local',
@@ -64,6 +74,7 @@ class Command(BaseCommand):
            
            # JuPyter
            Container.objects.create(user          = testuser,
                                     name          = 'Jupyter Notebook latest',
                                     image         = 'jupyter/base-notebook',
                                     type          = 'docker',
                                     registry      = 'docker_hub',
@@ -90,9 +101,15 @@ class Command(BaseCommand):
    
            # Create demo remote sys computing conf
            ComputingSysConf.objects.create(computing = demo_remote_computing,
                                            data      = {'host': 'slurmclusterworker-one',
                                                         'user': 'rosetta',
                                                         'identity': 'privkey?'})
                                            data      = {'host': 'slurmclusterworker-one'})

            # Create demo remote user computing conf
            ComputingUserConf.objects.create(user      = testuser,
                                             computing = demo_remote_computing,
                                             data      = {'user': 'testuser',
                                                          'id_rsa': '/rosetta/.ssh/id_rsa',
                                                          'id_rsa.pub': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC2n4wiLiRmE1sla5+w0IW3wwPW/mqhhkm7IyCBS+rGTgnts7xsWcxobvamNdD6KSLNnjFZbBb7Yaf/BvWrwQgdqIFVU3gRWHYzoU6js+lKtBjd0e2DAVGivWCKEkSGLx7zhx7uH/Jt8kyZ4NaZq0p5+SFHBzePdR/1rURd8G8+G3OaCPKqP+JQT4RMUQHC5SNRJLcK1piYdmhDiYEyuQG4FlStKCWLCXeUY2EVirNMeQIfOgbUHJsVjH07zm1y8y7lTWDMWVZOnkG6Ap5kB+n4l1eWbslOKgDv29JTFOMU+bvGvYZh70lmLK7Hg4CMpXVgvw5VF9v97YiiigLwvC7wasBHaASwH7wUqakXYhdGFxJ23xVMSLnvJn4S++4L8t8bifRIVqhT6tZCPOU4fdOvJKCRjKrf7gcW/E33ovZFgoOCJ2vBLIh9N9ME0v7tG15JpRtgIBsCXwLcl3tVyCZJ/eyYMbc3QJGsbcPGb2CYRjDbevPCQlNavcMdlyrNIke7VimM5aW8OBJKVh5wCNRpd9XylrKo1cZHYxu/c5Lr6VUZjLpxDlSz+IuTn4VE7vmgHNPnXdlxRKjLHG/FZrZTSCWFEBcRoSa/hysLSFwwDjKd9nelOZRNBvJ+NY48vA8ixVnk4WAMlR/5qhjTRam66BVysHeRcbjJ2IGjwTJC5Q== rosetta@rosetta.platform'})



            # Demo slurm computing resource
+37 −10
Original line number Diff line number Diff line
import uuid
import enum

from django.conf import settings
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone

from .utils import os_shell

if 'sqlite' in settings.DATABASES['default']['ENGINE']:
@@ -72,6 +69,7 @@ class Container(models.Model):
    user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE, null=True)  
    # If a container has no user, it will be available to anyone. Can be created, edited and deleted only by admins.

    name          = models.CharField('Container Name', max_length=255, blank=False, null=False)    
    image         = models.CharField('Container image', max_length=255, blank=False, null=False)
    type          = models.CharField('Container type', max_length=36, blank=False, null=False)
    registry      = models.CharField('Container registry', max_length=255, blank=False, null=False)
@@ -79,7 +77,7 @@ class Container(models.Model):
    #private       = models.BooleanField('Container is private and needs auth to be pulled from the registry')

    def __str__(self):
        return str('Container of type "{}" with image "{}" from registry "{}" of user "{}"'.format(self.type, self.image, self.registry, self.user))
        return str('Container of type "{}" with image "{}" with service ports "{}" from registry "{}" of user "{}"'.format(self.type, self.image, self.service_ports, self.registry, self.user))

    @property
    def id(self):
@@ -159,15 +157,39 @@ class Computing(models.Model):
    def sys_conf_data(self):          
        return ComputingSysConf.objects.get(computing=self).data
    
    #@property    
    #def user_conf_data(self):
    #    return {'testuser':'ciao'}
    @property    
    def user_conf_data(self):
        try:
            return self._user_conf_data
        except AttributeError:
            raise AttributeError('User conf data is not yet attached, please attach it before accessing.')
    
    def attach_user_conf_data(self, user):
        if self.user and self.user != user:
            raise Exception('Cannot attach a conf data for another user (my user="{}", another user="{}"'.format(self.user, user)) 
        try:
            self.user_conf_data = ComputingUserConf.objects.get(computing=self).data
            self._user_conf_data = ComputingUserConf.objects.get(computing=self, user=user).data
        except ComputingUserConf.DoesNotExist:
            self.user_conf_data = None
            self._user_conf_data = None

    # Get id_rsa file
    #@property
    #def id_rsa_file(self):
    #    try:
    #        id_rsa_file = self.user_conf_data['id_rsa']
    #    except (TypeError, KeyError, AttributeError):
    #        try:
    #            id_rsa_file = self.sys_conf_data['id_rsa']
    #        except:
    #            id_rsa_file = None
    #    return id_rsa_file

    def get_conf_param(self, param):
        try:
            param_value = self.sys_conf_data[param]
        except (TypeError, KeyError):
            param_value = self.user_conf_data[param]
        return param_value


class ComputingSysConf(models.Model):
@@ -210,6 +232,11 @@ class Task(models.Model):
    computing = models.ForeignKey(Computing, related_name='+', on_delete=models.CASCADE)
    container = models.ForeignKey('Container', on_delete=models.CASCADE, related_name='+')

    # Auth
    auth_user     = models.CharField('Task auth user', max_length=36, blank=True, null=True)
    auth_password = models.CharField('Task auth password', max_length=36, blank=True, null=True)
    access_method = models.CharField('Task access method', max_length=36, blank=True, null=True)

    def save(self, *args, **kwargs):
        
        try:
Loading