senlin/senlin/tests/unit/engine/service/test_clusters.py

2239 lines
98 KiB
Python
Executable File

# 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.actions import cluster_action as ca
from senlin.engine import dispatcher
from senlin.engine import node as nm
from senlin.engine import service
from senlin.objects import action as ao
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)
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)
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_id,
project=self.ctx.project_id, domain=self.ctx.domain_id))
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_id,
project=self.ctx.project_id, domain=self.ctx.domain_id))
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)
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 non-negative 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(ao.Action, 'delete_by_target')
@mock.patch.object(am.Action, 'create')
@mock.patch.object(co.Cluster, 'find')
@mock.patch.object(dispatcher, 'start_action')
def test_cluster_check_with_delete(self, notify, mock_find, mock_action,
mock_delete):
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={'delete_check_action': True})
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_delete.assert_called_once_with(
self.ctx, 'CID', action=['CLUSTER_CHECK'],
status=['SUCCEEDED', 'FAILED']
)
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={'delete_check_action': True},
)
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(am.Action, 'create')
@mock.patch.object(co.Cluster, 'find')
@mock.patch.object(dispatcher, 'start_action')
def test_cluster_check_project_is_none(self, notify, mock_find,
mock_action):
x_cluster = mock.Mock(id='CID', user='USER')
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(am.Action, 'create')
@mock.patch.object(co.Cluster, 'find')
@mock.patch.object(dispatcher, 'start_action')
def test_cluster_recover_rebuild(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': 'REBUILD'})
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': 'REBUILD'},
)
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_recover_reboot(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': 'REBOOT'})
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': 'REBOOT'},
)
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_recover_default(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')
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={}
)
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(co.Cluster, 'find')
def test_cluster_recover_invalid_operation(self, mock_find):
x_cluster = mock.Mock(id='CID')
mock_find.return_value = x_cluster
req = orco.ClusterRecoverRequest(identity='Bogus',
params={'operation': '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("Operation value 'fake' has to be one of the "
"following: REBOOT, REBUILD, RECREATE.",
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_operation_params(self, mock_find):
x_cluster = mock.Mock(id='CID')
mock_find.return_value = x_cluster
req = orco.ClusterRecoverRequest(
identity='Bogus',
params={'operation': 'reboot',
'operation_params': {'type': 'blah'}
}
)
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("Type field 'blah' in operation_params has to be one "
"of the following: SOFT, HARD.",
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={'candidates': {'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', force=False)
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',
force=False)
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',
force=False)
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',
force=False)
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',
force=False)
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',
force=False)
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',
force=False)
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'})
@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_force(self, notify, mock_find, mock_policies,
mock_receivers, mock_action):
for bad_status in [consts.CS_CREATING, consts.CS_UPDATING,
consts.CS_DELETING, consts.CS_RECOVERING]:
x_obj = mock.Mock(id='12345678AB', status=bad_status,
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', force=True)
result = self.eng.cluster_delete(self.ctx, req.obj_to_primitive())
self.assertEqual({'action': 'ACTION_ID'}, result)
mock_find.assert_called_with(self.ctx, 'IDENTITY')
mock_policies.assert_called_with(self.ctx, '12345678AB')
mock_receivers.assert_called_with(
self.ctx, filters={'cluster_id': '12345678AB'})
mock_action.assert_called_with(
self.ctx, '12345678AB', 'CLUSTER_DELETE',
name='cluster_delete_12345678',
cause=consts.CAUSE_RPC,
status=am.Action.READY)
notify.assert_called_with()
@mock.patch.object(ca, 'CompleteLifecycleProc')
def test_cluster_complete_lifecycle(self, mock_lifecycle):
req = orco.ClusterCompleteLifecycleRequest(
identity='CLUSTER', lifecycle_action_token='NODE_ACTION_ID')
# do it
res = self.eng.cluster_complete_lifecycle(self.ctx,
req.obj_to_primitive())
# verify
self.assertEqual({'action': 'NODE_ACTION_ID'}, res)
mock_lifecycle.assert_called_once_with(self.ctx, 'NODE_ACTION_ID')