option to rollback action_plan when it fails
It has costs when rollback action_plan. So give users an option whether to rollback it when the action_plan fails. Change-Id: I20c0afded795eda7fb1b57ffdd2ae1ca36c45301
This commit is contained in:
@@ -25,8 +25,11 @@ from taskflow import task as flow_task
|
|||||||
|
|
||||||
from watcher.applier.workflow_engine import base
|
from watcher.applier.workflow_engine import base
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
|
from watcher import conf
|
||||||
from watcher import objects
|
from watcher import objects
|
||||||
|
|
||||||
|
CONF = conf.CONF
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -127,9 +130,11 @@ class DefaultWorkFlowEngine(base.BaseWorkFlowEngine):
|
|||||||
|
|
||||||
class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
|
class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
|
||||||
def __init__(self, db_action, engine):
|
def __init__(self, db_action, engine):
|
||||||
name = "action_type:{0} uuid:{1}".format(db_action.action_type,
|
self.name = "action_type:{0} uuid:{1}".format(db_action.action_type,
|
||||||
db_action.uuid)
|
db_action.uuid)
|
||||||
super(TaskFlowActionContainer, self).__init__(name, db_action, engine)
|
super(TaskFlowActionContainer, self).__init__(self.name,
|
||||||
|
db_action,
|
||||||
|
engine)
|
||||||
|
|
||||||
def do_pre_execute(self):
|
def do_pre_execute(self):
|
||||||
db_action = self.engine.notify(self._db_action,
|
db_action = self.engine.notify(self._db_action,
|
||||||
@@ -158,6 +163,12 @@ class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
|
|||||||
self.action.post_condition()
|
self.action.post_condition()
|
||||||
|
|
||||||
def do_revert(self, *args, **kwargs):
|
def do_revert(self, *args, **kwargs):
|
||||||
|
# NOTE: Not rollback action plan
|
||||||
|
if not CONF.watcher_applier.rollback_when_actionplan_failed:
|
||||||
|
LOG.info("Failed actionplan rollback option is turned off, and "
|
||||||
|
"the following action will be skipped: %s", self.name)
|
||||||
|
return
|
||||||
|
|
||||||
LOG.warning("Revert action: %s", self.name)
|
LOG.warning("Revert action: %s", self.name)
|
||||||
try:
|
try:
|
||||||
# TODO(jed): do we need to update the states in case of failure?
|
# TODO(jed): do we need to update the states in case of failure?
|
||||||
|
|||||||
@@ -43,11 +43,20 @@ APPLIER_MANAGER_OPTS = [
|
|||||||
help='Select the engine to use to execute the workflow'),
|
help='Select the engine to use to execute the workflow'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
APPLIER_OPTS = [
|
||||||
|
cfg.BoolOpt('rollback_when_actionplan_failed',
|
||||||
|
default=False,
|
||||||
|
help='If set True, the failed actionplan will rollback '
|
||||||
|
'when executing. Defaule value is False.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
conf.register_group(watcher_applier)
|
conf.register_group(watcher_applier)
|
||||||
conf.register_opts(APPLIER_MANAGER_OPTS, group=watcher_applier)
|
conf.register_opts(APPLIER_MANAGER_OPTS, group=watcher_applier)
|
||||||
|
conf.register_opts(APPLIER_OPTS, group=watcher_applier)
|
||||||
|
|
||||||
|
|
||||||
def list_opts():
|
def list_opts():
|
||||||
return [(watcher_applier, APPLIER_MANAGER_OPTS)]
|
return [(watcher_applier, APPLIER_MANAGER_OPTS),
|
||||||
|
(watcher_applier, APPLIER_OPTS)]
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
import eventlet
|
import eventlet
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
from watcher.applier.workflow_engine import default as tflow
|
from watcher.applier.workflow_engine import default as tflow
|
||||||
from watcher.common import clients
|
from watcher.common import clients
|
||||||
from watcher.common import nova_helper
|
from watcher.common import nova_helper
|
||||||
@@ -111,3 +113,52 @@ class TestTaskFlowActionContainer(base.DbTestCase):
|
|||||||
mock_eventlet_spawn.return_value = et
|
mock_eventlet_spawn.return_value = et
|
||||||
action_container.execute()
|
action_container.execute()
|
||||||
et.kill.assert_called_with()
|
et.kill.assert_called_with()
|
||||||
|
|
||||||
|
@mock.patch('watcher.applier.workflow_engine.default.LOG')
|
||||||
|
def test_execute_without_rollback(self, mock_log):
|
||||||
|
action_plan = obj_utils.create_test_action_plan(
|
||||||
|
self.context, audit_id=self.audit.id,
|
||||||
|
strategy_id=self.strategy.id,
|
||||||
|
state=objects.action_plan.State.ONGOING)
|
||||||
|
|
||||||
|
action = obj_utils.create_test_action(
|
||||||
|
self.context, action_plan_id=action_plan.id,
|
||||||
|
state=objects.action.State.FAILED,
|
||||||
|
action_type='nop',
|
||||||
|
input_parameters={'message': 'hello World'})
|
||||||
|
action_container = tflow.TaskFlowActionContainer(
|
||||||
|
db_action=action,
|
||||||
|
engine=self.engine)
|
||||||
|
|
||||||
|
cfg.CONF.set_override("rollback_when_actionplan_failed", False,
|
||||||
|
group="watcher_applier")
|
||||||
|
action_name = "action_type:{0} uuid:{1}".format(action.action_type,
|
||||||
|
action.uuid)
|
||||||
|
expected_log = ('Failed actionplan rollback option is turned off, '
|
||||||
|
'and the following action will be skipped: %s')
|
||||||
|
action_container.revert()
|
||||||
|
mock_log.info.assert_called_once_with(expected_log, action_name)
|
||||||
|
|
||||||
|
@mock.patch('watcher.applier.workflow_engine.default.LOG')
|
||||||
|
def test_execute_with_rollback(self, mock_log):
|
||||||
|
action_plan = obj_utils.create_test_action_plan(
|
||||||
|
self.context, audit_id=self.audit.id,
|
||||||
|
strategy_id=self.strategy.id,
|
||||||
|
state=objects.action_plan.State.ONGOING)
|
||||||
|
|
||||||
|
action = obj_utils.create_test_action(
|
||||||
|
self.context, action_plan_id=action_plan.id,
|
||||||
|
state=objects.action.State.FAILED,
|
||||||
|
action_type='nop',
|
||||||
|
input_parameters={'message': 'hello World'})
|
||||||
|
action_container = tflow.TaskFlowActionContainer(
|
||||||
|
db_action=action,
|
||||||
|
engine=self.engine)
|
||||||
|
|
||||||
|
cfg.CONF.set_override("rollback_when_actionplan_failed", True,
|
||||||
|
group="watcher_applier")
|
||||||
|
action_name = "action_type:{0} uuid:{1}".format(action.action_type,
|
||||||
|
action.uuid)
|
||||||
|
expected_log = 'Revert action: %s'
|
||||||
|
action_container.revert()
|
||||||
|
mock_log.warning.assert_called_once_with(expected_log, action_name)
|
||||||
|
|||||||
Reference in New Issue
Block a user