postpone gridftp initialization (magical fix of uwsgi issues)
[qcg-portal.git] / qcg / models.py
index b9a35e5..0bc0cb2 100644 (file)
@@ -1,10 +1,10 @@
 # coding=utf-8
 from django.contrib.auth.models import AbstractUser
 # coding=utf-8
 from django.contrib.auth.models import AbstractUser
+from django.core.urlresolvers import reverse
 from django.db import models
 from django.utils.timezone import now
 from pyqcg.service import Job as QcgJob, Task as QcgTask
 from django.db import models
 from django.utils.timezone import now
 from pyqcg.service import Job as QcgJob, Task as QcgTask
-from pyqcg.utils import JobStatus, TaskStatus, TaskType
-from timedelta import TimedeltaField
+from pyqcg.utils import JobStatus, TaskStatus, TaskType, AllocationType, EPRUtils
 
 from qcg.utils import username_from_dn, get_attributes
 
 
 from qcg.utils import username_from_dn, get_attributes
 
@@ -15,6 +15,10 @@ __all__ = ['User', 'Job', 'Task', 'Allocation', 'NodeInfo']
 class User(AbstractUser):
     last_update = models.DateTimeField(default=now)
 
 class User(AbstractUser):
     last_update = models.DateTimeField(default=now)
 
+    @property
+    def tasks(self):
+        return Task.objects.filter(job__owner=self)
+
 
 class Job(models.Model):
     STATUS_CHOICES = list(enumerate(field for field in dir(JobStatus) if not field.startswith('__')))
 
 class Job(models.Model):
     STATUS_CHOICES = list(enumerate(field for field in dir(JobStatus) if not field.startswith('__')))
@@ -27,10 +31,10 @@ class Job(models.Model):
     status = models.IntegerField(u"Status", choices=STATUS_CHOICES)
     note = models.TextField(u"Notatka", blank=True, default='')
     description = models.TextField(u"Opis", blank=True, default='')
     status = models.IntegerField(u"Status", choices=STATUS_CHOICES)
     note = models.TextField(u"Notatka", blank=True, default='')
     description = models.TextField(u"Opis", blank=True, default='')
+    project = models.TextField(u"Projekt", blank=True, default='')
     submission_time = models.DateTimeField(u"Data wysłania")
     finish_time = models.DateTimeField(u"Data zakończenia", blank=True, null=True)
     submission_time = models.DateTimeField(u"Data wysłania")
     finish_time = models.DateTimeField(u"Data zakończenia", blank=True, null=True)
-    proxy_lifetime = TimedeltaField(u"Czas życia proxy", blank=True, null=True)
-    project = models.TextField(u"Projekt", blank=True, default='')
+    proxy_lifetime = models.DateTimeField(u"Czas życia proxy", blank=True, null=True)
     purged = models.BooleanField(u"Usunięty katalog roboczy?", default=False)
 
     owner = models.ForeignKey(User, verbose_name=u"Właściciel", related_name='jobs')
     purged = models.BooleanField(u"Usunięty katalog roboczy?", default=False)
 
     owner = models.ForeignKey(User, verbose_name=u"Właściciel", related_name='jobs')
@@ -45,25 +49,29 @@ class Job(models.Model):
     def __unicode__(self):
         return self.job_id
 
     def __unicode__(self):
         return self.job_id
 
+    def get_absolute_url(self):
+        return reverse('job', kwargs={'job_id': self.job_id})
+
     @property
     def qcg_job(self):
         if self._job is None:
     @property
     def qcg_job(self):
         if self._job is None:
-            self._job = QcgJob(self.epr)
+            self._job = QcgJob(EPRUtils.deserialize_epr(self.epr))
 
         return self._job
 
     @staticmethod
     def qcg_map(qcg_job, user=None):
         attrs = get_attributes(qcg_job, ('job_id', 'note', 'description', 'submission_time', 'finish_time',
 
         return self._job
 
     @staticmethod
     def qcg_map(qcg_job, user=None):
         attrs = get_attributes(qcg_job, ('job_id', 'note', 'description', 'submission_time', 'finish_time',
-                                         'proxy_lifetime', 'project', 'purged'))
+                                         'project', 'purged'))
 
 
-        attrs['epr'] = str(qcg_job.epr)
+        attrs['epr'] = EPRUtils.serialize_epr(qcg_job.epr)
         attrs['status'] = Job.STATUS_CHOICES_REVERSED[qcg_job.status]
         attrs['status'] = Job.STATUS_CHOICES_REVERSED[qcg_job.status]
