activity.py 6.02 KB
Newer Older
1
from __future__ import absolute_import, unicode_literals
Őry Máté committed
2 3 4
from contextlib import contextmanager
from logging import getLogger

5
from django.core.urlresolvers import reverse
6
from django.db.models import CharField, ForeignKey
Őry Máté committed
7 8 9
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

10 11 12 13 14
from common.models import (
    ActivityModel, activitycontextimpl, join_activity_code,
)


Őry Máté committed
15 16 17
logger = getLogger(__name__)


18 19 20 21 22 23 24 25 26 27 28 29
class ActivityInProgressError(Exception):

        def __init__(self, activity, message=None):
            if message is None:
                message = ("Another activity is currently in progress: '%s'."
                           % activity.activity_code)

            Exception.__init__(self, message)

            self.activity = activity


Őry Máté committed
30
class InstanceActivity(ActivityModel):
31
    ACTIVITY_CODE_BASE = join_activity_code('vm', 'Instance')
Őry Máté committed
32 33 34
    instance = ForeignKey('Instance', related_name='activity_log',
                          help_text=_('Instance this activity works on.'),
                          verbose_name=_('instance'))
35
    resultant_state = CharField(blank=True, max_length=20, null=True)
Őry Máté committed
36 37 38 39

    class Meta:
        app_label = 'vm'
        db_table = 'vm_instanceactivity'
40
        ordering = ['-finished', '-started', 'instance', '-id']
Őry Máté committed
41 42 43 44 45 46 47 48 49 50

    def __unicode__(self):
        if self.parent:
            return '{}({})->{}'.format(self.parent.activity_code,
                                       self.instance,
                                       self.activity_code)
        else:
            return '{}({})'.format(self.activity_code,
                                   self.instance)

51 52 53
    def get_absolute_url(self):
        return reverse('dashboard.views.vm-activity', args=[self.pk])

Őry Máté committed
54 55 56
    def get_readable_name(self):
        return self.activity_code.split('.')[-1].replace('_', ' ').capitalize()

57 58 59 60 61 62 63 64
    def get_status_id(self):
        if self.succeeded is None:
            return 'wait'
        elif self.succeeded:
            return 'success'
        else:
            return 'failed'

Őry Máté committed
65
    @classmethod
66 67
    def create(cls, code_suffix, instance, task_uuid=None, user=None,
               concurrency_check=True):
68 69
        # Check for concurrent activities
        active_activities = instance.activity_log.filter(finished__isnull=True)
70
        if concurrency_check and active_activities.exists():
71 72
            raise ActivityInProgressError(active_activities[0])

73 74 75 76
        activity_code = join_activity_code(cls.ACTIVITY_CODE_BASE, code_suffix)
        act = cls(activity_code=activity_code, instance=instance, parent=None,
                  resultant_state=None, started=timezone.now(),
                  task_uuid=task_uuid, user=user)
Őry Máté committed
77 78 79
        act.save()
        return act

80
    def create_sub(self, code_suffix, task_uuid=None, concurrency_check=True):
81 82
        # Check for concurrent activities
        active_children = self.children.filter(finished__isnull=True)
83
        if concurrency_check and active_children.exists():
84 85
            raise ActivityInProgressError(active_children[0])

Őry Máté committed
86
        act = InstanceActivity(
87
            activity_code=join_activity_code(self.activity_code, code_suffix),
88 89
            instance=self.instance, parent=self, resultant_state=None,
            started=timezone.now(), task_uuid=task_uuid, user=self.user)
Őry Máté committed
90 91 92 93
        act.save()
        return act

    @contextmanager
94
    def sub_activity(self, code_suffix, on_abort=None, on_commit=None,
95
                     task_uuid=None, concurrency_check=True):
96 97
        """Create a transactional context for a nested instance activity.
        """
98
        act = self.create_sub(code_suffix, task_uuid, concurrency_check)
99
        return activitycontextimpl(act, on_abort=on_abort, on_commit=on_commit)
Őry Máté committed
100

101 102 103 104 105
    def save(self, *args, **kwargs):
        ret = super(InstanceActivity, self).save(*args, **kwargs)
        self.instance._update_status()
        return ret

Őry Máté committed
106 107

@contextmanager
108
def instance_activity(code_suffix, instance, on_abort=None, on_commit=None,
109
                      task_uuid=None, user=None, concurrency_check=True):
110 111
    """Create a transactional context for an instance activity.
    """
112 113
    act = InstanceActivity.create(code_suffix, instance, task_uuid, user,
                                  concurrency_check)
114
    return activitycontextimpl(act, on_abort=on_abort, on_commit=on_commit)
115 116 117


class NodeActivity(ActivityModel):
118
    ACTIVITY_CODE_BASE = join_activity_code('vm', 'Node')
119 120 121 122 123 124 125 126
    node = ForeignKey('Node', related_name='activity_log',
                      help_text=_('Node this activity works on.'),
                      verbose_name=_('node'))

    class Meta:
        app_label = 'vm'
        db_table = 'vm_nodeactivity'

127 128 129 130 131 132 133 134 135 136 137 138
    def __unicode__(self):
        if self.parent:
            return '{}({})->{}'.format(self.parent.activity_code,
                                       self.node,
                                       self.activity_code)
        else:
            return '{}({})'.format(self.activity_code,
                                   self.node)

    def get_readable_name(self):
        return self.activity_code.split('.')[-1].replace('_', ' ').capitalize()

139 140
    @classmethod
    def create(cls, code_suffix, node, task_uuid=None, user=None):
141 142 143
        activity_code = join_activity_code(cls.ACTIVITY_CODE_BASE, code_suffix)
        act = cls(activity_code=activity_code, node=node, parent=None,
                  started=timezone.now(), task_uuid=task_uuid, user=user)
144 145 146 147 148
        act.save()
        return act

    def create_sub(self, code_suffix, task_uuid=None):
        act = NodeActivity(
149
            activity_code=join_activity_code(self.activity_code, code_suffix),
150 151 152 153 154 155 156 157 158 159 160 161 162
            node=self.node, parent=self, started=timezone.now(),
            task_uuid=task_uuid, user=self.user)
        act.save()
        return act

    @contextmanager
    def sub_activity(self, code_suffix, task_uuid=None):
        act = self.create_sub(code_suffix, task_uuid)
        return activitycontextimpl(act)


@contextmanager
def node_activity(code_suffix, node, task_uuid=None, user=None):
163
    act = NodeActivity.create(code_suffix, node, task_uuid, user)
164
    return activitycontextimpl(act)