Commit 66ddb1a9 by Őry Máté

vm: add readable name to activities

parent 96f1d71c
......@@ -74,7 +74,8 @@ class Operation(object):
self.check_auth(user)
self.check_precond()
activity = self.create_activity(parent=parent_activity, user=user)
activity = self.create_activity(
parent=parent_activity, user=user, kwargs=kwargs)
return activity, allargs, auxargs
......@@ -150,7 +151,7 @@ class Operation(object):
raise PermissionDenied("%s doesn't have the required permissions."
% user)
def create_activity(self, parent, user):
def create_activity(self, parent, user, kwargs):
raise NotImplementedError
def on_abort(self, activity, error):
......@@ -159,6 +160,18 @@ class Operation(object):
"""
pass
def get_activity_name(self, kwargs):
try:
return self.activity_name
except AttributeError:
try:
return self.name._proxy____args[0] # ewww!
except AttributeError:
raise ImproperlyConfigured(
"Set Operation.activity_name to an ugettext_nooped "
"string or a create_readable call, or override "
"get_activity_name to create a name dynamically")
def on_commit(self, activity):
"""This method is called when the operation executes successfully.
"""
......
......@@ -18,6 +18,7 @@
from __future__ import absolute_import, unicode_literals
from contextlib import contextmanager
from logging import getLogger
from warnings import warn
from celery.signals import worker_ready
from celery.contrib.abortable import AbortableAsyncResult
......@@ -28,7 +29,8 @@ from django.utils import timezone
from django.utils.translation import ugettext_lazy as _, ugettext_noop
from common.models import (
ActivityModel, activitycontextimpl, create_readable, join_activity_code
ActivityModel, activitycontextimpl, create_readable, join_activity_code,
HumanReadableObject,
)
from manager.mancelery import celery
......@@ -49,6 +51,18 @@ class ActivityInProgressError(Exception):
self.activity = activity
def _normalize_readable_name(name, default=None):
if name is None:
warn("Set readable_name to a HumanReadableObject",
DeprecationWarning, 3)
name = default.replace(".", " ")
if not isinstance(name, HumanReadableObject):
name = create_readable(name)
return name
class InstanceActivity(ActivityModel):
ACTIVITY_CODE_BASE = join_activity_code('vm', 'Instance')
instance = ForeignKey('Instance', related_name='activity_log',
......@@ -75,7 +89,9 @@ class InstanceActivity(ActivityModel):
@classmethod
def create(cls, code_suffix, instance, task_uuid=None, user=None,
concurrency_check=True):
concurrency_check=True, readable_name=None):
readable_name = _normalize_readable_name(readable_name, code_suffix)
# Check for concurrent activities
active_activities = instance.activity_log.filter(finished__isnull=True)
if concurrency_check and active_activities.exists():
......@@ -84,11 +100,15 @@ class InstanceActivity(ActivityModel):
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(),
readable_name_data=readable_name.to_dict(),
task_uuid=task_uuid, user=user)
act.save()
return act
def create_sub(self, code_suffix, task_uuid=None, concurrency_check=True):
def create_sub(self, code_suffix, task_uuid=None, concurrency_check=True,
readable_name=None):
readable_name = _normalize_readable_name(readable_name, code_suffix)
# Check for concurrent activities
active_children = self.children.filter(finished__isnull=True)
if concurrency_check and active_children.exists():
......@@ -97,7 +117,8 @@ class InstanceActivity(ActivityModel):
act = InstanceActivity(
activity_code=join_activity_code(self.activity_code, code_suffix),
instance=self.instance, parent=self, resultant_state=None,
started=timezone.now(), task_uuid=task_uuid, user=self.user)
readable_name_data=readable_name.to_dict(), started=timezone.now(),
task_uuid=task_uuid, user=self.user)
act.save()
return act
......@@ -158,10 +179,12 @@ class InstanceActivity(ActivityModel):
@contextmanager
def sub_activity(self, code_suffix, on_abort=None, on_commit=None,
task_uuid=None, concurrency_check=True):
readable_name=None, task_uuid=None,
concurrency_check=True):
"""Create a transactional context for a nested instance activity.
"""
act = self.create_sub(code_suffix, task_uuid, concurrency_check)
act = self.create_sub(code_suffix, task_uuid, concurrency_check,
readable_name=readable_name)
return activitycontextimpl(act, on_abort=on_abort, on_commit=on_commit)
......@@ -195,24 +218,32 @@ class NodeActivity(ActivityModel):
self.node)
@classmethod
def create(cls, code_suffix, node, task_uuid=None, user=None):
def create(cls, code_suffix, node, task_uuid=None, user=None,
readable_name=None):
readable_name = _normalize_readable_name(readable_name, code_suffix)
activity_code = join_activity_code(cls.ACTIVITY_CODE_BASE, code_suffix)
act = cls(activity_code=activity_code, node=node, parent=None,
readable_name_data=readable_name.to_dict(),
started=timezone.now(), task_uuid=task_uuid, user=user)
act.save()
return act
def create_sub(self, code_suffix, task_uuid=None):
def create_sub(self, code_suffix, task_uuid=None, readable_name=None):
readable_name = _normalize_readable_name(readable_name, code_suffix)
act = NodeActivity(
activity_code=join_activity_code(self.activity_code, code_suffix),
node=self.node, parent=self, started=timezone.now(),
task_uuid=task_uuid, user=self.user)
readable_name_data=readable_name.to_dict(), 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)
def sub_activity(self, code_suffix, task_uuid=None, readable_name=None):
act = self.create_sub(code_suffix, task_uuid,
readable_name=readable_name)
return activitycontextimpl(act)
......
......@@ -21,10 +21,11 @@ from re import search
from django.core.exceptions import PermissionDenied
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, ugettext_noop
from celery.exceptions import TimeLimitExceeded
from common.models import create_readable
from common.operations import Operation, register_operation
from .tasks.local_tasks import (
abortable_async_instance_operation, abortable_async_node_operation,
......@@ -59,7 +60,8 @@ class InstanceOperation(Operation):
super(InstanceOperation, self).check_auth(user=user)
def create_activity(self, parent, user):
def create_activity(self, parent, user, kwargs):
name = self.get_activity_name(kwargs)
if parent:
if parent.instance != self.instance:
raise ValueError("The instance associated with the specified "
......@@ -70,11 +72,13 @@ class InstanceOperation(Operation):
"parent activity does not match the user "
"provided as parameter.")
return parent.create_sub(code_suffix=self.activity_code_suffix)
return parent.create_sub(code_suffix=self.activity_code_suffix,
readable_name=name)
else:
return InstanceActivity.create(
code_suffix=self.activity_code_suffix, instance=self.instance,
user=user, concurrency_check=self.concurrency_check)
readable_name=name, user=user,
concurrency_check=self.concurrency_check)
def is_preferred(self):
"""If this is the recommended op in the current state of the instance.
......@@ -102,6 +106,10 @@ class AddInterfaceOperation(InstanceOperation):
return net
def get_activity_name(self, kwargs):
return create_readable(ugettext_noop("add %(vlan)s interface"),
vlan=kwargs['vlan'])
register_operation(AddInterfaceOperation)
......@@ -646,7 +654,8 @@ class NodeOperation(Operation):
super(NodeOperation, self).__init__(subject=node)
self.node = node
def create_activity(self, parent, user):
def create_activity(self, parent, user, kwargs):
name = self.get_activity_name(kwargs)
if parent:
if parent.node != self.node:
raise ValueError("The node associated with the specified "
......@@ -657,10 +666,12 @@ class NodeOperation(Operation):
"parent activity does not match the user "
"provided as parameter.")
return parent.create_sub(code_suffix=self.activity_code_suffix)
return parent.create_sub(code_suffix=self.activity_code_suffix,
readable_name=name)
else:
return NodeActivity.create(code_suffix=self.activity_code_suffix,
node=self.node, user=user)
node=self.node, user=user,
readable_name=name)
class FlushOperation(NodeOperation):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment