From cbf6979aaea215220e18b9a25a5d6d08f8f3ac3e Mon Sep 17 00:00:00 2001 From: Őry Máté <ory.mate@cloud.bme.hu> Date: Tue, 23 Sep 2014 21:31:39 +0200 Subject: [PATCH] vm: add new Node operations --- circle/vm/models/node.py | 29 +++-------------------------- circle/vm/operations.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/circle/vm/models/node.py b/circle/vm/models/node.py index b0dab3d..30554cd 100644 --- a/circle/vm/models/node.py +++ b/circle/vm/models/node.py @@ -27,7 +27,7 @@ from django.db.models import ( FloatField, permalink, ) from django.utils import timezone -from django.utils.translation import ugettext_lazy as _, ugettext_noop +from django.utils.translation import ugettext_lazy as _ from celery.exceptions import TimeoutError from model_utils.models import TimeStampedModel @@ -37,7 +37,7 @@ from common.models import method_cache, WorkerNotFound, HumanSortField from common.operations import OperatedMixin from firewall.models import Host from ..tasks import vm_tasks -from .activity import node_activity, NodeActivity +from .activity import NodeActivity from .common import Trait @@ -145,31 +145,8 @@ class Node(OperatedMixin, TimeStampedModel): def get_status_display(self): return self.STATES[self.enabled][self.online][1] - def disable(self, user=None, base_activity=None): - ''' Disable the node.''' - if self.enabled: - if base_activity: - act_ctx = base_activity.sub_activity( - 'disable', readable_name=ugettext_noop("disable node")) - else: - act_ctx = node_activity( - 'disable', node=self, user=user, - readable_name=ugettext_noop("disable node")) - with act_ctx: - self.enabled = False - self.save() - def enable(self, user=None, base_activity=None): - ''' Enable the node. ''' - if self.enabled is not True: - if base_activity: - act_ctx = base_activity.sub_activity('enable') - else: - act_ctx = node_activity('enable', node=self, user=user) - with act_ctx: - self.enabled = True - self.save() - self.get_info(invalidate_cache=True) + raise NotImplementedError("Use activate or passivate instead.") @property @node_available diff --git a/circle/vm/operations.py b/circle/vm/operations.py index 43e6828..b42c19a 100644 --- a/circle/vm/operations.py +++ b/circle/vm/operations.py @@ -803,11 +803,20 @@ class ChangeStateOperation(InstanceOperation): class NodeOperation(Operation): async_operation = abortable_async_node_operation host_cls = Node + online_required = True + superuser_required = True def __init__(self, node): super(NodeOperation, self).__init__(subject=node) self.node = node + def check_precond(self): + super(NodeOperation, self).check_precond() + if self.online_required and not self.node.online: + raise humanize_exception(ugettext_noop( + "You cannot call this operation on an offline node."), + Exception()) + def create_activity(self, parent, user, kwargs): name = self.get_activity_name(kwargs) if parent: @@ -833,20 +842,14 @@ class FlushOperation(NodeOperation): activity_code_suffix = 'flush' id = 'flush' name = _("flush") - description = _("Disable node and move all instances to other ones.") + description = _("Passivate node and move all instances to other ones.") required_perms = () - superuser_required = True async_queue = "localhost.man.slow" - def on_abort(self, activity, error): - from manager.scheduler import TraitsUnsatisfiableException - if isinstance(error, TraitsUnsatisfiableException): - if self.node_enabled: - self.node.enable(activity.user, activity) - def _operation(self, activity, user): - self.node_enabled = self.node.enabled - self.node.disable(user, activity) + if self.node.schedule_enabled: + PassivateOperation(self.node).call(parent_activity=activity, + user=user) for i in self.node.instance_set.all(): name = create_readable(ugettext_noop( "migrate %(instance)s (%(pk)s)"), instance=i.name, pk=i.pk) @@ -855,6 +858,72 @@ class FlushOperation(NodeOperation): i.migrate(user=user) +@register_operation +class ActivateOperation(NodeOperation): + activity_code_suffix = 'activate' + id = 'activate' + name = _("activate") + description = _("Make node active, i.e. scheduler is allowed to deploy " + "virtual machines to it.") + required_perms = () + + def check_precond(self): + super(ActivateOperation, self).check_precond() + if self.node.enabled and self.node.schedule_enabled: + raise humanize_exception(ugettext_noop( + "You cannot activate an active node."), Exception()) + + def _operation(self): + self.node.enabled = True + self.node.schedule_enabled = True + self.node.save() + + +@register_operation +class PassivateOperation(NodeOperation): + activity_code_suffix = 'passivate' + id = 'passivate' + name = _("passivate") + description = _("Make node passive, i.e. scheduler is denied to deploy " + "virtual machines to it, but remaining instances and " + "the ones manually migrated will continue running.") + required_perms = () + + def check_precond(self): + if self.node.enabled and not self.node.schedule_enabled: + raise humanize_exception(ugettext_noop( + "You cannot passivate a passive node."), Exception()) + super(PassivateOperation, self).check_precond() + + def _operation(self): + self.node.enabled = True + self.node.schedule_enabled = False + self.node.save() + + +@register_operation +class DisableOperation(NodeOperation): + activity_code_suffix = 'disable' + id = 'disable' + name = _("disable") + description = _("Disable node.") + required_perms = () + online_required = False + + def check_precond(self): + if not self.node.enabled: + raise humanize_exception(ugettext_noop( + "You cannot disable a disabled node."), Exception()) + if self.node.instance_set.exists(): + raise humanize_exception(ugettext_noop( + "You cannot disable a node which is hosting instances."), + Exception()) + super(DisableOperation, self).check_precond() + + def _operation(self): + self.node.enabled = False + self.node.schedule_enabled = False + self.node.save() @register_operation -- libgit2 0.26.0