+        attrs['proxy_lifetime'] = now() + qcg_job.proxy_lifetime
 
         username = username_from_dn(qcg_job.user_dn)
         if user is not None:
             if user.username != username:
 
         username = username_from_dn(qcg_job.user_dn)
         if user is not None:
             if user.username != username:
-                raise ValueError('')
+                raise ValueError('Username does not match!')
             attrs['owner'] = user
         else:
             attrs['owner'] = User.objects.get(username=username)
             attrs['owner'] = user
         else:
             attrs['owner'] = User.objects.get(username=username)
@@ -100,7 +108,7 @@ class Task(models.Model):
     finish_time = models.DateTimeField(u"Data zakończenia", blank=True, null=True)
     reserved_time_start = models.DateTimeField(u"Data rozpoczęcia rezerwacji", blank=True, null=True)
     reserved_time_finish = models.DateTimeField(u"Data zakończenia rezerwacji", blank=True, null=True)
     finish_time = models.DateTimeField(u"Data zakończenia", blank=True, null=True)
     reserved_time_start = models.DateTimeField(u"Data rozpoczęcia rezerwacji", blank=True, null=True)
     reserved_time_finish = models.DateTimeField(u"Data zakończenia rezerwacji", blank=True, null=True)
-    proxy_lifetime = TimedeltaField(u"Czas życia proxy", blank=True, null=True)
+    proxy_lifetime = models.DateTimeField(u"Czas życia proxy", blank=True, null=True)
     purged = models.BooleanField(u"Usunięty katalog roboczy?", default=False)
 
     created = models.DateTimeField(u"Utworzono", auto_now_add=True)
     purged = models.BooleanField(u"Usunięty katalog roboczy?", default=False)
 
     created = models.DateTimeField(u"Utworzono", auto_now_add=True)
@@ -115,22 +123,25 @@ class Task(models.Model):
     def __unicode__(self):
         return u'{}/{}'.format(self.job, self.task_id)
 
     def __unicode__(self):
         return u'{}/{}'.format(self.job, self.task_id)
 
+    def get_absolute_url(self):
+        return reverse('task', kwargs={'job_id': self.job.job_id, 'task_id': self.task_id})
+
     @property
     def qcg_task(self):
         if self._qcg_task is None:
     @property
     def qcg_task(self):
         if self._qcg_task is None:
-            self._qcg_task = QcgTask(self.epr)
+            self._qcg_task = QcgTask(EPRUtils.deserialize_epr(self.epr))
 
         return self._qcg_task
 
     @staticmethod
     def qcg_map(qcg_task, jobs=None):
         attrs = get_attributes(qcg_task, ('task_id', 'status_description', 'note', 'description', 'submission_time',
 
         return self._qcg_task
 
     @staticmethod
     def qcg_map(qcg_task, jobs=None):
         attrs = get_attributes(qcg_task, ('task_id', 'status_description', 'note', 'description', 'submission_time',
-                                          'start_time', 'finish_time', 'reserved_time_slot', 'proxy_lifetime',
-                                          'purged'))
+                                          'start_time', 'finish_time', 'reserved_time_slot', 'purged'))
 
 
-        attrs['epr'] = str(qcg_task.epr)
+        attrs['epr'] = EPRUtils.serialize_epr(qcg_task.epr)
         attrs['status'] = Task.STATUS_CHOICES_REVERSED[qcg_task.status]
         attrs['type'] = Task.TYPE_CHOICES_REVERSED[qcg_task.type]
         attrs['status'] = Task.STATUS_CHOICES_REVERSED[qcg_task.status]
         attrs['type'] = Task.TYPE_CHOICES_REVERSED[qcg_task.type]
+        attrs['proxy_lifetime'] = now() + qcg_task.proxy_lifetime
 
         if jobs is not None and qcg_task.job_id in jobs:
             attrs['job'] = jobs[qcg_task.job_id]
 
         if jobs is not None and qcg_task.job_id in jobs:
             attrs['job'] = jobs[qcg_task.job_id]
@@ -157,17 +168,21 @@ class Task(models.Model):
             self.reserved_time_start, self.reserved_time_finish = value
 
     @property
             self.reserved_time_start, self.reserved_time_finish = value
 
     @property
-    def hosts(self):
-        return {alloc.host_name for alloc in self.allocations.all()}
+    def short_host_names(self):
+        return {alloc.host_name.split('.', 1)[0] for alloc in self.allocations.all()}
 
 
 class Allocation(models.Model):
 
 
 class Allocation(models.Model):
