Skip to content
Snippets Groups Projects
Commit 2cfb340a authored by Stefano Alberto Russo's avatar Stefano Alberto Russo
Browse files

Added first stub for the Computing model.

parent afbaafc7
No related branches found
No related tags found
No related merge requests found
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.contrib.auth.models import User from django.contrib.auth.models import User
from ...models import Profile, Container from ...models import Profile, Container, Computing
class Command(BaseCommand): class Command(BaseCommand):
help = 'Adds the admin superuser with \'a\' password.' help = 'Adds the admin superuser with \'a\' password.'
...@@ -71,9 +71,20 @@ class Command(BaseCommand): ...@@ -71,9 +71,20 @@ class Command(BaseCommand):
# Computing resources
#Computing.objects.create(user = None,
# name = 'L',
# type = '')
# Computing resources
#Computing.objects.create(user = None,
# name = 'L',
# type = '')
# Computing resources
#Computing.objects.create(user = None,
# name = 'L',
# type = '')
...@@ -49,20 +49,70 @@ class LoginToken(models.Model): ...@@ -49,20 +49,70 @@ class LoginToken(models.Model):
token = models.CharField('Login token', max_length=36) token = models.CharField('Login token', max_length=36)
#=========================
# Containers
#=========================
class Container(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
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.
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)
service_ports = models.CharField('Container service ports', max_length=36, blank=True, null=True)
#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))
@property
def id(self):
return str(self.uuid).split('-')[0]
#@property
#def name(self):
# return self.image.split(':')[0].replace('_',' ').replace('-', ' ').replace('/', ' ').title()
#=========================
# Computing resources
#=========================
# TODO: this must be an abstract class. Or maybe not? Maybe Add ComputingConfiguration/Handler with the relevant fields and methods?
# ...so that can be used as foreign key in the tasks as well? Examples: ComputingConfiguration ComputingType ComputingHandler
class Computing(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE, null=True)
# If a compute resource has no user, it will be available to anyone. Can be created, edited and deleted only by admins.
name = models.CharField('Computing Name', max_length=255, blank=False, null=False)
def __str__(self):
return str('Computing Resource "{}" of user "{}"'.format(self.name, self.user))
@property
def id(self):
return str(self.uuid).split('-')[0]
#========================= #=========================
# Tasks # Tasks
#========================= #=========================
class Task(models.Model): class Task(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE) user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE)
tid = models.CharField('Task ID', max_length=64, blank=False, null=False) tid = models.CharField('Task ID', max_length=64, blank=False, null=False)
name = models.CharField('Task name', max_length=36, blank=False, null=False) name = models.CharField('Task name', max_length=36, blank=False, null=False)
status = models.CharField('Task status', max_length=36, blank=True, null=True) status = models.CharField('Task status', max_length=36, blank=True, null=True)
created = models.DateTimeField('Created on', default=timezone.now) created = models.DateTimeField('Created on', default=timezone.now)
compute = models.CharField('Task compute', max_length=36, blank=True, null=True) computing = models.ForeignKey(Computing, related_name='+', on_delete=models.CASCADE)
pid = models.IntegerField('Task pid', blank=True, null=True) pid = models.IntegerField('Task pid', blank=True, null=True)
port = models.IntegerField('Task port', blank=True, null=True) port = models.IntegerField('Task port', blank=True, null=True)
ip = models.CharField('Task ip address', max_length=36, 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) tunnel_port = models.IntegerField('Task tunnel port', blank=True, null=True)
# Links # Links
...@@ -84,7 +134,7 @@ class Task(models.Model): ...@@ -84,7 +134,7 @@ class Task(models.Model):
def update_status(self): def update_status(self):
if self.compute == 'local': if self.computing == 'local':
check_command = 'sudo docker inspect --format \'{{.State.Status}}\' ' + self.tid # or, .State.Running check_command = 'sudo docker inspect --format \'{{.State.Status}}\' ' + self.tid # or, .State.Running
out = os_shell(check_command, capture=True) out = os_shell(check_command, capture=True)
...@@ -111,30 +161,4 @@ class Task(models.Model): ...@@ -111,30 +161,4 @@ class Task(models.Model):
#=========================
# Containers
#=========================
class Container(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
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.
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)
service_ports = models.CharField('Container service ports', max_length=36, blank=True, null=True)
#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))
@property
def id(self):
return str(self.uuid).split('-')[0]
#@property
#def name(self):
# return self.image.split(':')[0].replace('_',' ').replace('-', ' ').replace('/', ' ').title()
{% load static %}
{% include "header.html" %}
{% include "navigation.html" with main_path='/main/' %}
<br/>
<br/>
<div class="container">
<div class="dashboard">
<div class="span8 offset2">
{% if data.computing %}
<h1><a href="/computings">Computing Resources List</a> &gt; {{ data.computing.id }} </h1>
{% else %}
<h1>Computing Resources List</h1>
{% endif %}
<hr/>
{% if data.computing %}
{% include "components/computing.html" with computing=data.computing %}
{% else %}
{% for computing in data.platform_computings %}
{% include "components/computing.html" with computing=computing %}
<br />
{% endfor %}
{% for computing in data.user_computings %}
{% include "components/computing.html" with computing=computing %}
<br />
{% endfor %}
<br />
<a href="/add_computing">Add new...</a>
{% endif %}
<br />
<br />
<br />
<br />
</div>
</div>
</div>
{% include "footer.html" %}
...@@ -64,12 +64,12 @@ ...@@ -64,12 +64,12 @@
<tr> <tr>
<td><b>Computing resource</b></td><td> <td><b>Computing resource</b></td><td>
<select name="task_compute" > <select name="task_computing" >
<option value="local" selected>Local</option> <option value="local" selected>Local</option>
<option value="demoremote">Demo remote</option> <option value="demoremote">Demo remote</option>
<option value="demoslurm">Demo Slurm cluster</option> <option value="demoslurm">Demo Slurm cluster</option>
</select> </select>
&nbsp; | <a href="/add_compute">Add new...</a> &nbsp; | <a href="/add_computing">Add new...</a>
</td> </td>
</tr> </tr>
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
{% if user.is_authenticated %} {% if user.is_authenticated %}
<li>
<a href="/computings" onclick = $("#menu-close").click(); >Computing</a>
</li>
<li> <li>
<a href="/containers" onclick = $("#menu-close").click(); >Containers</a> <a href="/containers" onclick = $("#menu-close").click(); >Containers</a>
</li> </li>
......
...@@ -20,7 +20,7 @@ from django.contrib.auth.models import User ...@@ -20,7 +20,7 @@ from django.contrib.auth.models import User
from django.contrib.auth import update_session_auth_hash from django.contrib.auth import update_session_auth_hash
# Project imports # Project imports
from .models import Profile, LoginToken, Task, TaskStatuses, Container from .models import Profile, LoginToken, Task, TaskStatuses, Container, Computing
from .utils import send_email, format_exception, random_username, log_user_activity, timezonize, os_shell, booleanize from .utils import send_email, format_exception, random_username, log_user_activity, timezonize, os_shell, booleanize
# Setup logging # Setup logging
...@@ -427,7 +427,7 @@ def tasks(request): ...@@ -427,7 +427,7 @@ def tasks(request):
elif action=='stop': # or delete,a and if delete also remove object elif action=='stop': # or delete,a and if delete also remove object
try: try:
if task.compute == 'local': if task.computing == 'local':
# Delete the Docker container # Delete the Docker container
if standby_supported: if standby_supported:
...@@ -439,7 +439,7 @@ def tasks(request): ...@@ -439,7 +439,7 @@ def tasks(request):
if out.exit_code != 0: if out.exit_code != 0:
raise Exception(out.stderr) raise Exception(out.stderr)
elif task.compute == 'demoremote': elif task.computing == 'demoremote':
# Stop the task remotely # Stop the task remotely
stop_command = 'ssh -4 -o StrictHostKeyChecking=no slurmclusterworker-one "kill -9 {}"'.format(task.pid) stop_command = 'ssh -4 -o StrictHostKeyChecking=no slurmclusterworker-one "kill -9 {}"'.format(task.pid)
...@@ -450,7 +450,7 @@ def tasks(request): ...@@ -450,7 +450,7 @@ def tasks(request):
raise Exception(out.stderr) raise Exception(out.stderr)
else: else:
data['error']= 'Don\'t know how to stop tasks on "{}" compute resource.'.format(task.compute) data['error']= 'Don\'t know how to stop tasks on "{}" computing resource.'.format(task.computing)
return render(request, 'error.html', {'data': data}) return render(request, 'error.html', {'data': data})
# Ok, save status as deleted # Ok, save status as deleted
...@@ -485,7 +485,7 @@ def tasks(request): ...@@ -485,7 +485,7 @@ def tasks(request):
elif action=='connect': elif action=='connect':
# Create task tunnel # Create task tunnel
if task.compute in ['local', 'demoremote']: if task.computing in ['local', 'demoremote']:
# If there is no tunnel port allocated yet, find one # If there is no tunnel port allocated yet, find one
if not task.tunnel_port: if not task.tunnel_port:
...@@ -529,7 +529,7 @@ def tasks(request): ...@@ -529,7 +529,7 @@ def tasks(request):
subprocess.Popen(background_tunnel_command, shell=True) subprocess.Popen(background_tunnel_command, shell=True)
else: else:
raise ErrorMessage('Connecting to tasks on compute "{}" is not supported yet'.format(task.compute)) raise ErrorMessage('Connecting to tasks on computing "{}" is not supported yet'.format(task.computing))
# Ok, now redirect to the task through the tunnel # Ok, now redirect to the task through the tunnel
from django.shortcuts import redirect from django.shortcuts import redirect
...@@ -602,9 +602,9 @@ def create_task(request): ...@@ -602,9 +602,9 @@ def create_task(request):
raise Exception('Consistency error, container with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_container_uuid, request.user.email)) raise Exception('Consistency error, container with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_container_uuid, request.user.email))
# Compute # Compute
task_compute = request.POST.get('task_compute', None) task_computing = request.POST.get('task_computing', None)
if task_compute not in ['local', 'demoremote']: if task_computing not in ['local', 'demoremote']:
raise ErrorMessage('Unknown compute resource "{}') raise ErrorMessage('Unknown computing resource "{}')
# Generate the task uuid # Generate the task uuid
str_uuid = str(uuid.uuid4()) str_uuid = str(uuid.uuid4())
...@@ -616,12 +616,12 @@ def create_task(request): ...@@ -616,12 +616,12 @@ def create_task(request):
name = task_name, name = task_name,
status = TaskStatuses.created, status = TaskStatuses.created,
container = task_container, container = task_container,
compute = task_compute) computing = task_computing)
# Actually start tasks # Actually start tasks
try: try:
if task_compute == 'local': if task_computing == 'local':
# Get our ip address # Get our ip address
#import netifaces #import netifaces
...@@ -668,8 +668,8 @@ def create_task(request): ...@@ -668,8 +668,8 @@ def create_task(request):
# Save # Save
task.save() task.save()
elif task_compute == 'demoremote': elif task_computing == 'demoremote':
logger.debug('Using Demo Remote as compute resource') logger.debug('Using Demo Remote as computing resource')
# 1) Run the singularity container on slurmclusterworker-one (non blocking) # 1) Run the singularity container on slurmclusterworker-one (non blocking)
...@@ -701,7 +701,7 @@ def create_task(request): ...@@ -701,7 +701,7 @@ def create_task(request):
else: else:
raise Exception('Consistency exception: invalid compute resource "{}'.format(task_compute)) raise Exception('Consistency exception: invalid computing resource "{}'.format(task_computing))
except Exception as e: except Exception as e:
data['error'] = 'Error in creating new Task.' data['error'] = 'Error in creating new Task.'
...@@ -744,7 +744,7 @@ def task_log(request): ...@@ -744,7 +744,7 @@ def task_log(request):
# Get the log # Get the log
try: try:
if task.compute == 'local': if task.computing == 'local':
# View the Docker container log (attach) # View the Docker container log (attach)
view_log_command = 'sudo docker logs {}'.format(task.tid,) view_log_command = 'sudo docker logs {}'.format(task.tid,)
...@@ -755,7 +755,7 @@ def task_log(request): ...@@ -755,7 +755,7 @@ def task_log(request):
else: else:
data['log'] = out.stdout data['log'] = out.stdout
elif task.compute == 'demoremote': elif task.computing == 'demoremote':
# View the Singularity container log # View the Singularity container log
view_log_command = 'ssh -4 -o StrictHostKeyChecking=no slurmclusterworker-one "cat /tmp/{}.log"'.format(task.uuid) view_log_command = 'ssh -4 -o StrictHostKeyChecking=no slurmclusterworker-one "cat /tmp/{}.log"'.format(task.uuid)
...@@ -767,7 +767,7 @@ def task_log(request): ...@@ -767,7 +767,7 @@ def task_log(request):
data['log'] = out.stdout data['log'] = out.stdout
else: else:
data['error']= 'Don\'t know how to view task logs on "{}" compute resource.'.format(task.compute) data['error']= 'Don\'t know how to view task logs on "{}" computing resource.'.format(task.computing)
return render(request, 'error.html', {'data': data}) return render(request, 'error.html', {'data': data})
except Exception as e: except Exception as e:
...@@ -899,35 +899,36 @@ def add_container(request): ...@@ -899,35 +899,36 @@ def add_container(request):
#========================= #=========================
# Computes view # Computings view
#========================= #=========================
@private_view @private_view
def computes(request): def computings(request):
# Init data # Init data
data={} data={}
data['user'] = request.user data['user'] = request.user
data['profile'] = Profile.objects.get(user=request.user) data['profile'] = Profile.objects.get(user=request.user)
data['title'] = 'Add compute' data['title'] = 'Add computing'
data['name'] = request.POST.get('name',None) data['name'] = request.POST.get('name',None)
data['computings'] = Computing.objects.all()
return render(request, 'computings.html', {'data': data})
return render(request, 'computes.html', {'data': data})
#========================= #=========================
# Add Compute view # Add Compute view
#========================= #=========================
@private_view @private_view
def add_compute(request): def add_computing(request):
# Init data # Init data
data={} data={}
data['user'] = request.user data['user'] = request.user
data['profile'] = Profile.objects.get(user=request.user) data['profile'] = Profile.objects.get(user=request.user)
data['title'] = 'Add compute' data['title'] = 'Add computing'
data['name'] = request.POST.get('name',None) data['name'] = request.POST.get('name',None)
return render(request, 'add_compute.html', {'data': data}) return render(request, 'add_computing.html', {'data': data})
...@@ -43,8 +43,8 @@ urlpatterns = [ ...@@ -43,8 +43,8 @@ urlpatterns = [
url(r'^tasks/$', base_app_views.tasks), url(r'^tasks/$', base_app_views.tasks),
url(r'^create_task/$', base_app_views.create_task), url(r'^create_task/$', base_app_views.create_task),
url(r'^task_log/$', base_app_views.task_log), url(r'^task_log/$', base_app_views.task_log),
url(r'^computes/$', base_app_views.computes), url(r'^computings/$', base_app_views.computings),
url(r'^add_compute/$', base_app_views.add_compute), url(r'^add_computing/$', base_app_views.add_computing),
url(r'^containers/$', base_app_views.containers), url(r'^containers/$', base_app_views.containers),
url(r'^add_container/$', base_app_views.add_container), url(r'^add_container/$', base_app_views.add_container),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment