# 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 oslo_config import cfg from oslo_messaging.rpc import dispatcher as rpc from oslo_utils import uuidutils import six from senlin.common import consts from senlin.common import exception as exc from senlin.common.i18n import _ from senlin.common import scaleutils as su from senlin.common import utils as common_utils from senlin.engine.actions import base as am from senlin.engine import dispatcher from senlin.engine import node as nm from senlin.engine import service from senlin.objects import base as obj_base from senlin.objects import cluster as co from senlin.objects import cluster_policy as cpo from senlin.objects import node as no from senlin.objects import profile as po from senlin.objects import receiver as ro from senlin.objects.requests import clusters as orco from senlin.tests.unit.common import base from senlin.tests.unit.common import utils class ClusterTest(base.SenlinTestCase): def setUp(self): super(ClusterTest, self).setUp() self.ctx = utils.dummy_context(project='cluster_test_project') self.eng = service.EngineService('host-a', 'topic-a') @mock.patch.object(co.Cluster, 'count_all') def test_check_cluster_quota(self, mock_count): mock_count.return_value = 10 cfg.CONF.set_override('max_clusters_per_project', 11, enforce_type=True) res = self.eng.check_cluster_quota(self.ctx) self.assertIsNone(res) mock_count.assert_called_once_with(self.ctx) @mock.patch.object(co.Cluster, 'count_all') def test_check_cluster_quota_failed(self, mock_count): mock_count.return_value = 11 cfg.CONF.set_override('max_clusters_per_project', 11, enforce_type=True) ex = self.assertRaises(exc.Forbidden, self.eng.check_cluster_quota, self.ctx) self.assertEqual("You are not authorized to complete this " "operation.", six.text_type(ex)) def _prepare_request(self, req): mock_cls = self.patchobject(obj_base.SenlinObject, 'obj_class_from_name') req.update({'senlin_object.name': 'RequestClass', 'senlin_object.version': '1.0'}) req_base = mock.Mock() mock_cls.return_value = req_base req_obj = mock.Mock() for k, v in req.items(): setattr(req_obj, k, v) req_base.obj_from_primitive.return_value = req_obj @mock.patch.object(co.Cluster, 'get_all') def test_cluster_list(self, mock_get): x_obj_1 = mock.Mock() x_obj_1.to_dict.return_value = {'k': 'v1'} x_obj_2 = mock.Mock() x_obj_2.to_dict.return_value = {'k': 'v2'} mock_get.return_value = [x_obj_1, x_obj_2] req = orco.ClusterListRequest(project_safe=True) result = self.eng.cluster_list(self.ctx, req.obj_to_primitive()) self.assertEqual([{'k': 'v1'}, {'k': 'v2'}], result) mock_get.assert_called_once_with(self.ctx, project_safe=True) @mock.patch.object(co.Cluster, 'get_all') def test_cluster_list_with_params(self, mock_get): mock_get.return_value = [] marker = uuidutils.generate_uuid() req = { 'limit': 10, 'marker': marker, 'name': ['test_cluster'], 'status': ['ACTIVE'], 'sort': 'name:asc', 'project_safe': True } self._prepare_request(req) result = self.eng.cluster_list(self.ctx, req) self.assertEqual([], result) mock_get.assert_called_once_with( self.ctx, limit=10, marker=marker, sort='name:asc', filters={'name': ['test_cluster'], 'status': ['ACTIVE']}, project_safe=True) @mock.patch.object(service.EngineService, 'check_cluster_quota') @mock.patch.object(su, 'check_size_params') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, "create") @mock.patch.object(po.Profile, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_create(self, notify, mock_profile, mock_cluster, mock_action, mock_check, mock_quota): x_profile = mock.Mock(id='PROFILE_ID') mock_profile.return_value = x_profile x_cluster = mock.Mock(id='12345678ABC') x_cluster.to_dict.return_value = {'foo': 'bar'} mock_cluster.return_value = x_cluster mock_action.return_value = 'ACTION_ID' mock_check.return_value = None mock_quota.return_value = None req = orco.ClusterCreateRequestBody(name='C1', profile_id='PROFILE', desired_capacity=3) # do it result = self.eng.cluster_create(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID', 'foo': 'bar'}, result) mock_profile.assert_called_once_with(self.ctx, 'PROFILE') mock_check.assert_called_once_with(None, 3, None, None, True) mock_cluster.assert_called_once_with( self.ctx, dict(name='C1', desired_capacity=3, profile_id='PROFILE_ID', min_size=0, max_size=-1, timeout=3600, metadata={}, dependents={}, data={}, next_index=1, status='INIT', config={}, status_reason='Initializing', user=self.ctx.user, project=self.ctx.project, domain=self.ctx.domain)) mock_action.assert_called_once_with( self.ctx, '12345678ABC', 'CLUSTER_CREATE', name='cluster_create_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, ) notify.assert_called_once_with() @mock.patch.object(service.EngineService, 'check_cluster_quota') @mock.patch.object(su, 'check_size_params') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, "create") @mock.patch.object(po.Profile, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_create_desired_null(self, notify, mock_profile, mock_cluster, mock_action, mock_check, mock_quota): x_profile = mock.Mock(id='PROFILE_ID') mock_profile.return_value = x_profile x_cluster = mock.Mock(id='12345678ABC') x_cluster.to_dict.return_value = {'foo': 'bar'} mock_cluster.return_value = x_cluster mock_action.return_value = 'ACTION_ID' mock_check.return_value = None mock_quota.return_value = None req = orco.ClusterCreateRequestBody(name='C1', profile_id='PROFILE', min_size=1, max_size=5, config={'k1': 'v1'}) # do it result = self.eng.cluster_create(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID', 'foo': 'bar'}, result) mock_profile.assert_called_once_with(self.ctx, 'PROFILE') mock_check.assert_called_once_with(None, 1, 1, 5, True) mock_cluster.assert_called_once_with( self.ctx, dict(name='C1', desired_capacity=1, profile_id='PROFILE_ID', min_size=1, max_size=5, timeout=3600, metadata={}, dependents={}, data={}, next_index=1, status='INIT', config={'k1': 'v1'}, status_reason='Initializing', user=self.ctx.user, project=self.ctx.project, domain=self.ctx.domain)) mock_action.assert_called_once_with( self.ctx, '12345678ABC', 'CLUSTER_CREATE', name='cluster_create_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, ) notify.assert_called_once_with() @mock.patch.object(service.EngineService, 'check_cluster_quota') def test_cluster_create_exceeding_quota(self, mock_quota): mock_quota.side_effect = exc.Forbidden() req = {'profile_id': 'PROFILE', 'name': 'CLUSTER'} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_create, self.ctx, req) self.assertEqual(exc.Forbidden, ex.exc_info[0]) self.assertEqual("You are not authorized to complete this " "operation.", six.text_type(ex.exc_info[1])) mock_quota.assert_called_once_with(self.ctx) @mock.patch.object(service.EngineService, 'check_cluster_quota') @mock.patch.object(co.Cluster, 'get_by_name') def test_cluster_create_duplicate_name(self, mock_get, mock_quota): cfg.CONF.set_override('name_unique', True, enforce_type=True) mock_quota.return_value = None mock_get.return_value = mock.Mock() req = {'profile_id': 'PROFILE', 'name': 'CLUSTER'} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_create, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual(_("a cluster named 'CLUSTER' already exists."), six.text_type(ex.exc_info[1])) mock_get.assert_called_once_with(self.ctx, 'CLUSTER') @mock.patch.object(service.EngineService, 'check_cluster_quota') @mock.patch.object(po.Profile, 'find') def test_cluster_create_profile_not_found(self, mock_find, mock_quota): mock_quota.return_value = None mock_find.side_effect = exc.ResourceNotFound(type='profile', id='Bogus') req = {'profile_id': 'Bogus', 'name': 'CLUSTER'} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_create, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("The specified profile 'Bogus' could not " "be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'Bogus') @mock.patch.object(service.EngineService, 'check_cluster_quota') @mock.patch.object(po.Profile, 'find') @mock.patch.object(su, 'check_size_params') def test_cluster_create_failed_checking(self, mock_check, mock_find, mock_quota): mock_quota.return_value = None mock_find.return_value = mock.Mock() mock_check.return_value = 'INVALID' req = {'profile_id': 'PROFILE', 'name': 'CLUSTER'} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_create, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("INVALID.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'PROFILE') @mock.patch.object(co.Cluster, 'find') def test_cluster_get(self, mock_find): x_cluster = mock.Mock() x_cluster.to_dict.return_value = {'foo': 'bar'} mock_find.return_value = x_cluster req = orco.ClusterGetRequest(identity='C1') result = self.eng.cluster_get(self.ctx, req.obj_to_primitive()) self.assertEqual({'foo': 'bar'}, result) mock_find.assert_called_once_with(self.ctx, 'C1') @mock.patch.object(co.Cluster, 'find') def test_cluster_get_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = {'identity': 'CLUSTER'} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_get, self.ctx, req) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) @mock.patch.object(am.Action, 'create') @mock.patch.object(po.Profile, 'find') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_update(self, notify, mock_find, mock_profile, mock_action): x_cluster = mock.Mock(id='12345678AB', status='ACTIVE', profile_id='OLD_PROFILE', metadata={'A': 'B'}) x_cluster.to_dict.return_value = {'foo': 'bar'} mock_find.return_value = x_cluster old_profile = mock.Mock(type='FAKE_TYPE', id='ID_OLD') new_profile = mock.Mock(type='FAKE_TYPE', id='ID_NEW') mock_profile.side_effect = [old_profile, new_profile] mock_action.return_value = 'ACTION_ID' req = orco.ClusterUpdateRequest(identity='FAKE_ID', name='new_name', profile_id='NEW_PROFILE', metadata={'B': 'A'}, timeout=120, config={'k1': 'v1'}) # do it result = self.eng.cluster_update(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID', 'foo': 'bar'}, result) mock_find.assert_called_once_with(self.ctx, 'FAKE_ID') mock_profile.assert_has_calls([ mock.call(self.ctx, 'OLD_PROFILE'), mock.call(self.ctx, 'NEW_PROFILE'), ]) mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ 'new_profile_id': 'ID_NEW', 'metadata': { 'B': 'A', }, 'timeout': 120, 'name': 'new_name', 'config': { 'k1': 'v1', }, } ) @mock.patch.object(co.Cluster, 'find') def test_cluster_update_cluster_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = {'identity': 'Bogus', 'name': 'new-name'} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_update, self.ctx, req) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) @mock.patch.object(co.Cluster, 'find') def test_cluster_update_cluster_bad_status(self, mock_find): x_cluster = mock.Mock(status='ERROR') mock_find.return_value = x_cluster req = {'identity': 'CLUSTER', 'name': 'new-name'} self._prepare_request(req) self.assertEqual(consts.CS_ERROR, x_cluster.status) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_update, self.ctx, req) self.assertEqual(exc.FeatureNotSupported, ex.exc_info[0]) self.assertEqual('Updating a cluster in error state is not supported.', six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') @mock.patch.object(po.Profile, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_update_profile_not_found(self, mock_find, mock_profile): mock_find.return_value = mock.Mock(status='ACTIVE', profile_id='OLD_ID') mock_profile.side_effect = [ mock.Mock(type='FAKE_TYPE', id='OLD_ID'), exc.ResourceNotFound(type='profile', id='Bogus') ] req = orco.ClusterUpdateRequest(identity='CLUSTER', profile_id='Bogus') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_update, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("The specified profile 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_profile.assert_has_calls([ mock.call(self.ctx, 'OLD_ID'), mock.call(self.ctx, 'Bogus'), ]) @mock.patch.object(po.Profile, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_update_diff_profile_type(self, mock_find, mock_profile): x_obj = mock.Mock(status='ACTIVE', profile_id='OLD_ID') mock_find.return_value = x_obj mock_profile.side_effect = [ mock.Mock(type='FAKE_TYPE', id='OLD_ID'), mock.Mock(type='DIFF_TYPE', id='NEW_ID'), ] req = orco.ClusterUpdateRequest(identity='CLUSTER', profile_id='NEW_PROFILE') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_update, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_profile.assert_has_calls([ mock.call(self.ctx, 'OLD_ID'), mock.call(self.ctx, 'NEW_PROFILE'), ]) @mock.patch.object(am.Action, 'create') @mock.patch.object(po.Profile, 'find') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_update_same_profile(self, notify, mock_find, mock_profile, mock_action): x_cluster = mock.Mock(id='12345678AB', status='ACTIVE', profile_id='OLD_PROFILE') x_cluster.to_dict.return_value = {'foo': 'bar'} mock_find.return_value = x_cluster old_profile = mock.Mock(type='FAKE_TYPE', id='ID_OLD') new_profile = mock.Mock(type='FAKE_TYPE', id='ID_OLD') mock_profile.side_effect = [old_profile, new_profile] mock_action.return_value = 'ACTION_ID' req = orco.ClusterUpdateRequest(identity='FAKE_ID', name='NEW_NAME', profile_id='NEW_PROFILE') # do it result = self.eng.cluster_update(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID', 'foo': 'bar'}, result) mock_find.assert_called_once_with(self.ctx, 'FAKE_ID') mock_profile.assert_has_calls([ mock.call(self.ctx, 'OLD_PROFILE'), mock.call(self.ctx, 'NEW_PROFILE'), ]) mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ # Note profile_id is not shown in the inputs 'name': 'NEW_NAME', }, ) notify.assert_called_once_with() @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_update_same_metadata(self, notify, mock_find, mock_action): x_cluster = mock.Mock(id='12345678AB', status='ACTIVE', metadata={'K': 'V'}) x_cluster.to_dict.return_value = {'foo': 'bar'} mock_find.return_value = x_cluster mock_action.return_value = 'ACTION_ID' req = orco.ClusterUpdateRequest(identity='FAKE_ID', name='NEW_NAME', metadata={'K': 'V'}) # do it result = self.eng.cluster_update(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID', 'foo': 'bar'}, result) mock_find.assert_called_once_with(self.ctx, 'FAKE_ID') mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ # Note metadata is not included in the inputs 'name': 'NEW_NAME', }, ) notify.assert_called_once_with() @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_update_same_timeout(self, notify, mock_find, mock_action): x_cluster = mock.Mock(id='12345678AB', status='ACTIVE', timeout=10) x_cluster.to_dict.return_value = {'foo': 'bar'} x_cluster.timeout = 10 mock_find.return_value = x_cluster mock_action.return_value = 'ACTION_ID' req = orco.ClusterUpdateRequest(identity='FAKE_ID', name='NEW_NAME', timeout=10) # do it result = self.eng.cluster_update(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID', 'foo': 'bar'}, result) mock_find.assert_called_once_with(self.ctx, 'FAKE_ID') mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ # Note timeout is not included in the inputs 'name': 'NEW_NAME', }, ) notify.assert_called_once_with() @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_update_same_name(self, notify, mock_find, mock_action): x_cluster = mock.Mock(id='12345678AB', status='ACTIVE', name='OLD_NAME', timeout=10) x_cluster.name = 'OLD_NAME' x_cluster.to_dict.return_value = {'foo': 'bar'} mock_find.return_value = x_cluster mock_action.return_value = 'ACTION_ID' req = orco.ClusterUpdateRequest(identity='FAKE_ID', name='OLD_NAME', timeout=100) # do it result = self.eng.cluster_update(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID', 'foo': 'bar'}, result) mock_find.assert_called_once_with(self.ctx, 'FAKE_ID') mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_UPDATE', name='cluster_update_12345678', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ # Note name is not included in the inputs 'timeout': 100, }, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_update_all_property_same(self, mock_find): x_cluster = mock.Mock(id='12345678AB', status='ACTIVE', name='OLD_NAME', timeout=10) x_cluster.name = 'OLD_NAME' x_cluster.timeout = 10 mock_find.return_value = x_cluster # Notice that name and timeout are all not changed. req = orco.ClusterUpdateRequest(identity='CLUSTER', name='OLD_NAME', timeout=10) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_update, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual('', six.text_type(ex)) @mock.patch.object(co.Cluster, 'find') def test_cluster_update_no_property_updated(self, mock_find): x_cluster = mock.Mock(status='ACTIVE', profile_id='OLD_ID') mock_find.return_value = x_cluster req = orco.ClusterUpdateRequest(identity='CLUSTER') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_update, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual('', six.text_type(ex)) @mock.patch.object(co.Cluster, 'find') def test_cluster_add_nodes_cluster_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = {'identity': 'Bogus', 'nodes': ['n1', 'n2']} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_add_nodes, self.ctx, req) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'Bogus') @mock.patch.object(su, 'check_size_params') @mock.patch.object(am.Action, 'create') @mock.patch.object(po.Profile, 'get') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_add_nodes(self, notify, mock_find, mock_node, mock_profile, mock_action, mock_check): x_cluster = mock.Mock(id='12345678AB', profile_id='FAKE_ID', desired_capacity=4) mock_find.return_value = x_cluster mock_profile.return_value = mock.Mock(type='FAKE_TYPE') x_node_1 = mock.Mock(id='NODE1', cluster_id='', status='ACTIVE', profile_id='FAKE_ID_1') x_node_2 = mock.Mock(id='NODE2', cluster_id='', status='ACTIVE', profile_id='FAKE_ID_1') mock_node.side_effect = [x_node_1, x_node_2] mock_action.return_value = 'ACTION_ID' mock_check.return_value = None req = orco.ClusterAddNodesRequest(identity='C1', nodes=['NODE_A', 'NODE_B']) result = self.eng.cluster_add_nodes(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'C1') mock_node.assert_has_calls([ mock.call(self.ctx, 'NODE_A'), mock.call(self.ctx, 'NODE_B'), ]) mock_check.assert_called_once_with(x_cluster, 6, strict=True) mock_action.assert_called_once_with( self.ctx, '12345678AB', consts.CLUSTER_ADD_NODES, name='cluster_add_nodes_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'nodes': ['NODE1', 'NODE2']}, ) self.assertEqual(3, mock_profile.call_count) notify.assert_called_once_with() @mock.patch.object(po.Profile, 'get') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_add_nodes_nodes_not_found(self, mock_find, mock_node, mock_profile): mock_find.return_value = mock.Mock(id='1234', profile_id='FAKE_ID') mock_profile.return_value = mock.Mock(type='FAKE_TYPE') mock_node.side_effect = exc.ResourceNotFound(type='node', id='NODE1') req = {'identity': 'CLUSTER', 'nodes': ['NODE1']} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_add_nodes, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Nodes not found: ['NODE1'].", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_profile.assert_called_once_with(self.ctx, 'FAKE_ID', project_safe=True) mock_node.assert_called_once_with(self.ctx, 'NODE1') @mock.patch.object(po.Profile, 'get') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_add_nodes_bad_status(self, mock_find, mock_node, mock_profile): mock_find.return_value = mock.Mock(id='1234', profile_id='FAKE_ID') mock_profile.return_value = mock.Mock(type='FAKE_TYPE') mock_node.return_value = mock.Mock( id='NODE2', cluster_id='', status='ERROR') req = {'identity': 'CLUSTER', 'nodes': ['NODE2']} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_add_nodes, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Nodes are not ACTIVE: ['NODE2'].", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') self.assertEqual(2, mock_profile.call_count) mock_node.assert_called_once_with(self.ctx, 'NODE2') @mock.patch.object(po.Profile, 'get') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_add_nodes_node_already_owned(self, mock_find, mock_node, mock_profile): mock_find.return_value = mock.Mock(id='1234', profile_id='FAKE_ID') mock_profile.return_value = mock.Mock(type='FAKE_TYPE') mock_node.return_value = mock.Mock(id='NODE3', status='ACTIVE', cluster_id='OTHER') req = {'identity': 'CLUSTER', 'nodes': ['NODE3']} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_add_nodes, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Nodes ['NODE3'] already owned by some cluster.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') self.assertEqual(2, mock_profile.call_count) mock_node.assert_called_once_with(self.ctx, 'NODE3') @mock.patch.object(po.Profile, 'get') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_add_nodes_node_profile_type_not_match( self, mock_find, mock_node, mock_profile): mock_find.return_value = mock.Mock(id='1234', profile_id='FAKE_ID') mock_profile.side_effect = [ mock.Mock(type='FAKE_TYPE_1'), mock.Mock(type='FAKE_TYPE_2'), ] mock_node.return_value = mock.Mock(id='NODE4', status='ACTIVE', cluster_id='', profile_id='DIFF') req = {'identity': 'CLUSTER', 'nodes': ['NODE4']} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_add_nodes, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Profile type of nodes ['NODE4'] does not " "match that of the cluster.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_profile.assert_has_calls([ mock.call(self.ctx, 'FAKE_ID', project_safe=True), mock.call(self.ctx, 'DIFF', project_safe=True), ]) mock_node.assert_called_once_with(self.ctx, 'NODE4') @mock.patch.object(po.Profile, 'get') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_add_nodes_mult_err(self, mock_find, mock_node, mock_profile): mock_find.return_value = mock.Mock(id='1234', profile_id='FAKE_ID') mock_profile.return_value = mock.Mock(type='FAKE_TYPE') mock_node.return_value = mock.Mock(id='NODE2', status='ERROR') req = {'identity': 'CLUSTER', 'nodes': ['NODE2']} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_add_nodes, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) msg1 = _("Nodes ['NODE2'] already owned by some cluster.") msg2 = _("Nodes are not ACTIVE: ['NODE2'].") self.assertIn(msg1, six.text_type(ex.exc_info[1])) self.assertIn(msg2, six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') self.assertEqual(2, mock_profile.call_count) mock_node.assert_called_once_with(self.ctx, 'NODE2') @mock.patch.object(po.Profile, 'get') @mock.patch.object(su, 'check_size_params') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_add_nodes_failed_checking(self, mock_find, mock_node, mock_check, mock_profile): x_cluster = mock.Mock(id='12345678AB', profile_id='FAKE_PROFILE', desired_capacity=2) mock_find.return_value = x_cluster mock_profile.return_value = mock.Mock(type='FAKE_TYPE') x_node_1 = mock.Mock(id='NODE1', cluster_id='', status='ACTIVE', profile_id='FAKE_PROFILE_1') x_node_2 = mock.Mock(id='NODE2', cluster_id='', status='ACTIVE', profile_id='FAKE_PROFILE_2') mock_node.side_effect = [x_node_1, x_node_2] mock_check.return_value = 'Failed size checking.' req = {'identity': 'C1', 'nodes': ['NODE_A', 'NODE_B']} self._prepare_request(req) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_add_nodes, self.ctx, req) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Failed size checking.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'C1') mock_profile.assert_has_calls([ mock.call(self.ctx, 'FAKE_PROFILE', project_safe=True), mock.call(self.ctx, 'FAKE_PROFILE_1', project_safe=True), mock.call(self.ctx, 'FAKE_PROFILE_2', project_safe=True), ]) mock_node.assert_has_calls([ mock.call(self.ctx, 'NODE_A'), mock.call(self.ctx, 'NODE_B'), ]) mock_check.assert_called_once_with(x_cluster, 4, strict=True) @mock.patch.object(su, 'check_size_params') @mock.patch.object(am.Action, 'create') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_del_nodes(self, notify, mock_find, mock_node, mock_action, mock_check): x_cluster = mock.Mock(id='1234', desired_capacity=2) mock_find.return_value = x_cluster mock_node.return_value = mock.Mock(id='NODE2', cluster_id='1234', dependents={}) mock_check.return_value = None mock_action.return_value = 'ACTION_ID' req = orco.ClusterDelNodesRequest(identity='CLUSTER', nodes=['NODE1']) result = self.eng.cluster_del_nodes(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_node.assert_called_once_with(self.ctx, 'NODE1') mock_check.asset_called_once_with(x_cluster, 1, strict=True) mock_action.assert_called_once_with( self.ctx, '1234', consts.CLUSTER_DEL_NODES, name='cluster_del_nodes_1234', status=am.Action.READY, cause=consts.CAUSE_RPC, inputs={ 'count': 1, 'candidates': ['NODE2'], }, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_del_nodes_cluster_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = orco.ClusterDelNodesRequest(identity='Bogus', nodes=['NODE1']) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_del_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'Bogus') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_del_nodes_node_not_found(self, mock_find, mock_node): mock_find.return_value = mock.Mock() mock_node.side_effect = exc.ResourceNotFound(type='node', id='NODE1') req = orco.ClusterDelNodesRequest(identity='CLUSTER', nodes=['NODE1']) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_del_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertIn("Nodes not found", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_node.assert_called_once_with(self.ctx, 'NODE1') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_del_nodes_have_containers(self, mock_cluster, mock_node): mock_cluster.return_value = mock.Mock(id='CLUSTER1') dependents = {'nodes': ['container1']} node = mock.Mock(id='NODE1', dependents=dependents, cluster_id='CLUSTER1') mock_node.return_value = node req = orco.ClusterDelNodesRequest(identity='CLUSTER', nodes=['NODE1']) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_del_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceInUse, ex.exc_info[0]) message = _("nodes ['NODE1'] are depended by other nodes, so can't be " "deleted or become orphan nodes") self.assertIn(message, six.text_type(ex.exc_info[1])) @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_del_nodes_node_in_other_cluster(self, mock_find, mock_node): mock_find.return_value = mock.Mock(id='1234') mock_node.return_value = mock.Mock(id='NODE2', cluster_id='5678') req = orco.ClusterDelNodesRequest(identity='CLUSTER', nodes=['NODE2']) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_del_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Nodes not members of specified cluster: ['NODE2'].", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_node.assert_called_once_with(self.ctx, 'NODE2') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_del_nodes_mult_errors(self, mock_find, mock_node): mock_find.return_value = mock.Mock(id='1234') mock_node.side_effect = [mock.Mock(id='NODE1', cluster_id='5678'), exc.ResourceNotFound(type='node', id='NODE2')] req = orco.ClusterDelNodesRequest(identity='CLUSTER', nodes=['NODE1', 'NODE2']) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_del_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) msg1 = _("Nodes not found:") msg2 = _("Nodes not members of specified cluster: ['NODE1'].") self.assertIn(msg1, six.text_type(ex.exc_info[1])) self.assertIn(msg2, six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') self.assertEqual(2, mock_node.call_count) @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_del_nodes_orphan_nodes(self, mock_find, mock_node): mock_find.return_value = mock.Mock(id='1234') mock_node.return_value = mock.Mock(id='NODE3', cluster_id='') req = orco.ClusterDelNodesRequest(identity='CLUSTER', nodes=['NODE3']) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_del_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Nodes not members of specified cluster: ['NODE3'].", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_node.assert_called_once_with(self.ctx, 'NODE3') @mock.patch.object(su, 'check_size_params') @mock.patch.object(no.Node, 'find') @mock.patch.object(co.Cluster, 'find') def test_cluster_del_nodes_failed_checking(self, mock_find, mock_node, mock_check): x_cluster = mock.Mock(id='1234', desired_capacity=2) mock_find.return_value = x_cluster mock_node.return_value = mock.Mock(id='NODE2', cluster_id='1234', dependents={}) mock_check.return_value = 'Failed size checking.' req = orco.ClusterDelNodesRequest(identity='CLUSTER', nodes=['NODE3']) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_del_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Failed size checking.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_node.assert_called_once_with(self.ctx, 'NODE3') mock_check.assert_called_once_with(x_cluster, 1, strict=True) @mock.patch.object(no.Node, 'count_by_cluster') @mock.patch.object(su, 'calculate_desired') @mock.patch.object(su, 'check_size_params') @mock.patch.object(dispatcher, 'start_action') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') def test_cluster_resize_exact_capacity(self, mock_find, mock_action, notify, mock_check, mock_calc, mock_count): x_cluster = mock.Mock(id='12345678ABCDEFGH') mock_find.return_value = x_cluster mock_count.return_value = 3 mock_calc.return_value = 5 mock_check.return_value = None mock_action.return_value = 'ACTION_ID' req = orco.ClusterResizeRequest( identity='CLUSTER', adjustment_type=consts.EXACT_CAPACITY, number=5 ) res = self.eng.cluster_resize(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, res) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_calc.assert_called_once_with(3, consts.EXACT_CAPACITY, 5, None) mock_check.assert_called_once_with(x_cluster, 5, None, None, True) mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_RESIZE, name='cluster_resize_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ consts.ADJUSTMENT_TYPE: consts.EXACT_CAPACITY, consts.ADJUSTMENT_NUMBER: 5, consts.ADJUSTMENT_MIN_SIZE: None, consts.ADJUSTMENT_MAX_SIZE: None, consts.ADJUSTMENT_MIN_STEP: None, consts.ADJUSTMENT_STRICT: True }, ) notify.assert_called_once_with() @mock.patch.object(no.Node, 'count_by_cluster') @mock.patch.object(su, 'calculate_desired') @mock.patch.object(su, 'check_size_params') @mock.patch.object(dispatcher, 'start_action') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') def test_cluster_resize_change_in_capacity(self, mock_find, mock_action, notify, mock_check, mock_calc, mock_count): x_cluster = mock.Mock(id='12345678ABCDEFGH') mock_find.return_value = x_cluster mock_count.return_value = 2 mock_calc.return_value = 7 mock_check.return_value = None mock_action.return_value = 'ACTION_ID' req = orco.ClusterResizeRequest( identity='CLUSTER', adjustment_type=consts.CHANGE_IN_CAPACITY, number=5 ) res = self.eng.cluster_resize(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, res) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_calc.assert_called_once_with(2, consts.CHANGE_IN_CAPACITY, 5, None) mock_check.assert_called_once_with(x_cluster, 7, None, None, True) mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_RESIZE, name='cluster_resize_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ consts.ADJUSTMENT_TYPE: consts.CHANGE_IN_CAPACITY, consts.ADJUSTMENT_NUMBER: 5, consts.ADJUSTMENT_MIN_SIZE: None, consts.ADJUSTMENT_MAX_SIZE: None, consts.ADJUSTMENT_MIN_STEP: None, consts.ADJUSTMENT_STRICT: True }, ) notify.assert_called_once_with() @mock.patch.object(no.Node, 'count_by_cluster') @mock.patch.object(su, 'calculate_desired') @mock.patch.object(su, 'check_size_params') @mock.patch.object(dispatcher, 'start_action') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') def test_cluster_resize_change_in_percentage(self, mock_find, mock_action, notify, mock_check, mock_calc, mock_count): x_cluster = mock.Mock(id='12345678ABCDEFGH') mock_find.return_value = x_cluster mock_count.return_value = 10 mock_calc.return_value = 8 mock_check.return_value = None mock_action.return_value = 'ACTION_ID' req = orco.ClusterResizeRequest( identity='CLUSTER', adjustment_type=consts.CHANGE_IN_PERCENTAGE, number=15.81 ) res = self.eng.cluster_resize(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, res) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_calc.assert_called_once_with(10, consts.CHANGE_IN_PERCENTAGE, 15.81, None) mock_check.assert_called_once_with(x_cluster, 8, None, None, True) mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_RESIZE, name='cluster_resize_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={ consts.ADJUSTMENT_TYPE: consts.CHANGE_IN_PERCENTAGE, consts.ADJUSTMENT_NUMBER: 15.81, consts.ADJUSTMENT_MIN_SIZE: None, consts.ADJUSTMENT_MAX_SIZE: None, consts.ADJUSTMENT_MIN_STEP: None, consts.ADJUSTMENT_STRICT: True }, ) notify.assert_called_once_with() def test_cluster_resize_type_missing_number(self): req = orco.ClusterResizeRequest( identity='CLUSTER', adjustment_type=consts.EXACT_CAPACITY ) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_resize, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Missing number value for size adjustment.", six.text_type(ex.exc_info[1])) def test_cluster_resize_number_without_type(self): req = orco.ClusterResizeRequest( identity='CLUSTER', number=10 ) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_resize, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Missing adjustment_type " "value for size adjustment.", six.text_type(ex.exc_info[1])) def test_cluster_resize_bad_number_for_exact_capacity(self): req = orco.ClusterResizeRequest( identity='CLUSTER', adjustment_type=consts.EXACT_CAPACITY, number=-5 ) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_resize, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("The 'number' must be positive integer for " "adjustment type 'EXACT_CAPACITY'.", six.text_type(ex.exc_info[1])) @mock.patch.object(co.Cluster, 'find') def test_cluster_resize_cluster_not_found(self, mock_find): req = orco.ClusterResizeRequest( identity='CLUSTER', adjustment_type=consts.EXACT_CAPACITY, number=10 ) mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='CLUSTER') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_resize, self.ctx, req.obj_to_primitive()) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'CLUSTER' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') @mock.patch.object(su, 'check_size_params') @mock.patch.object(no.Node, 'count_by_cluster') @mock.patch.object(co.Cluster, 'find') def test_cluster_resize_failing_size_check(self, mock_find, mock_count, mock_check): x_cluster = mock.Mock(id='CID') mock_find.return_value = x_cluster mock_count.return_value = 5 mock_check.return_value = 'size check.' req = orco.ClusterResizeRequest( identity='CLUSTER', adjustment_type=consts.EXACT_CAPACITY, number=5 ) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_resize, self.ctx, req.obj_to_primitive()) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_count.assert_called_once_with(self.ctx, 'CID') mock_check.assert_called_once_with(x_cluster, 5, None, None, True) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("size check.", six.text_type(ex.exc_info[1])) @mock.patch.object(dispatcher, 'start_action') @mock.patch.object(am.Action, 'create') @mock.patch.object(su, 'check_size_params') @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_out(self, mock_find, mock_check, mock_action, notify): x_cluster = mock.Mock(id='12345678ABCDEFGH', desired_capacity=4) mock_find.return_value = x_cluster mock_check.return_value = None mock_action.return_value = 'ACTION_ID' req = orco.ClusterScaleOutRequest(identity='CLUSTER', count=1) result = self.eng.cluster_scale_out(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_check.assert_called_once_with(x_cluster, 5) mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_SCALE_OUT, name='cluster_scale_out_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'count': 1}, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_out_cluster_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = orco.ClusterScaleOutRequest(identity='Bogus', count=1) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_scale_out, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'Bogus') @mock.patch.object(dispatcher, 'start_action') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_out_count_is_none(self, mock_find, mock_action, notify): mock_find.return_value = mock.Mock(id='12345678ABCDEFGH', desired_capacity=4) mock_action.return_value = 'ACTION_ID' req = orco.ClusterScaleOutRequest(identity='CLUSTER') result = self.eng.cluster_scale_out(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_action.assert_called_once_with( self.ctx, '12345678ABCDEFGH', consts.CLUSTER_SCALE_OUT, name='cluster_scale_out_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_out_count_zero(self, mock_find): mock_find.return_value = mock.Mock(desired_capacity=4) req = orco.ClusterScaleOutRequest(identity='CLUSTER', count=0) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_scale_out, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Count for scale-out request cannot be 0.", six.text_type(ex.exc_info[1])) @mock.patch.object(su, 'check_size_params') @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_out_failed_size_check(self, mock_find, mock_check): x_cluster = mock.Mock(desired_capacity=4) mock_find.return_value = x_cluster mock_check.return_value = 'size limit' req = orco.ClusterScaleOutRequest(identity='CLUSTER', count=2) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_scale_out, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("size limit.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_check.assert_called_once_with(x_cluster, 6) @mock.patch.object(dispatcher, 'start_action') @mock.patch.object(am.Action, 'create') @mock.patch.object(su, 'check_size_params') @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_in(self, mock_find, mock_check, mock_action, notify): x_cluster = mock.Mock(id='12345678ABCD', desired_capacity=4) mock_find.return_value = x_cluster mock_check.return_value = None mock_action.return_value = 'ACTION_ID' req = orco.ClusterScaleInRequest(identity='CLUSTER', count=2) result = self.eng.cluster_scale_in(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_check.assert_called_once_with(x_cluster, 2) mock_action.assert_called_once_with( self.ctx, '12345678ABCD', consts.CLUSTER_SCALE_IN, name='cluster_scale_in_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'count': 2}, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_in_cluster_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = orco.ClusterScaleInRequest(identity='Bogus', count=2) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_scale_in, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'Bogus') @mock.patch.object(dispatcher, 'start_action') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_in_count_is_none(self, mock_find, mock_action, notify): mock_find.return_value = mock.Mock(id='FOO', desired_capacity=4) mock_action.return_value = 'ACTION_ID' req = orco.ClusterScaleInRequest(identity='CLUSTER') result = self.eng.cluster_scale_in(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_action.assert_called_once_with( self.ctx, 'FOO', consts.CLUSTER_SCALE_IN, name='cluster_scale_in_FOO', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_in_count_zero(self, mock_find): mock_find.return_value = mock.Mock(desired_capacity=4) req = orco.ClusterScaleInRequest(identity='CLUSTER', count=0) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_scale_in, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Count for scale-in request cannot be 0.", six.text_type(ex.exc_info[1])) @mock.patch.object(su, 'check_size_params') @mock.patch.object(co.Cluster, 'find') def test_cluster_scale_in_failed_size_check(self, mock_find, mock_check): x_cluster = mock.Mock(desired_capacity=4) mock_find.return_value = x_cluster mock_check.return_value = 'size limit' req = orco.ClusterScaleInRequest(identity='FAKE_CLUSTER', count=2) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_scale_in, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("size limit.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'FAKE_CLUSTER') mock_check.assert_called_once_with(x_cluster, 2) @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_check(self, notify, mock_find, mock_action): x_cluster = mock.Mock(id='CID', user='USER', project='PROJECT') mock_find.return_value = x_cluster mock_action.return_value = 'ACTION_ID' req = orco.ClusterCheckRequest(identity='C1', params={'foo': 'bar'}) res = self.eng.cluster_check(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, res) mock_find.assert_called_once_with(self.ctx, 'C1') mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_CHECK, name='cluster_check_CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'foo': 'bar'}, ) notify.assert_called_once_with() @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_check_user_is_none(self, notify, mock_find, mock_action): x_cluster = mock.Mock(id='CID', project='PROJECT') mock_find.return_value = x_cluster mock_action.return_value = 'ACTION_ID' req = orco.ClusterCheckRequest(identity='C1') result = self.eng.cluster_check(self.ctx, req.obj_to_primitive()) self.assertIsNotNone(x_cluster.user) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'C1') mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_CHECK, name='cluster_check_CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_check_cluster_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = orco.ClusterCheckRequest(identity='C1', params={'foo': 'bar'}) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_check, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'C1') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_recover(self, notify, mock_find, mock_action): x_cluster = mock.Mock(id='CID') mock_find.return_value = x_cluster mock_action.return_value = 'ACTION_ID' req = orco.ClusterRecoverRequest(identity='C1', params={'operation': 'RECREATE'}) result = self.eng.cluster_recover(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'C1') mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_RECOVER, name='cluster_recover_CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'operation': 'RECREATE'}, ) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_recover_cluster_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = orco.ClusterRecoverRequest(identity='Bogus') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_recover, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'Bogus') @mock.patch.object(co.Cluster, 'find') def test_cluster_recover_invalid(self, mock_find): x_cluster = mock.Mock(id='CID') mock_find.return_value = x_cluster req = orco.ClusterRecoverRequest(identity='Bogus', params={'bad': 'fake'}) ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_recover, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("Action parameter ['bad'] is not recognizable.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'Bogus') @mock.patch.object(am.Action, 'create') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_recover_user_is_none(self, notify, mock_find, mock_action): x_cluster = mock.Mock(id='CID', project='PROJECT') mock_find.return_value = x_cluster mock_action.return_value = 'ACTION_ID' req = orco.ClusterRecoverRequest(identity='C1') result = self.eng.cluster_recover(self.ctx, req.obj_to_primitive()) self.assertIsNotNone(x_cluster.user) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'C1') mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_RECOVER, name='cluster_recover_CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={}, ) notify.assert_called_once_with() @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes(self, mock_profile, mock_node): cluster = mock.Mock(id='CID', profile_id='FAKE_ID') mock_profile.return_value = mock.Mock(type='FAKE_TYPE') mock_node.side_effect = [ mock.Mock(id='OLD_ID', cluster_id='CID'), mock.Mock(id='NEW_ID', cluster_id='', status=consts.NS_ACTIVE, profile_id='FAKE_ID_1') ] # do it res = self.eng._validate_replace_nodes(self.ctx, cluster, {'OLD_NODE': 'NEW_NODE'}) self.assertEqual({'OLD_ID': 'NEW_ID'}, res) mock_node.assert_has_calls([ mock.call(self.ctx, 'OLD_NODE'), mock.call(self.ctx, 'NEW_NODE'), ]) mock_profile.assert_has_calls([ mock.call(self.ctx, 'FAKE_ID', project_safe=True), mock.call(self.ctx, 'FAKE_ID_1', project_safe=True) ]) @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes_old_missing(self, mock_profile, mock_node): c = mock.Mock(id='CID', profile_id='FAKE_ID') mock_node.side_effect = exc.ResourceNotFound(type='node', id='OLD') # do it ex = self.assertRaises(exc.BadRequest, self.eng._validate_replace_nodes, self.ctx, c, {'OLD': 'NEW'}) self.assertIn("Original nodes not found: ['OLD']", six.text_type(ex)) mock_node.assert_called_once_with(self.ctx, 'OLD') @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes_new_missing(self, mock_profile, mock_node): c = mock.Mock(id='CID', profile_id='FAKE_ID') mock_node.side_effect = [ mock.Mock(), exc.ResourceNotFound(type='node', id='NEW') ] # do it ex = self.assertRaises(exc.BadRequest, self.eng._validate_replace_nodes, self.ctx, c, {'OLD': 'NEW'}) self.assertIn("Replacement nodes not found: ['NEW']", six.text_type(ex)) mock_node.assert_has_calls([ mock.call(self.ctx, 'OLD'), mock.call(self.ctx, 'NEW') ]) @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes_old_not_member(self, mock_profile, mock_node): c = mock.Mock(id='CID', profile_id='FAKE_ID') mock_node.side_effect = [ mock.Mock(cluster_id='OTHER'), mock.Mock(cluster_id=''), ] # do it ex = self.assertRaises(exc.BadRequest, self.eng._validate_replace_nodes, self.ctx, c, {'OLD': 'NEW'}) self.assertIn("The specified nodes ['OLD'] to be replaced are not " "members of the cluster CID.", six.text_type(ex)) mock_node.assert_has_calls([ mock.call(self.ctx, 'OLD'), mock.call(self.ctx, 'NEW') ]) @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes_new_not_orphan(self, mock_profile, mock_node): c = mock.Mock(id='CID', profile_id='FAKE_ID') mock_node.side_effect = [ mock.Mock(cluster_id='CID'), mock.Mock(cluster_id='OTHER'), ] # do it ex = self.assertRaises(exc.BadRequest, self.eng._validate_replace_nodes, self.ctx, c, {'OLD': 'NEW'}) self.assertIn("Nodes ['NEW'] already member of a cluster.", six.text_type(ex)) mock_node.assert_has_calls([ mock.call(self.ctx, 'OLD'), mock.call(self.ctx, 'NEW') ]) @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes_new_bad_status(self, mock_profile, mock_node): c = mock.Mock(id='CID', profile_id='FAKE_ID') mock_node.side_effect = [ mock.Mock(cluster_id='CID'), mock.Mock(cluster_id='', status=consts.NS_ERROR), ] # do it ex = self.assertRaises(exc.BadRequest, self.eng._validate_replace_nodes, self.ctx, c, {'OLD': 'NEW'}) self.assertIn("Nodes are not ACTIVE: ['NEW'].", six.text_type(ex)) mock_node.assert_has_calls([ mock.call(self.ctx, 'OLD'), mock.call(self.ctx, 'NEW') ]) @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes_mult_err(self, mock_profile, mock_node): c = mock.Mock(id='CID', profile_id='FAKE_ID') mock_node.side_effect = [ mock.Mock(id='OLD1', cluster_id='CID'), mock.Mock(id='NEW1', cluster_id='OTHER', status=consts.NS_ERROR), ] # do it ex = self.assertRaises(exc.BadRequest, self.eng._validate_replace_nodes, self.ctx, c, {'OLD1': 'NEW1'}) msg1 = _("Nodes ['NEW1'] already member of a cluster.") msg2 = _("Nodes are not ACTIVE: ['NEW1'].") self.assertIn(msg1, six.text_type(ex)) self.assertIn(msg2, six.text_type(ex)) mock_node.assert_has_calls([ mock.call(self.ctx, 'OLD1'), mock.call(self.ctx, 'NEW1'), ]) @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'get') def test__validate_replace_nodes_new_profile_type_mismatch( self, mock_profile, mock_node): c = mock.Mock(id='CID', profile_id='FAKE_CLUSTER_PROFILE') mock_profile.side_effect = [ mock.Mock(type='FAKE_TYPE'), # for cluster mock.Mock(type='FAKE_TYPE_1'), # for node ] mock_node.side_effect = [ mock.Mock(cluster_id='CID'), mock.Mock(cluster_id='', status=consts.NS_ACTIVE, profile_id='FAKE_NODE_PROFILE'), ] # do it ex = self.assertRaises(exc.BadRequest, self.eng._validate_replace_nodes, self.ctx, c, {'OLD': 'NEW'}) self.assertIn("Profile type of nodes ['NEW'] do not match that of " "the cluster.", six.text_type(ex)) mock_node.assert_has_calls([ mock.call(self.ctx, 'OLD'), mock.call(self.ctx, 'NEW') ]) mock_profile.assert_has_calls([ mock.call(self.ctx, 'FAKE_CLUSTER_PROFILE', project_safe=True), mock.call(self.ctx, 'FAKE_NODE_PROFILE', project_safe=True) ]) @mock.patch.object(am.Action, 'create') @mock.patch.object(service.EngineService, '_validate_replace_nodes') @mock.patch.object(no.Node, 'find') @mock.patch.object(po.Profile, 'find') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_replace_nodes(self, notify, mock_find, mock_profile, mock_node, mock_validate, mock_action): cluster = mock.Mock(id='CID', profile_id='FAKE_ID') mock_find.return_value = cluster mock_profile.return_value = mock.Mock(type='FAKE_TYPE') old_node = mock.Mock(id='ORIGIN', cluster_id='CID', status='ACTIVE') new_node = mock.Mock(id='REPLACE', cluster_id='', status='ACTIVE', profile_id='FAKE_ID_1') mock_node.side_effect = [old_node, new_node] mock_action.return_value = 'ACTION_ID' param = {'ORIGINAL': 'REPLACE'} mock_validate.return_value = param req = orco.ClusterReplaceNodesRequest(identity='CLUSTER', nodes=param) # do it res = self.eng.cluster_replace_nodes(self.ctx, req.obj_to_primitive()) # verify self.assertEqual({'action': 'ACTION_ID'}, res) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_validate.assert_called_once_with(self.ctx, cluster, param) mock_action.assert_called_once_with( self.ctx, 'CID', consts.CLUSTER_REPLACE_NODES, name='cluster_replace_nodes_CID', cause=consts.CAUSE_RPC, status=am.Action.READY, inputs={'ORIGINAL': 'REPLACE'}) notify.assert_called_once_with() @mock.patch.object(service.EngineService, '_validate_replace_nodes') @mock.patch.object(co.Cluster, 'find') def test_cluster_replace_nodes_failed_validate(self, mock_find, mock_chk): nodes = {'OLD': 'NEW'} cluster = mock.Mock() mock_find.return_value = cluster mock_chk.side_effect = exc.BadRequest(msg='failed') req = orco.ClusterReplaceNodesRequest(identity='CLUSTER', nodes=nodes) # do it ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_replace_nodes, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, ex.exc_info[0]) self.assertEqual("failed.", six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'CLUSTER') mock_chk.assert_called_once_with(self.ctx, cluster, nodes) @mock.patch.object(nm.Node, 'load') @mock.patch.object(no.Node, 'get_all_by_cluster') @mock.patch.object(co.Cluster, 'find') def test_cluster_collect(self, mock_find, mock_get, mock_load): x_cluster = mock.Mock(id='FAKE_CLUSTER') mock_find.return_value = x_cluster x_obj_1 = mock.Mock(id='NODE1', physical_id='PHYID1') x_obj_1.to_dict.return_value = {'name': 'node1'} x_obj_2 = mock.Mock(id='NODE2', physical_id='PHYID2') x_obj_2.to_dict.return_value = {'name': 'node2'} x_node_1 = mock.Mock() x_node_2 = mock.Mock() x_node_1.get_details.return_value = {'ip': '1.2.3.4'} x_node_2.get_details.return_value = {'ip': '5.6.7.8'} mock_get.return_value = [x_obj_1, x_obj_2] mock_load.side_effect = [x_node_1, x_node_2] req = orco.ClusterCollectRequest(identity='CLUSTER_ID', path='details.ip') res = self.eng.cluster_collect(self.ctx, req.obj_to_primitive()) self.assertIn('cluster_attributes', res) self.assertIn({'id': 'NODE1', 'value': '1.2.3.4'}, res['cluster_attributes']) self.assertIn({'id': 'NODE2', 'value': '5.6.7.8'}, res['cluster_attributes']) mock_find.assert_called_once_with(self.ctx, 'CLUSTER_ID') mock_get.assert_called_once_with(self.ctx, 'FAKE_CLUSTER') mock_load.assert_has_calls([ mock.call(self.ctx, db_node=x_obj_1), mock.call(self.ctx, db_node=x_obj_2) ]) x_obj_1.to_dict.assert_called_once_with() x_node_1.get_details.assert_called_once_with(self.ctx) x_obj_2.to_dict.assert_called_once_with() x_node_2.get_details.assert_called_once_with(self.ctx) @mock.patch.object(co.Cluster, 'find') @mock.patch.object(common_utils, 'get_path_parser') def test_cluster_collect_bad_path(self, mock_parser, mock_find): mock_parser.side_effect = exc.BadRequest(msg='Boom') req = orco.ClusterCollectRequest(identity='CLUSTER_ID', path='foo.bar') err = self.assertRaises(rpc.ExpectedException, self.eng.cluster_collect, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.BadRequest, err.exc_info[0]) mock_parser.assert_called_once_with('foo.bar') self.assertEqual(0, mock_find.call_count) @mock.patch.object(no.Node, 'get_all_by_cluster') @mock.patch.object(co.Cluster, 'find') def test_cluster_collect_cluster_not_found(self, mock_find, mock_get): cid = 'FAKE_CLUSTER' mock_find.side_effect = exc.ResourceNotFound(type='cluster', id=cid) req = orco.ClusterCollectRequest(identity=cid, path='foo.bar') err = self.assertRaises(rpc.ExpectedException, self.eng.cluster_collect, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceNotFound, err.exc_info[0]) mock_find.assert_called_once_with(self.ctx, cid) self.assertEqual(0, mock_get.call_count) @mock.patch.object(no.Node, 'get_all_by_cluster') @mock.patch.object(co.Cluster, 'find') def test_cluster_collect_no_nodes(self, mock_find, mock_get): x_cluster = mock.Mock(id='FAKE_CLUSTER') mock_find.return_value = x_cluster mock_get.return_value = [] req = orco.ClusterCollectRequest(identity='CLUSTER_ID', path='barr') res = self.eng.cluster_collect(self.ctx, req.obj_to_primitive()) self.assertEqual({'cluster_attributes': []}, res) mock_find.assert_called_once_with(self.ctx, 'CLUSTER_ID') mock_get.assert_called_once_with(self.ctx, 'FAKE_CLUSTER') @mock.patch.object(no.Node, 'get_all_by_cluster') @mock.patch.object(co.Cluster, 'find') def test_cluster_collect_no_details(self, mock_find, mock_get): x_cluster = mock.Mock(id='FAKE_CLUSTER') mock_find.return_value = x_cluster x_node_1 = mock.Mock(id='NODE1', physical_id=None) x_node_1.to_dict.return_value = {'name': 'node1'} x_node_2 = mock.Mock(id='NODE2', physical_id=None) x_node_2.to_dict.return_value = {'name': 'node2'} mock_get.return_value = [x_node_1, x_node_2] req = orco.ClusterCollectRequest(identity='CLUSTER_ID', path='name') res = self.eng.cluster_collect(self.ctx, req.obj_to_primitive()) self.assertIn('cluster_attributes', res) self.assertIn({'id': 'NODE1', 'value': 'node1'}, res['cluster_attributes']) self.assertIn({'id': 'NODE2', 'value': 'node2'}, res['cluster_attributes']) mock_find.assert_called_once_with(self.ctx, 'CLUSTER_ID') mock_get.assert_called_once_with(self.ctx, 'FAKE_CLUSTER') x_node_1.to_dict.assert_called_once_with() self.assertEqual(0, x_node_1.get_details.call_count) x_node_2.to_dict.assert_called_once_with() self.assertEqual(0, x_node_2.get_details.call_count) @mock.patch.object(no.Node, 'get_all_by_cluster') @mock.patch.object(co.Cluster, 'find') def test_cluster_collect_no_match(self, mock_find, mock_get): x_cluster = mock.Mock(id='FAKE_CLUSTER') mock_find.return_value = x_cluster x_node_1 = mock.Mock(physical_id=None) x_node_1.to_dict.return_value = {'name': 'node1'} x_node_2 = mock.Mock(physical_id=None) x_node_2.to_dict.return_value = {'name': 'node2'} mock_get.return_value = [x_node_1, x_node_2] req = orco.ClusterCollectRequest(identity='CLUSTER_ID', path='bogus') res = self.eng.cluster_collect(self.ctx, req.obj_to_primitive()) self.assertEqual({'cluster_attributes': []}, res) mock_find.assert_called_once_with(self.ctx, 'CLUSTER_ID') mock_get.assert_called_once_with(self.ctx, 'FAKE_CLUSTER') x_node_1.to_dict.assert_called_once_with() self.assertEqual(0, x_node_1.get_details.call_count) x_node_2.to_dict.assert_called_once_with() self.assertEqual(0, x_node_2.get_details.call_count) @mock.patch.object(am.Action, 'create') @mock.patch.object(ro.Receiver, 'get_all') @mock.patch.object(cpo.ClusterPolicy, 'get_all') @mock.patch.object(co.Cluster, 'find') @mock.patch.object(dispatcher, 'start_action') def test_cluster_delete(self, notify, mock_find, mock_policies, mock_receivers, mock_action): x_obj = mock.Mock(id='12345678AB', status='ACTIVE', dependents={}) mock_find.return_value = x_obj mock_policies.return_value = [] mock_receivers.return_value = [] mock_action.return_value = 'ACTION_ID' req = orco.ClusterDeleteRequest(identity='IDENTITY') result = self.eng.cluster_delete(self.ctx, req.obj_to_primitive()) self.assertEqual({'action': 'ACTION_ID'}, result) mock_find.assert_called_once_with(self.ctx, 'IDENTITY') mock_policies.assert_called_once_with(self.ctx, '12345678AB') mock_receivers.assert_called_once_with( self.ctx, filters={'cluster_id': '12345678AB'}) mock_action.assert_called_once_with( self.ctx, '12345678AB', 'CLUSTER_DELETE', name='cluster_delete_12345678', cause=consts.CAUSE_RPC, status=am.Action.READY) notify.assert_called_once_with() @mock.patch.object(co.Cluster, 'find') def test_cluster_delete_with_containers(self, mock_find): dependents = {'profiles': ['profile1']} cluster = mock.Mock(id='cluster1', status='ACTIVE', dependents=dependents) mock_find.return_value = cluster req = orco.ClusterDeleteRequest(identity='FAKE_CLUSTER') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_delete, self.ctx, req.obj_to_primitive()) msg = _("The cluster 'FAKE_CLUSTER' cannot be deleted: still " "referenced by profile(s): ['profile1'].") self.assertEqual(exc.ResourceInUse, ex.exc_info[0]) self.assertEqual(msg, six.text_type(ex.exc_info[1])) @mock.patch.object(co.Cluster, 'find') def test_cluster_delete_not_found(self, mock_find): mock_find.side_effect = exc.ResourceNotFound(type='cluster', id='Bogus') req = orco.ClusterDeleteRequest(identity='Bogus') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_delete, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceNotFound, ex.exc_info[0]) self.assertEqual("The cluster 'Bogus' could not be found.", six.text_type(ex.exc_info[1])) @mock.patch.object(co.Cluster, 'find') def test_cluster_delete_improper_status(self, mock_find): for bad_status in [consts.CS_CREATING, consts.CS_UPDATING, consts.CS_DELETING, consts.CS_RECOVERING]: fake_cluster = mock.Mock(id='12345678AB', status=bad_status) mock_find.return_value = fake_cluster req = orco.ClusterDeleteRequest(identity='BUSY') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_delete, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ActionInProgress, ex.exc_info[0]) self.assertEqual( "The cluster 'BUSY' is in status %s." % bad_status, six.text_type(ex.exc_info[1])) @mock.patch.object(cpo.ClusterPolicy, 'get_all') @mock.patch.object(co.Cluster, 'find') def test_cluster_delete_policy_attached(self, mock_find, mock_policies): x_obj = mock.Mock(id='12345678AB', dependents={}) mock_find.return_value = x_obj mock_policies.return_value = [mock.Mock()] req = orco.ClusterDeleteRequest(identity='IDENTITY') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_delete, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceInUse, ex.exc_info[0]) expected_msg = _("The cluster 'IDENTITY' cannot be deleted: " "there is still policy(s) attached to it.") self.assertEqual(expected_msg, six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'IDENTITY') mock_policies.assert_called_once_with(self.ctx, '12345678AB') @mock.patch.object(ro.Receiver, 'get_all') @mock.patch.object(cpo.ClusterPolicy, 'get_all') @mock.patch.object(co.Cluster, 'find') def test_cluster_delete_with_receiver(self, mock_find, mock_policies, mock_receivers): x_obj = mock.Mock(id='12345678AB', dependents={}) mock_find.return_value = x_obj mock_policies.return_value = [] mock_receivers.return_value = [mock.Mock()] req = orco.ClusterDeleteRequest(identity='IDENTITY') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_delete, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceInUse, ex.exc_info[0]) expected_msg = _("The cluster 'IDENTITY' cannot be deleted: " "there is still receiver(s) associated with it.") self.assertEqual(expected_msg, six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'IDENTITY') mock_policies.assert_called_once_with(self.ctx, '12345678AB') mock_receivers.assert_called_once_with( self.ctx, filters={'cluster_id': '12345678AB'}) @mock.patch.object(ro.Receiver, 'get_all') @mock.patch.object(cpo.ClusterPolicy, 'get_all') @mock.patch.object(co.Cluster, 'find') def test_cluster_delete_mult_err(self, mock_find, mock_policies, mock_receivers): x_obj = mock.Mock(id='12345678AB', dependents={}) mock_find.return_value = x_obj mock_policies.return_value = [mock.Mock()] mock_receivers.return_value = [mock.Mock()] req = orco.ClusterDeleteRequest(identity='IDENTITY') ex = self.assertRaises(rpc.ExpectedException, self.eng.cluster_delete, self.ctx, req.obj_to_primitive()) self.assertEqual(exc.ResourceInUse, ex.exc_info[0]) self.assertIn('there is still policy(s) attached to it.', six.text_type(ex.exc_info[1])) self.assertIn('there is still receiver(s) associated with it.', six.text_type(ex.exc_info[1])) mock_find.assert_called_once_with(self.ctx, 'IDENTITY') mock_policies.assert_called_once_with(self.ctx, '12345678AB') mock_receivers.assert_called_once_with( self.ctx, filters={'cluster_id': '12345678AB'})