Fix node lock aquire to force with node operation

This patch fixes the node_operation action to properly
steal the lock for the node. This is to prevent failures
when a delete action is using node_stop_on_delete.

Change-Id: I97fbc126bef4cd1bec65201320365cf6fa2f41e4
This commit is contained in:
Jude Cross 2019-02-01 13:45:05 -08:00
parent 8bc176742c
commit 7581f527ca
4 changed files with 51 additions and 3 deletions

View File

@ -1179,7 +1179,7 @@ class ClusterAction(base.Action):
was a success and why if it wasn't a success.
"""
# Try to lock cluster before do real operation
forced = True if self.action == consts.CLUSTER_DELETE else False
forced = (self.action == consts.CLUSTER_DELETE)
res = senlin_lock.cluster_lock_acquire(self.context, self.target,
self.id, self.owner,
senlin_lock.CLUSTER_SCOPE,

View File

@ -247,6 +247,7 @@ class NodeAction(base.Action):
"""
# Since node.cluster_id could be reset to '' during action execution,
# we record it here for policy check and cluster lock release.
forced = (self.action in [consts.NODE_DELETE, consts.NODE_OPERATION])
saved_cluster_id = self.entity.cluster_id
if saved_cluster_id:
if self.cause == consts.CAUSE_RPC:
@ -268,11 +269,11 @@ class NodeAction(base.Action):
return self.RES_ERROR, ('Policy check: ' +
self.data['reason'])
elif self.cause == consts.CAUSE_DERIVED_LCH:
self.policy_check(self.entity.cluster_id, 'BEFORE')
self.policy_check(saved_cluster_id, 'BEFORE')
try:
res = senlin_lock.node_lock_acquire(self.context, self.entity.id,
self.id, self.owner, False)
self.id, self.owner, forced)
if not res:
res = self.RES_RETRY
reason = 'Failed in locking node'

View File

@ -1995,6 +1995,7 @@ class EngineService(service.Service):
db_node = node_obj.Node.find(ctx, req.identity)
node = node_mod.Node.load(ctx, db_node=db_node)
profile = node.rt['profile']
if req.operation not in profile.OPERATIONS:
msg = _("The requested operation '%(o)s' is not supported by the "

View File

@ -716,6 +716,52 @@ class NodeActionTest(base.SenlinTestCase):
'ACTION_ID', None, False)
mock_release_node.assert_called_once_with('NODE_ID', 'ACTION_ID')
@mock.patch.object(lock, 'cluster_lock_acquire')
@mock.patch.object(lock, 'cluster_lock_release')
@mock.patch.object(base_action.Action, 'policy_check')
@mock.patch.object(lock, 'node_lock_acquire')
@mock.patch.object(lock, 'node_lock_release')
def test_execute_success_stealing_node_lock(self, mock_release_node,
mock_acquire_node, mock_check,
mock_release, mock_acquire,
mock_load):
node = mock.Mock()
node.cluster_id = 'FAKE_CLUSTER'
node.id = 'NODE_ID'
mock_load.return_value = node
action = node_action.NodeAction('NODE_ID', 'NODE_OPERATION', self.ctx,
cause='RPC Request')
action.id = 'ACTION_ID'
action.data = {
'status': policy_mod.CHECK_OK,
'reason': 'Policy checking passed'
}
action.inputs = {'operation': 'stop', 'params': {}}
mock_acquire.return_value = 'ACTION_ID'
mock_acquire_node.return_value = True
res_code, res_msg = action.execute()
reason = "Node operation 'stop' succeeded."
self.assertEqual(action.RES_OK, 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)
policy_calls = [
mock.call('FAKE_CLUSTER', 'BEFORE'),
mock.call('FAKE_CLUSTER', 'AFTER')
]
mock_release.assert_called_once_with('FAKE_CLUSTER', 'ACTION_ID',
lock.NODE_SCOPE)
mock_check.assert_has_calls(policy_calls)
mock_acquire_node.assert_called_once_with(self.ctx, 'NODE_ID',
'ACTION_ID', None, True)
mock_release_node.assert_called_once_with('NODE_ID', 'ACTION_ID')
@mock.patch.object(lock, 'cluster_lock_acquire')
@mock.patch.object(lock, 'cluster_lock_release')
@mock.patch.object(base_action.Action, 'policy_check')