+    STATUS_CHOICES = list(enumerate(field for field in dir(AllocationType) if not field.startswith('__')))
+    STATUS_CHOICES_REVERSED = {v: k for k, v in STATUS_CHOICES}
+
     task = models.ForeignKey(Task, verbose_name='Zadanie', related_name='allocations')
 
     host_name = models.CharField(u"Host", max_length=100)
     task = models.ForeignKey(Task, verbose_name='Zadanie', related_name='allocations')
 
     host_name = models.CharField(u"Host", max_length=100)
+    status = models.IntegerField(u"Status", choices=STATUS_CHOICES)
     status_description = models.TextField(u"Opis statusu", blank=True, default='')
     status_description = models.TextField(u"Opis statusu", blank=True, default='')
-    processes_count = models.PositiveIntegerField(u"Liczba procesorów")
-    slots_count = models.PositiveIntegerField(u"Liczba slotów")
+    processes_count = models.PositiveIntegerField(u"Liczba procesów")
+    slots_count = models.PositiveIntegerField(u"Liczba rdzeni")
     processes_group_id = models.TextField(u"Identyfikator grupy procesów", blank=True, default='')
     submission_time = models.DateTimeField(u"Data wysłania")
     estimated_start_time = models.DateTimeField(u"Przewidywana data rozpoczęcia", blank=True, null=True)
     processes_group_id = models.TextField(u"Identyfikator grupy procesów", blank=True, default='')
     submission_time = models.DateTimeField(u"Data wysłania")
     estimated_start_time = models.DateTimeField(u"Przewidywana data rozpoczęcia", blank=True, null=True)
@@ -179,6 +194,7 @@ class Allocation(models.Model):
     efficiency = models.IntegerField(u"Efektywność", blank=True, null=True)  # ??
     comment = models.TextField(u"Komentarz", blank=True, default='')
     memory_usage = models.PositiveIntegerField(u"Użycie pamięci", blank=True, null=True)
     efficiency = models.IntegerField(u"Efektywność", blank=True, null=True)  # ??
     comment = models.TextField(u"Komentarz", blank=True, default='')
     memory_usage = models.PositiveIntegerField(u"Użycie pamięci", blank=True, null=True)
+    working_directory = models.CharField(u"Katalog roboczy", max_length=1024, blank=True, default='')
 
     class Meta:
         verbose_name = u"Alokacja"
 
     class Meta:
         verbose_name = u"Alokacja"
@@ -190,17 +206,22 @@ class Allocation(models.Model):
 
     @staticmethod
     def qcg_map(qcg_allocation):
 
     @staticmethod
     def qcg_map(qcg_allocation):
-        return get_attributes(qcg_allocation, ('host_name', 'status_description', 'processes_count', 'slots_count',
-                                               'processes_group_id', 'submission_time', 'estimated_start_time',
-                                               'finish_time', 'local_submission_time', 'local_start_time',
-                                               'local_finish_time', 'purged', 'efficiency', 'comment', 'memory_usage'))
+        attrs = get_attributes(qcg_allocation, ('host_name', 'status_description', 'processes_count', 'slots_count',
+                                                'processes_group_id', 'submission_time', 'estimated_start_time',
+                                                'finish_time', 'local_submission_time', 'local_start_time',
+                                                'local_finish_time', 'purged', 'efficiency', 'comment', 'memory_usage',
+                                                'working_directory'))
+
+        attrs['status'] = Allocation.STATUS_CHOICES_REVERSED[qcg_allocation.status]
+
+        return attrs
 
 
 class NodeInfo(models.Model):
     allocation = models.ForeignKey(Allocation, verbose_name=u"Alokacja", related_name='nodes')
 
     name = models.CharField(u"Nazwa", max_length=32)
 
 
 class NodeInfo(models.Model):
     allocation = models.ForeignKey(Allocation, verbose_name=u"Alokacja", related_name='nodes')
 
     name = models.CharField(u"Nazwa", max_length=32)
-    count = models.PositiveSmallIntegerField(u"Liczba slotów", blank=True, null=True)
+    count = models.PositiveSmallIntegerField(u"Liczba rdzeni", blank=True, null=True)
 
     class Meta:
         verbose_name = u"Węzeł"
 
     class Meta:
         verbose_name = u"Węzeł"
@@ -216,6 +237,4 @@ class NodeInfo(models.Model):
 
     @staticmethod
     def qcg_map(qcg_node):
 
     @staticmethod
     def qcg_map(qcg_node):
-        return {'name': qcg_node.value,
-                # FIXME
-                'count': qcg_node.slots_count.intValue() if qcg_node.slots_count is not None else None}
+        return {'name': qcg_node.name, 'count': qcg_node.slots_count}