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

Added preliminary support for viewing task terminal output (log). move from...

Added preliminary support for viewing task terminal output (log). move from short_uuid to id. Minor fixes.
parent eaa13c58
No related branches found
No related tags found
No related merge requests found
......@@ -106,10 +106,11 @@ class Task(models.Model):
self.save()
@property
def short_uuid(self):
def id(self):
return str(self.uuid).split('-')[0]
#=========================
# Containers
#=========================
......@@ -128,4 +129,12 @@ class Container(models.Model):
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()
......@@ -8,30 +8,78 @@
<div class="container">
<div class="dashboard">
<div class="span8 offset2">
<h1>Container List</h1>
<h1><a href="/containers">Container List</a> {% if data.container %}&gt; {{ data.container.id }} {% endif %} </h1>
<hr/>
{% if data.container %}
<table class="dashboard">
<tr>
<td><b>ID</b></td>
<td>{{ data.container.id }}</td>
</tr>
<tr>
<td><b>Image</b></td>
<td>{{ data.container.image }}</td>
</tr>
<tr>
<td><b>Type</b></td>
<td>{{ data.container.type }}</td>
</tr>
<tr>
<td><b>Owner</b></td>
<td>{% if data.container.user %}{{data.container.user}}{% else %}Platform{% endif %}</td>
</tr>
<tr>
<td><b>Registry</b></td>
<td>{{ data.container.registry }}</td>
</tr>
<tr>
<td><b>Service port(s)</b></td>
<td>{{ data.container.service_ports}}</td>
</tr>
</table>
<br />
{% else %}
{% for container in data.platform_containers %}
<table class="dashboard">
<tr>
<td><b>Container image</b></td>
<td>{{ container.image }} (platform)</td>
<td><b>ID</b></td>
<td><a href="?uuid={{ container.uuid }}">{{ container.id }}</a></td>
</tr>
<tr>
<td><b>Container type</b></td>
<td><b>Image</b></td>
<td>{{ container.image }}</td>
</tr>
<tr>
<td><b>Type</b></td>
<td>{{ container.type }}</td>
</tr>
<tr>
<td><b>Container registry</b></td>
<td><b>Owner</b></td>
<td>Platform</td>
</tr>
<tr>
<td><b>Registry</b></td>
<td>{{ container.registry }}</td>
</tr>
<tr>
<td><b>Container service ports</b></td>
<td><b>Service port(s)</b></td>
<td>{{ container.service_ports}}</td>
</tr>
......@@ -44,22 +92,32 @@
<table class="dashboard">
<tr>
<td><b>Container image</b></td>
<td>{{ container.image }} (user)</td>
<td><b>ID</b></td>
<td><a href="?uuid={{ container.uuid }}">{{ container.id }}</a></td>
</tr>
<tr>
<td><b>Container type</b></td>
<td><b>Image</b></td>
<td>{{ container.image }}</td>
</tr>
<tr>
<td><b>Type</b></td>
<td>{{ container.type }}</td>
</tr>
<tr>
<td><b>Container registry</b></td>
<td><b>Owner</b></td>
<td>{{container.user}}</td>
</tr>
<tr>
<td><b>Registry</b></td>
<td>{{ container.registry }}</td>
</tr>
<tr>
<td><b>Container service ports</b></td>
<td><b>Service port(s)</b></td>
<td>{{ container.service_ports}}</td>
</tr>
......@@ -74,13 +132,13 @@
<br />
<a href="/add_container">Add new...</a>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
{% endif %}
<br />
<br />
<br />
<br />
</div>
</div>
</div>
......
......@@ -9,6 +9,10 @@
<meta name="description" content="">
<meta name="author" content="">
{% if refresh %}
<meta http-equiv="refresh" content="{{refresh}}" >
{% endif %}
{% if data.title %}
<title>{{data.title}}</title>
{% else %}
......
{% load static %}
{% include "header.html" with refresh=data.refresh %}
{% include "navigation.html" with main_path='/main/' %}
<br/>
<br/>
<div class="container">
<div class="dashboard">
<div class="span8 offset2">
<h1><a href="/tasks/">Task List</a> &gt; {{ data.task.id }} Log</h1>
<hr>
<b>ID:</b> {{ data.task.id }} &nbsp; &nbsp;
<b>Status:</b> {{ data.task.status }} &nbsp; &nbsp;
<b>Auto refresh:{{data.refresh}}</b>&nbsp;
{% if not data.refresh %} OFF {% else %} <a href="?uuid={{data.task.uuid}}">OFF</a> {% endif %} |
{% if data.refresh == "3" %} 3s {% else %} <a href="?uuid={{data.task.uuid}}&refresh=3">3s</a> {% endif %} |
{% if data.refresh == "10" %} 10s{% else %} <a href="?uuid={{data.task.uuid}}}&refresh=10">10s</a> {% endif %} |
{% if data.refresh == "60" %} 60s{% else %} <a href="?uuid={{data.task.uuid}}}&refresh=60">60s</a> {% endif %}
<pre id="output" style="border: 1px solid #a0a0a0; width: 100%; height: 500px; background-color:black; color:white; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: white-space: -o-pre-wrap; word-wrap: break-word;">{{ data.log }}</pre>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
</div>
</div>
</div>
{% include "footer.html" %}
<script>
jQuery( function(){
var pre = jQuery("#output");
pre.scrollTop( pre.prop("scrollHeight") );
});
</script>
......@@ -8,12 +8,8 @@
<div class="container">
<div class="dashboard">
<div class="span8 offset2">
{% if not data.sid %}
<h1>Task List</h1>
{% else %}
<h1>Task Info</h1>
{% endif %}
<hr>
......@@ -21,27 +17,27 @@
<table class="dashboard">
<tr>
<td><b>Task id</b></td>
<td>{{ task.short_uuid }}</td>
<td><b>ID</b></td>
<td>{{ task.id }}</td>
</tr>
<tr>
<td><b>Task name</b></td>
<td><b>Name</b></td>
<td>{{ task.name }}</td>
</tr>
<tr>
<td><b>Task container</b></td>
<td>{{ task.container.image }}</td>
<td><b>Container</b></td>
<td><a href="">{{ task.container.image }}</a></td>
</tr>
<tr>
<td><b>Task status</b></td>
<td><b>Status</b></td>
<td>{{ task.status }}</td>
</tr>
<tr>
<td><b>Task created</b></td>
<td><b>Created at</b></td>
<td>{{ task.created }}</td>
</tr>
......@@ -51,12 +47,12 @@
</tr> -->
<tr>
<td><b>Task ip</b></td>
<td><b>IP</b></td>
<td>{{ task.ip}}</td>
</tr>
<tr>
<td><b>Task port</b></td>
<td><b>Port</b></td>
<td>{{ task.port }}</td>
</tr>
......@@ -83,8 +79,10 @@
{% endif %}
{% if task.status == "running" %}
| <a href=?uuid={{task.uuid}}&action=connect>Connect</a>
| <a href=/task_log/?uuid={{task.uuid}}&action=viewlog>View Log</a>
{% else %}
| <font color="#c0c0c0">Connect</font>
| <font color="#c0c0c0">View Log</font>
{% endif%}
</td>
......
......@@ -404,9 +404,6 @@ def tasks(request):
# Delete
task.delete()
# Unset uuid to load the list again
uuid = None
except Exception as e:
data['error'] = 'Error in deleting the task'
logger.error('Error in deleting task with uuid="{}": "{}"'.format(uuid, e))
......@@ -434,7 +431,8 @@ def tasks(request):
logger.debug(stop_command)
out = os_shell(stop_command, capture=True)
if out.exit_code != 0:
raise Exception(out.stderr)
if not 'No such process' in out.stderr:
raise Exception(out.stderr)
else:
data['error']= 'Don\'t know how to stop tasks on "{}" compute resource.'.format(task.compute)
......@@ -469,9 +467,6 @@ def tasks(request):
logger.error('Error in stopping task with uuid="{}": "{}"'.format(uuid, e))
return render(request, 'error.html', {'data': data})
# Unset uuid to load the list again
uuid = None
elif action=='connect':
# Get the task (raises if none available including no permission)
......@@ -524,26 +519,17 @@ def tasks(request):
else:
raise ErrorMessage('Connecting to tasks on compute "{}" is not supported yet'.format(task.compute))
# Ok, now redirect to the task through the tunnel
from django.shortcuts import redirect
return redirect('http://localhost:{}'.format(task.tunnel_port))
# Get all task(s)
if uuid:
try:
tasks = [Task.objects.get(user=request.user, uuid=uuid)]
except Exception as e:
data['error'] = 'Error in getting info for Task "{}"'.format(uuid)
logger.error('Error in getting Virtual Device with uuid="{}": "{}"'.format(uuid, e))
return render(request, 'error.html', {'data': data})
else:
try:
tasks = Task.objects.filter(user=request.user).order_by('created')
except Exception as e:
data['error'] = 'Error in getting Virtual Devices info'
logger.error('Error in getting Virtual Devices: "{}"'.format(e))
return render(request, 'error.html', {'data': data})
# Get all tasks
try:
tasks = Task.objects.filter(user=request.user).order_by('created')
except Exception as e:
data['error'] = 'Error in getting Tasks info'
logger.error('Error in getting Virtual Devices: "{}"'.format(e))
return render(request, 'error.html', {'data': data})
# Update task statuses
for task in tasks:
......@@ -660,7 +646,7 @@ def create_task(request):
# 1) Run the singularity container on slurmclusterworker-one (non blocking)
run_command = 'ssh -4 -o StrictHostKeyChecking=no slurmclusterworker-one "export SINGULARITY_NOHTTPS=true && exec nohup singularity run --pid --writable-tmpfs --containall --cleanenv docker://dregistry:5000/rosetta/metadesktop &> /dev/null & echo \$!"'
run_command = 'ssh -4 -o StrictHostKeyChecking=no slurmclusterworker-one "export SINGULARITY_NOHTTPS=true && exec nohup singularity run --pid --writable-tmpfs --containall --cleanenv docker://dregistry:5000/rosetta/metadesktop &> /tmp/{}.log & echo \$!"'.format(task.uuid)
out = os_shell(run_command, capture=True)
if out.exit_code != 0:
raise Exception(out.stderr)
......@@ -701,6 +687,71 @@ def create_task(request):
return render(request, 'create_task.html', {'data': data})
#=========================
# Task log
#=========================
@private_view
def task_log(request):
# Init data
data={}
data['user'] = request.user
data['profile'] = Profile.objects.get(user=request.user)
data['title'] = 'Tasks'
# Get uuid and refresh if any
uuid = request.GET.get('uuid', None)
refresh = request.GET.get('refresh', None)
if not uuid:
return render(request, 'error.html', {'data': 'uuid not set'})
# Get the task (raises if none available including no permission)
task = Task.objects.get(user=request.user, uuid=uuid)
# Set back task and refresh
data['task'] = task
data['refresh'] = refresh
# Get the log
try:
if task.compute == 'local':
raise NotImplementedError('Not yet')
# View the Docker container log (attach)
#view_log_command = 'sudo docker stop {} && sudo docker rm {}'.format(task.tid,task.tid)
#out = os_shell(view_log_command, capture=True)
#if out.exit_code != 0:
# raise Exception(out.stderr)
elif task.compute == 'demoremote':
# View the Singularity container log
view_log_command = 'ssh -4 -o StrictHostKeyChecking=no slurmclusterworker-one "cat /tmp/{}.log"'.format(task.uuid)
logger.debug(view_log_command)
out = os_shell(view_log_command, capture=True)
if out.exit_code != 0:
raise Exception(out.stderr)
else:
data['log'] = out.stdout
else:
data['error']= 'Don\'t know how to view task logs on "{}" compute resource.'.format(task.compute)
return render(request, 'error.html', {'data': data})
except Exception as e:
data['error'] = 'Error in viewing task log'
logger.error('Error in viewing task log with uuid="{}": "{}"'.format(uuid, e))
return render(request, 'error.html', {'data': data})
return render(request, 'task_log.html', {'data': data})
#=========================
......@@ -714,35 +765,40 @@ def containers(request):
data={}
data['user'] = request.user
data['profile'] = Profile.objects.get(user=request.user)
data['title'] = 'Containers'
data['name'] = request.POST.get('name',None)
# Get action if any
action = request.GET.get('action', None)
uuid = request.GET.get('uuid', None)
uuid = request.GET.get('uuid', None)
# Do we have to operate on a specific container?
if uuid:
try:
if action and uuid:
# Get the task (raises if none available including no permission)
container = Container.objects.get(uuid=uuid)
data['container'] = container
if action=='delete':
try:
# Get the task (raises if none available including no permission)
container = Container.objects.get(user=request.user, uuid=uuid)
if action and action=='delete':
# Delete
container.delete()
# Unset uuid to load the list again
uuid = None
# Unset container to load the list again
data['container'] = None
except Exception as e:
data['error'] = 'Error in deleting the container'
logger.error('Error in deleting task with uuid="{}": "{}"'.format(uuid, e))
return render(request, 'error.html', {'data': data})
except Exception as e:
data['error'] = 'Error in getting the container or performing the required action'
logger.error('Error in getting the container with uuid="{}" or performing the required action: "{}"'.format(uuid, e))
return render(request, 'error.html', {'data': data})
# Get containers configured on the platform, both private to this user and public
data['user_containers'] = Container.objects.filter(user=request.user)
data['platform_containers'] = Container.objects.filter(user=None)
# Do we have to get he list of containers?
if not uuid:
# Get containers configured on the platform, both private to this user and public
data['user_containers'] = Container.objects.filter(user=request.user)
data['platform_containers'] = Container.objects.filter(user=None)
logger.debug(data)
return render(request, 'containers.html', {'data': data})
......
......@@ -42,6 +42,7 @@ urlpatterns = [
url(r'^account/$', base_app_views.account),
url(r'^tasks/$', base_app_views.tasks),
url(r'^create_task/$', base_app_views.create_task),
url(r'^task_log/$', base_app_views.task_log),
url(r'^computes/$', base_app_views.computes),
url(r'^add_compute/$', base_app_views.add_compute),
url(r'^containers/$', base_app_views.containers),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment