<th>Koniec</th>
<th>Status</th>
<th>Host</th>
- <th>Uwagi</th>
+{# <th>Uwagi</th>#}
</tr>
</thead>
<tbody>
- <tr class="treegrid-1">
- <td>
- <a href="{% url 'job' %}">
- <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
- </a>
- </td>
- <td>urban</td>
- <td>04.07.13 17:03</td>
- <td></td>
- <td></td>
- <td>PENDING</td>
- <td>hydra</td>
- <td></td>
- </tr>
- <tr class="treegrid-2">
- <td>
- <a href="{% url 'job' %}">
- <span class="glyphicon glyphicon-folder-close" aria-hidden="true"></span>
- </a>
- </td>
- <td>urban</td>
- <td>04.07.13 17:03</td>
- <td></td>
- <td></td>
- <td>RUNNING</td>
- <td>inula</td>
- <td></td>
- </tr>
- <tr class="treegrid-3 treegrid-parent-2">
- <td>
- <a href="{% url 'job' %}">
- <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
- </a>
- </td>
- <td>urban</td>
- <td>04.07.13 17:03</td>
- <td></td>
- <td></td>
- <td>FINISHED</td>
- <td>inula</td>
- <td></td>
- </tr>
- <tr class="treegrid-4">
- <td>
- <a href="{% url 'job' %}">
- <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
- </a>
- </td>
- <td>urban</td>
- <td>04.07.13 17:03</td>
- <td></td>
- <td></td>
- <td>CANCELED</td>
- <td>inula</td>
- <td></td>
- </tr>
+ {% regroup tasks by job as jobs %}
+
+ {% for job in jobs %}
+ {% ifequal job.list|length 1 %}
+ {% with job.list.0 as task %}
+ <tr class="treegrid-{{ forloop.counter }}">
+ <td>
+ <a href="{% url 'job' %}">
+ <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
+{# {{ task }}#}
+ </a>
+ </td>
+ <td>{{ task.note }}</td>
+ <td>{{ task.submission_time }}</td>
+ <td>{{ task.start_time }}</td>
+ <td>{{ task.finish_time }}</td>
+ <td>{{ task.get_status_display }}</td>
+ <td>{{ task.hosts|join:', ' }}</td>
+ </tr>
+ {% endwith %}
+ {% else %}
+ <tr class="treegrid-{{ forloop.counter }}">
+ <td>
+ <a href="{% url 'job' %}">
+ <span class="glyphicon glyphicon-folder-close" aria-hidden="true"></span>
+{# {{ job.grouper }}#}
+ </a>
+ </td>
+ <td>{{ job.grouper.note }}</td>
+ <td>{{ job.grouper.submission_time }}</td>
+ <td>-</td>
+ <td>{{ job.grouper.finish_time }}</td>
+ <td>{{ job.grouper.get_status_display }}</td>
+ <td>-</td>
+ </tr>
+
+ {% for task in job.list %}
+ <tr class="treegrid-{{ forloop.parentloop.counter }}-{{ forloop.counter }} treegrid-parent-{{ forloop.parentloop.counter }}">
+ <td>
+ <a href="{% url 'job' %}">
+ <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
+{# {{ task }}#}
+ </a>
+ </td>
+ <td>{{ task.note }}</td>
+ <td>{{ task.submission_time }}</td>
+ <td>{{ task.start_time }}</td>
+ <td>{{ task.finish_time }}</td>
+ <td>{{ task.get_status_display }}</td>
+ <td>{{ task.hosts|join:', ' }}</td>
+ </tr>
+ {% endfor %}
+ {% endifequal %}
+ {% endfor %}
</tbody>
</table>
--- /dev/null
+from datetime import timedelta
+from django.db import transaction
+from django.utils.timezone import now
+from pyqcg.service import Registry
+from pyqcg.utils import Credential, TimePeriod
+
+
+def get_attributes(obj, attrs):
+ return {name: getattr(obj, name) for name in attrs if getattr(obj, name) is not None}
+
+
+def username_from_dn(dn):
+ _, username = dn.rsplit('=', 1)
+
+ return username
+
+
+@transaction.atomic
+def update_user_data(user, proxy):
+ from qcg.models import User, Job, Task, Allocation, NodeInfo
+
+ credential = Credential(proxy)
+ registry = Registry(credential)
+
+ # put lock on user record (hopefully..?)
+ user = User.objects.select_for_update().get(pk=user.pk)
+
+ changed_filter = {'changed': TimePeriod(after=user.last_update)}
+
+ ###################################
+ # Jobs
+ ###################################
+ for qcg_job in registry.jobs(**changed_filter):
+ params = Job.qcg_map(qcg_job, user)
+ job_id = params.pop('job_id')
+
+ Job.objects.update_or_create(job_id=job_id, defaults=params)
+
+ ###################################
+ # Tasks
+ ###################################
+ jobs_cache = {j.job_id: j for j in Job.objects.filter(owner=user)}
+ for qcg_task in registry.tasks(**changed_filter):
+ params = Task.qcg_map(qcg_task, jobs_cache)
+ task_id = params.pop('task_id')
+
+ task, created = Task.objects.update_or_create(job__job_id=qcg_task.job_id, task_id=task_id, defaults=params)
+
+ if not created:
+ task.allocations.all().delete()
+
+ for qcg_alloc in qcg_task.allocations:
+ alloc = task.allocations.create(**Allocation.qcg_map(qcg_alloc))
+
+ for qcg_node in qcg_alloc.nodes:
+ alloc.nodes.create(**NodeInfo.qcg_map(qcg_node))
+
+ # release user lock
+ user.last_update = now()
+ user.save()
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
+from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.shortcuts import render
from django.utils.http import urlencode
from django_openid_auth.views import make_consumer
from openid.extensions import ax
+from pyqcg.qcg import QCG
+from qcg.models import Task
+
+from qcg.utils import update_user_data
def index(request):
return HttpResponse(openid_request.htmlMarkup(request.build_absolute_uri('/'), return_to))
+@login_required
def jobs_list(request):
- return render(request, 'qcg/jobs.html')
+ # QCG.start()
+ # update_user_data(request.user, request.session['proxy'])
+
+ tasks = Task.objects.filter(job__owner=request.user) \
+ .select_related('job').prefetch_related('allocations__nodes') \
+ .order_by('-job__submission_time', '-submission_time')[:25]
+
+ return render(request, 'qcg/jobs.html', {'tasks': tasks})
def job_details(request):