synchronizing user jobs & basic task list view
authorMaciej Tronowski <mtro@man.poznan.pl>
Thu, 19 Feb 2015 16:08:48 +0000 (17:08 +0100)
committerMaciej Tronowski <mtro@man.poznan.pl>
Thu, 19 Feb 2015 16:08:48 +0000 (17:08 +0100)
qcg/templates/qcg/jobs.html
qcg/utils.py [new file with mode: 0644]
qcg/views.py

index 747d382..78e3dd2 100644 (file)
                 <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>
 
diff --git a/qcg/utils.py b/qcg/utils.py
new file mode 100644 (file)
index 0000000..353dc0c
--- /dev/null
@@ -0,0 +1,60 @@
+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()
index eb54d58..dd6ecf7 100644 (file)
@@ -1,11 +1,16 @@
 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):
@@ -35,8 +40,16 @@ def openid_begin(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):