Merge "Release cluster lock on failed policy check"

This commit is contained in:
Zuul 2020-12-16 19:44:50 +00:00 committed by Gerrit Code Review
commit 6b60c7a87e
4 changed files with 59 additions and 47 deletions

View File

@ -496,21 +496,6 @@ class Action(object):
def is_resumed(self):
return self._check_signal() == self.SIG_RESUME
def _check_result(self, name):
"""Check policy status and generate event.
:param name: Name of policy checked
:return: True if the policy checking can be continued, or False if the
policy checking should be aborted.
"""
reason = self.data['reason']
if self.data['status'] == policy_mod.CHECK_OK:
return True
self.data['reason'] = ("Failed policy '%(name)s': %(reason)s"
) % {'name': name, 'reason': reason}
return False
def policy_check(self, cluster_id, target):
"""Check all policies attached to cluster and give result.
@ -526,9 +511,10 @@ class Action(object):
bindings = cpo.ClusterPolicy.get_all(self.context, cluster_id,
sort='priority',
filters={'enabled': True})
# default values
self.data['status'] = policy_mod.CHECK_OK
self.data['reason'] = 'Completed policy checking.'
self.data['status'] = policy_mod.CHECK_NONE
self.data['reason'] = ''
for pb in bindings:
policy = policy_mod.Policy.load(self.context, pb.policy_id,
@ -546,12 +532,22 @@ class Action(object):
else: # target == 'AFTER'
method = getattr(policy, 'post_op', None)
# call policy check function
# it will set result in data['status']
if method is not None:
method(cluster_id, self)
res = self._check_result(policy.name)
if res is False:
# stop policy check is one of them fails
if self.data['status'] == policy_mod.CHECK_ERROR:
reason = self.data['reason']
self.data['reason'] = ("Failed policy '%(name)s': %(reason)s"
) % {'name': policy.name,
'reason': reason}
return
self.data['status'] = policy_mod.CHECK_OK
self.data['reason'] = 'Completed policy checking.'
return
@staticmethod

View File

@ -25,9 +25,9 @@ from senlin.objects import credential as co
from senlin.objects import policy as po
CHECK_RESULTS = (
CHECK_OK, CHECK_ERROR,
CHECK_OK, CHECK_ERROR, CHECK_NONE
) = (
'OK', 'ERROR',
'OK', 'ERROR', 'NONE'
)

View File

@ -1025,29 +1025,6 @@ class ActionPolicyCheckTest(base.SenlinTestCase):
self.assertEqual(0, mock_pre_op.call_count)
self.assertEqual(0, mock_post_op.call_count)
def test_check_result_true(self):
cluster_id = CLUSTER_ID
action = ab.Action(cluster_id, 'OBJECT_ACTION', self.ctx)
action.data['status'] = policy_mod.CHECK_OK
action.data['reason'] = "Completed policy checking."
res = action._check_result('FAKE_POLICY_NAME')
self.assertTrue(res)
def test_check_result_false(self):
cluster_id = CLUSTER_ID
action = ab.Action(cluster_id, 'OBJECT_ACTION', self.ctx)
action.data['status'] = policy_mod.CHECK_ERROR
reason = ("Policy '%s' cooldown is still in progress." %
'FAKE_POLICY_2')
action.data['reason'] = reason
res = action._check_result('FAKE_POLICY_NAME')
reason = ("Failed policy '%(name)s': %(reason)s"
) % {'name': 'FAKE_POLICY_NAME', 'reason': reason}
self.assertFalse(res)
@mock.patch.object(cpo.ClusterPolicy, 'get_all')
@mock.patch.object(policy_mod.Policy, 'load')
def test_policy_check_pre_op(self, mock_load, mock_load_all):
@ -1115,8 +1092,7 @@ class ActionPolicyCheckTest(base.SenlinTestCase):
@mock.patch.object(cpo.ClusterPolicy, 'get_all')
@mock.patch.object(policy_mod.Policy, 'load')
@mock.patch.object(ab.Action, '_check_result')
def test_policy_check_abort_in_middle(self, mock_check, mock_load,
def test_policy_check_abort_in_middle(self, mock_load,
mock_load_all):
cluster_id = CLUSTER_ID
# Note: both policies are mocked
@ -1127,6 +1103,13 @@ class ActionPolicyCheckTest(base.SenlinTestCase):
TARGET=[('AFTER', 'OBJECT_ACTION')])
policy2.name = 'P2'
action = ab.Action(cluster_id, 'OBJECT_ACTION', self.ctx)
action.data = mock.MagicMock()
# mock action.data to return error for the first policy call
# (i.e. after policy1 post_op method has been called).
# this should stop the policy check and prevent the
# the policy2 post_op method from being called.
action.data.__getitem__.side_effect = [policy_mod.CHECK_ERROR, '']
# Note: policy binding is created but not stored
pb1 = self._create_cp_binding(cluster_id, policy1.id)
@ -1134,7 +1117,6 @@ class ActionPolicyCheckTest(base.SenlinTestCase):
mock_load_all.return_value = [pb1, pb2]
# mock return value for two calls
mock_load.side_effect = [policy1, policy2]
mock_check.side_effect = [False, True]
res = action.policy_check(cluster_id, 'AFTER')

View File

@ -637,6 +637,40 @@ class NodeActionTest(base.SenlinTestCase):
lock.NODE_SCOPE)
mock_check.assert_called_once_with('FAKE_CLUSTER', 'BEFORE')
@mock.patch.object(lock, 'cluster_lock_acquire')
@mock.patch.object(lock, 'cluster_lock_release')
@mock.patch.object(base_action.Action, 'policy_check')
def test_execute_policy_check_exception(self, mock_check, mock_release,
mock_acquire, mock_load):
node = mock.Mock()
node.id = 'NID'
node.cluster_id = 'FAKE_CLUSTER'
mock_load.return_value = node
action = node_action.NodeAction('NODE_ID', 'NODE_FLY', self.ctx,
cause='RPC Request')
action.id = 'ACTION_ID'
action.data = {
'status': policy_mod.CHECK_NONE,
'reason': ''
}
mock_acquire.return_value = action.id
mock_check.side_effect = Exception('error')
res_code, res_msg = action.execute()
reason = 'Policy check: '
self.assertEqual(action.RES_ERROR, res_code)
self.assertEqual(reason, res_msg)
mock_load.assert_called_once_with(action.context, node_id='NODE_ID')
mock_acquire.assert_called_once_with(self.ctx, 'FAKE_CLUSTER',
'ACTION_ID', None,
lock.NODE_SCOPE, False)
mock_release.assert_called_once_with('FAKE_CLUSTER', 'ACTION_ID',
lock.NODE_SCOPE)
mock_check.assert_called_once_with('FAKE_CLUSTER', 'BEFORE')
@mock.patch.object(lock, 'cluster_lock_acquire')
@mock.patch.object(lock, 'cluster_lock_release')
@mock.patch.object(lock, 'node_lock_acquire')