Commit 66ddb1a9 by Őry Máté

vm: add readable name to activities

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