576 lines
25 KiB
Python
576 lines
25 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import mock
|
|
|
|
from senlin.common import scaleutils
|
|
from senlin.engine.actions import base as base_action
|
|
from senlin.engine.actions import node_action
|
|
from senlin.engine import cluster as cluster_mod
|
|
from senlin.engine import event as event_mod
|
|
from senlin.engine import node as node_mod
|
|
from senlin.engine import senlin_lock as lock
|
|
from senlin.policies import base as policy_mod
|
|
from senlin.tests.unit.common import base
|
|
from senlin.tests.unit.common import utils
|
|
|
|
|
|
@mock.patch.object(node_mod.Node, 'load')
|
|
class NodeActionTest(base.SenlinTestCase):
|
|
|
|
def setUp(self):
|
|
super(NodeActionTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
|
|
def test_do_create(self, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
node.do_create = mock.Mock(return_value=None)
|
|
mock_load.return_value = node
|
|
action = node_action.NodeAction(node.id, 'ACTION', self.ctx)
|
|
|
|
# Test node creation failure path
|
|
res_code, res_msg = action.do_create()
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
self.assertEqual('Node creation failed.', res_msg)
|
|
node.do_create.assert_called_once_with(action.context)
|
|
node.reset_mock()
|
|
|
|
# Test node creation success path
|
|
node.do_create = mock.Mock(return_value=mock.Mock())
|
|
res_code, res_msg = action.do_create()
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
self.assertEqual('Node created successfully.', res_msg)
|
|
node.do_create.assert_called_once_with(action.context)
|
|
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
def test_do_create_with_cluster_id_specified(self, mock_c_load,
|
|
mock_check, mock_load):
|
|
cluster = mock.Mock()
|
|
cluster.id = 'CID'
|
|
cluster.desired_capacity = 0
|
|
mock_c_load.return_value = cluster
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
node.do_create = mock.Mock(return_value=None)
|
|
node.cluster_id = cluster.id
|
|
mock_load.return_value = node
|
|
mock_check.return_value = ''
|
|
action = node_action.NodeAction(node.id, 'ACTION', self.ctx,
|
|
cause=base_action.CAUSE_RPC)
|
|
|
|
node.do_create = mock.Mock(return_value=mock.Mock())
|
|
res_code, res_msg = action.do_create()
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
mock_check.assert_called_once_with(cluster, 1, None, None, True)
|
|
mock_c_load.assert_called_once_with(action.context, 'CID')
|
|
cluster.store.assert_called_once_with(action.context)
|
|
self.assertEqual(1, cluster.desired_capacity)
|
|
cluster.add_node.assert_called_once_with(node)
|
|
|
|
def test_do_delete(self, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
node.do_delete = mock.Mock(return_value=None)
|
|
mock_load.return_value = node
|
|
action = node_action.NodeAction('ID', 'ACTION', self.ctx)
|
|
|
|
# Test failed node deletion path
|
|
res_code, res_msg = action.do_delete()
|
|
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
self.assertEqual('Node deletion failed.', res_msg)
|
|
node.do_delete.assert_called_once_with(action.context)
|
|
node.reset_mock()
|
|
|
|
# Test node deletion success path
|
|
node.do_delete = mock.Mock(return_value=mock.Mock())
|
|
res_code, res_msg = action.do_delete()
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
self.assertEqual('Node deleted successfully.', res_msg)
|
|
node.do_delete.assert_called_once_with(action.context)
|
|
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
def test_do_delete_with_cluster_id_specified(self, mock_c_load,
|
|
mock_check, mock_load):
|
|
cluster = mock.Mock()
|
|
cluster.id = 'CID'
|
|
cluster.desired_capacity = 1
|
|
mock_c_load.return_value = cluster
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
node.do_delete = mock.Mock(return_value=None)
|
|
node.cluster_id = cluster.id
|
|
mock_load.return_value = node
|
|
mock_check.return_value = ''
|
|
action = node_action.NodeAction(node.id, 'ACTION', self.ctx,
|
|
cause=base_action.CAUSE_RPC)
|
|
|
|
node.do_delete = mock.Mock(return_value=mock.Mock())
|
|
|
|
res_code, res_msg = action.do_delete()
|
|
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
mock_check.assert_called_once_with(cluster, 0, None, None, True)
|
|
mock_c_load.assert_called_once_with(action.context, 'CID')
|
|
cluster.store.assert_called_once_with(action.context)
|
|
self.assertEqual(0, cluster.desired_capacity)
|
|
cluster.remove_node.assert_called_once_with(node.id)
|
|
|
|
def test_do_update(self, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
inputs = {"new_profile_id": "FAKE_PROFILE_ID"}
|
|
action = node_action.NodeAction(node.id, 'ACTION', self.ctx,
|
|
inputs=inputs)
|
|
|
|
# Test failed node update path
|
|
node.do_update = mock.Mock(return_value=None)
|
|
res_code, res_msg = action.do_update()
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
self.assertEqual('Node update failed.', res_msg)
|
|
node.do_update.assert_called_once_with(action.context, inputs)
|
|
node.reset_mock()
|
|
|
|
# Test node update success path
|
|
node.do_update = mock.Mock(return_value=mock.Mock())
|
|
res_code, res_msg = action.do_update()
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
self.assertEqual('Node updated successfully.', res_msg)
|
|
node.do_update.assert_called_once_with(action.context, inputs)
|
|
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
def test_do_join_success(self, mock_check, mock_c_load, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
inputs = {"cluster_id": "FAKE_ID"}
|
|
action = node_action.NodeAction(node.id, 'NODE_JOIN', self.ctx,
|
|
inputs=inputs)
|
|
cluster = mock.Mock()
|
|
cluster.desired_capacity = 100
|
|
mock_c_load.return_value = cluster
|
|
mock_check.return_value = ''
|
|
node.do_join = mock.Mock(return_value=True)
|
|
|
|
# Test failed node join path
|
|
res_code, res_msg = action.do_join()
|
|
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
self.assertEqual('Node successfully joined cluster.', res_msg)
|
|
node.do_join.assert_called_once_with(action.context, 'FAKE_ID')
|
|
mock_calls = [mock.call(action.context, 'FAKE_ID'),
|
|
mock.call(action.context, 'FAKE_ID')]
|
|
mock_c_load.assert_has_calls(mock_calls)
|
|
mock_check.assert_called_once_with(cluster, 101, None, None, True)
|
|
self.assertEqual(101, cluster.desired_capacity)
|
|
cluster.store.assert_called_once_with(action.context)
|
|
cluster.add_node.assert_called_once_with(node)
|
|
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
def test_do_join_fail_size_check(self, mock_check, mock_c_load, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
inputs = {"cluster_id": "FAKE_ID"}
|
|
action = node_action.NodeAction(node.id, 'NODE_JOIN', self.ctx,
|
|
inputs=inputs)
|
|
cluster = mock.Mock()
|
|
cluster.desired_capacity = 100
|
|
mock_c_load.return_value = cluster
|
|
mock_check.return_value = 'Size limits'
|
|
node.do_join = mock.Mock(return_value=True)
|
|
|
|
# Test failed node join path
|
|
res_code, res_msg = action.do_join()
|
|
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
self.assertEqual('Size limits', res_msg)
|
|
mock_c_load.assert_called_once_with(action.context, 'FAKE_ID')
|
|
mock_check.assert_called_once_with(cluster, 101, None, None, True)
|
|
self.assertEqual(0, node.do_join.call_count)
|
|
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
def test_do_join_failed_do_join(self, mock_check, mock_c_load, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
inputs = {"cluster_id": "FAKE_ID"}
|
|
action = node_action.NodeAction(node.id, 'NODE_JOIN', self.ctx,
|
|
inputs=inputs)
|
|
cluster = mock.Mock()
|
|
cluster.desired_capacity = 100
|
|
mock_c_load.return_value = cluster
|
|
mock_check.return_value = ''
|
|
node.do_join = mock.Mock(return_value=False)
|
|
|
|
# Test failed node join path
|
|
res_code, res_msg = action.do_join()
|
|
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
self.assertEqual('Node failed in joining cluster.', res_msg)
|
|
mock_c_load.assert_called_once_with(action.context, 'FAKE_ID')
|
|
mock_check.assert_called_once_with(cluster, 101, None, None, True)
|
|
node.do_join.assert_called_once_with(action.context, 'FAKE_ID')
|
|
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
def test_do_leave_success(self, mock_check, mock_c_load, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
node.cluster_id = 'FAKE_ID'
|
|
action = node_action.NodeAction(node.id, 'NODE_LEAVE', self.ctx)
|
|
cluster = mock.Mock()
|
|
cluster.id = 'FAKE_ID'
|
|
cluster.desired_capacity = 100
|
|
mock_c_load.return_value = cluster
|
|
mock_check.return_value = ''
|
|
node.do_leave = mock.Mock(return_value=True)
|
|
|
|
# Test failed node join path
|
|
res_code, res_msg = action.do_leave()
|
|
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
self.assertEqual('Node successfully left cluster.', res_msg)
|
|
node.do_leave.assert_called_once_with(action.context)
|
|
mock_calls = [mock.call(action.context, 'FAKE_ID'),
|
|
mock.call(action.context, 'FAKE_ID')]
|
|
mock_c_load.assert_has_calls(mock_calls)
|
|
mock_check.assert_called_once_with(cluster, 99, None, None, True)
|
|
self.assertEqual(99, cluster.desired_capacity)
|
|
cluster.store.assert_called_once_with(action.context)
|
|
cluster.remove_node.assert_called_once_with('NID')
|
|
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
def test_do_leave_failed_check(self, mock_check, mock_c_load, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
node.cluster_id = 'FAKE_ID'
|
|
mock_load.return_value = node
|
|
action = node_action.NodeAction(node.id, 'NODE_LEAVE', self.ctx)
|
|
cluster = mock.Mock()
|
|
cluster.desired_capacity = 100
|
|
mock_c_load.return_value = cluster
|
|
mock_check.return_value = 'Size limits'
|
|
node.do_leave = mock.Mock(return_value=True)
|
|
|
|
# Test failed node join path
|
|
res_code, res_msg = action.do_leave()
|
|
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
self.assertEqual('Size limits', res_msg)
|
|
mock_c_load.assert_called_once_with(action.context, 'FAKE_ID')
|
|
mock_check.assert_called_once_with(cluster, 99, None, None, True)
|
|
self.assertEqual(0, node.do_leave.call_count)
|
|
|
|
@mock.patch.object(cluster_mod.Cluster, 'load')
|
|
@mock.patch.object(scaleutils, 'check_size_params')
|
|
def test_do_leave_failed_do_leave(self, mock_check, mock_c_load,
|
|
mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
node.cluster_id = 'FAKE_ID'
|
|
mock_load.return_value = node
|
|
action = node_action.NodeAction(node.id, 'NODE_LEAVE', self.ctx)
|
|
cluster = mock.Mock()
|
|
cluster.desired_capacity = 100
|
|
mock_c_load.return_value = cluster
|
|
mock_check.return_value = ''
|
|
node.do_leave = mock.Mock(return_value=False)
|
|
|
|
# Test failed node join path
|
|
res_code, res_msg = action.do_leave()
|
|
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
self.assertEqual('Node failed in leaving cluster.', res_msg)
|
|
node.do_leave.assert_called_once_with(action.context)
|
|
mock_c_load.assert_called_once_with(action.context, 'FAKE_ID')
|
|
mock_check.assert_called_once_with(cluster, 99, None, None, True)
|
|
|
|
def test_execute(self, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
action = node_action.NodeAction(node.id, 'NODE_SING', self.ctx)
|
|
action.do_sing = mock.Mock(return_value=(action.RES_OK, 'GOOD'))
|
|
|
|
res_code, res_msg = action._execute()
|
|
|
|
self.assertEqual(action.RES_OK, res_code)
|
|
self.assertEqual('GOOD', res_msg)
|
|
action.do_sing.assert_called_once_with()
|
|
|
|
@mock.patch.object(event_mod, 'error')
|
|
def test_execute_bad_action(self, mock_error, mock_load):
|
|
node = mock.Mock()
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
action = node_action.NodeAction(node.id, 'NODE_DANCE', self.ctx)
|
|
|
|
res_code, res_msg = action._execute()
|
|
|
|
self.assertEqual(action.RES_ERROR, res_code)
|
|
reason = 'Unsupported action: NODE_DANCE'
|
|
self.assertEqual(reason, res_msg)
|
|
mock_error.assert_called_once_with(action.context, node,
|
|
action.action, 'Failed',
|
|
reason)
|
|
|
|
@mock.patch.object(lock, 'cluster_lock_acquire')
|
|
def test_execute_failed_lock_cluster(self, mock_acquire, mock_load):
|
|
node = mock.Mock()
|
|
node.cluster_id = 'FAKE_CLUSTER'
|
|
node.id = 'NID'
|
|
mock_load.return_value = node
|
|
action = node_action.NodeAction('NODE_ID', 'NODE_FLY', self.ctx,
|
|
cause='RPC Request')
|
|
action.id = 'ACTION_ID'
|
|
mock_acquire.return_value = None
|
|
|
|
res_code, res_msg = action.execute()
|
|
|
|
reason = 'Failed in locking cluster'
|
|
self.assertEqual(action.RES_RETRY, 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',
|
|
lock.NODE_SCOPE, False)
|
|
|
|
@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_failed_policy_check(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_ERROR,
|
|
'reason': 'Failed policy checking'
|
|
}
|
|
mock_acquire.return_value = action.id
|
|
|
|
res_code, res_msg = action.execute()
|
|
|
|
reason = 'Policy check: Failed policy checking'
|
|
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',
|
|
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(base_action.Action, 'policy_check')
|
|
@mock.patch.object(lock, 'node_lock_acquire')
|
|
@mock.patch.object(lock, 'node_lock_release')
|
|
def test_execute_failed_locking_node(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_FLY', self.ctx,
|
|
cause='RPC Request')
|
|
action.id = 'ACTION_ID'
|
|
action.data = {
|
|
'status': policy_mod.CHECK_OK,
|
|
'reason': 'Policy checking passed'
|
|
}
|
|
mock_acquire.return_value = 'ACTION_ID'
|
|
mock_acquire_node.return_value = None
|
|
|
|
res_code, res_msg = action.execute()
|
|
|
|
reason = 'Failed in locking node'
|
|
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',
|
|
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_acquire_node.assert_called_once_with(self.ctx, 'NODE_ID',
|
|
'ACTION_ID', 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(self, mock_release_node, mock_acquire_node,
|
|
mock_check, mock_release, mock_acquire,
|
|
mock_load):
|
|
def fake_execute():
|
|
node.cluster_id = None
|
|
return (action.RES_OK, 'Execution ok')
|
|
|
|
node = mock.Mock()
|
|
node.cluster_id = 'FAKE_CLUSTER'
|
|
node.id = 'NODE_ID'
|
|
mock_load.return_value = node
|
|
|
|
action = node_action.NodeAction(node.id, 'NODE_FLY', self.ctx,
|
|
cause='RPC Request')
|
|
action.id = 'ACTION_ID'
|
|
# check result
|
|
action.data = {
|
|
'status': policy_mod.CHECK_OK,
|
|
'reason': 'Policy checking passed'
|
|
}
|
|
self.patchobject(action, '_execute', side_effect=fake_execute)
|
|
mock_acquire.return_value = 'ACTION_ID'
|
|
mock_acquire_node.return_value = 'ACTION_ID'
|
|
|
|
res_code, res_msg = action.execute()
|
|
|
|
reason = 'Execution ok'
|
|
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',
|
|
lock.NODE_SCOPE, False)
|
|
mock_release.assert_called_once_with('FAKE_CLUSTER', 'ACTION_ID',
|
|
lock.NODE_SCOPE)
|
|
mock_acquire_node.assert_called_once_with(self.ctx, 'NODE_ID',
|
|
'ACTION_ID', False)
|
|
mock_release_node.assert_called_once_with('NODE_ID', 'ACTION_ID')
|
|
check_calls = [
|
|
mock.call('FAKE_CLUSTER', 'BEFORE'),
|
|
mock.call('FAKE_CLUSTER', 'AFTER')
|
|
]
|
|
mock_check.assert_has_calls(check_calls)
|
|
|
|
@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_failed_execute(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_FLY', self.ctx,
|
|
cause='RPC Request')
|
|
action.id = 'ACTION_ID'
|
|
# check result
|
|
action.data = {
|
|
'status': policy_mod.CHECK_OK,
|
|
'reason': 'Policy checking passed'
|
|
}
|
|
self.patchobject(action, '_execute',
|
|
return_value=(action.RES_ERROR, 'Execution Failed'))
|
|
mock_acquire.return_value = 'ACTION_ID'
|
|
mock_acquire_node.return_value = 'ACTION_ID'
|
|
|
|
res_code, res_msg = action.execute()
|
|
|
|
reason = 'Execution Failed'
|
|
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',
|
|
lock.NODE_SCOPE, False)
|
|
mock_release.assert_called_once_with('FAKE_CLUSTER', 'ACTION_ID',
|
|
lock.NODE_SCOPE)
|
|
mock_acquire_node.assert_called_once_with(self.ctx, 'NODE_ID',
|
|
'ACTION_ID', False)
|
|
mock_release_node.assert_called_once_with('NODE_ID', 'ACTION_ID')
|
|
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')
|
|
@mock.patch.object(lock, 'node_lock_release')
|
|
def test_execute_failed_post_check(self, mock_release_node,
|
|
mock_acquire_node,
|
|
mock_release, mock_acquire,
|
|
mock_load):
|
|
|
|
def fake_check(cluster_id, target):
|
|
if target == 'BEFORE':
|
|
action.data = {
|
|
'status': policy_mod.CHECK_OK,
|
|
'reason': 'Policy checking passed'
|
|
}
|
|
else:
|
|
action.data = {
|
|
'status': policy_mod.CHECK_ERROR,
|
|
'reason': 'Policy checking failed'
|
|
}
|
|
|
|
node = mock.Mock()
|
|
node.cluster_id = 'FAKE_CLUSTER'
|
|
node.id = 'NODE_ID'
|
|
mock_load.return_value = node
|
|
|
|
action = node_action.NodeAction('NODE_ID', 'NODE_FLY', self.ctx,
|
|
cause='RPC Request')
|
|
action.id = 'ACTION_ID'
|
|
mock_check = self.patchobject(action, 'policy_check',
|
|
side_effect=fake_check)
|
|
# check result
|
|
self.patchobject(action, '_execute',
|
|
return_value=(action.RES_OK, 'Ignored'))
|
|
mock_acquire.return_value = 'ACTION_ID'
|
|
mock_acquire_node.return_value = 'ACTION_ID'
|
|
|
|
res_code, res_msg = action.execute()
|
|
|
|
reason = 'Policy check: Policy checking failed'
|
|
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',
|
|
lock.NODE_SCOPE, False)
|
|
mock_release.assert_called_once_with('FAKE_CLUSTER', 'ACTION_ID',
|
|
lock.NODE_SCOPE)
|
|
check_calls = [
|
|
mock.call('FAKE_CLUSTER', 'BEFORE'),
|
|
mock.call('FAKE_CLUSTER', 'AFTER')
|
|
]
|
|
mock_check.assert_has_calls(check_calls)
|
|
mock_acquire_node.assert_called_once_with(self.ctx, 'NODE_ID',
|
|
'ACTION_ID', False)
|
|
mock_release_node.assert_called_once_with('NODE_ID', 'ACTION_ID')
|