diff --git a/senlin/common/consts.py b/senlin/common/consts.py index 1f961ed98..463595513 100755 --- a/senlin/common/consts.py +++ b/senlin/common/consts.py @@ -336,3 +336,11 @@ HEALTH_CHECK_MESSAGE = ( 'Poll URL health check passed', 'Poll URL health check failed', ) + +CONFLICT_BYPASS_ACTIONS = [ + CLUSTER_DELETE, NODE_DELETE, NODE_OPERATION, +] + +LOCK_BYPASS_ACTIONS = [ + CLUSTER_DELETE, NODE_DELETE, NODE_OPERATION, +] diff --git a/senlin/engine/actions/base.py b/senlin/engine/actions/base.py index ab0e1c5fc..715a8ccdd 100755 --- a/senlin/engine/actions/base.py +++ b/senlin/engine/actions/base.py @@ -271,8 +271,7 @@ class Action(object): @staticmethod def _check_action_lock(target, action): - if action == consts.CLUSTER_DELETE or action == consts.NODE_DELETE: - # DELETE actions do not care about locks + if action in consts.LOCK_BYPASS_ACTIONS: return elif (action in list(consts.CLUSTER_ACTION_NAMES) and cl.ClusterLock.is_locked(target)): @@ -287,8 +286,7 @@ class Action(object): def _check_conflicting_actions(ctx, target, action): conflict_actions = ao.Action.get_all_active_by_target(ctx, target) # Ignore conflicting actions on deletes. - if not conflict_actions or action in (consts.CLUSTER_DELETE, - consts.NODE_DELETE): + if not conflict_actions or action in consts.CONFLICT_BYPASS_ACTIONS: return else: action_ids = [a['id'] for a in conflict_actions] diff --git a/senlin/tests/unit/engine/actions/test_action_base.py b/senlin/tests/unit/engine/actions/test_action_base.py index e74548474..9ce3080ea 100755 --- a/senlin/tests/unit/engine/actions/test_action_base.py +++ b/senlin/tests/unit/engine/actions/test_action_base.py @@ -381,6 +381,27 @@ class ActionBaseTest(base.SenlinTestCase): mock_store.assert_called_once_with(self.ctx) mock_active.assert_called_once_with(mock.ANY, OBJID) + @mock.patch.object(ab.Action, 'store') + @mock.patch.object(ao.Action, 'get_all_active_by_target') + @mock.patch.object(cl.ClusterLock, 'is_locked') + def test_action_create_node_operation_no_conflict(self, mock_lock, + mock_active, mock_store): + mock_store.return_value = 'FAKE_ID' + uuid1 = 'ce982cd5-26da-4e2c-84e5-be8f720b7478' + uuid2 = 'ce982cd5-26da-4e2c-84e5-be8f720b7479' + mock_active.return_value = [ + ao.Action(id=uuid1, action='NODE_DELETE'), + ao.Action(id=uuid2, action='NODE_DELETE') + ] + mock_lock.return_value = True + + result = ab.Action.create(self.ctx, OBJID, 'NODE_OPERATION', + name='test') + + self.assertEqual('FAKE_ID', result) + mock_store.assert_called_once_with(self.ctx) + mock_active.assert_called_once_with(mock.ANY, OBJID) + @mock.patch.object(timeutils, 'is_older_than') @mock.patch.object(cpo.ClusterPolicy, 'get_all') @mock.patch.object(policy_mod.Policy, 'load')