senlin/senlin/tests/unit/engine/test_cluster.py

1014 lines
39 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from oslo_config import cfg
import six
from senlin.common import consts
from senlin.common import exception
from senlin.engine import cluster as cm
from senlin.engine import cluster_policy as cpm
from senlin.engine import health_manager
from senlin.engine import node as node_mod
from senlin.objects import cluster as co
from senlin.objects import cluster_policy as cpo
from senlin.policies import base as pcb
from senlin.profiles import base as pfb
from senlin.tests.unit.common import base
from senlin.tests.unit.common import utils
PROFILE_ID = 'aa5f86b8-e52b-4f2b-828a-4c14c770938d'
CLUSTER_ID = '60efdaa1-06c2-4fcf-ae44-17a2d85ff3ea'
POLICY_ID = '2c5139a6-24ba-4a6f-bd53-a268f61536de'
class TestCluster(base.SenlinTestCase):
def setUp(self):
super(TestCluster, self).setUp()
self.context = utils.dummy_context(project='cluster_test_project')
def test_init(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
self.assertIsNone(cluster.id)
self.assertEqual('test-cluster', cluster.name)
self.assertEqual(PROFILE_ID, cluster.profile_id)
self.assertEqual('', cluster.user)
self.assertEqual('', cluster.project)
self.assertEqual('', cluster.domain)
self.assertIsNone(cluster.init_at)
self.assertIsNone(cluster.created_at)
self.assertIsNone(cluster.updated_at)
self.assertEqual(0, cluster.min_size)
self.assertEqual(-1, cluster.max_size)
self.assertEqual(0, cluster.desired_capacity)
self.assertEqual(1, cluster.next_index)
self.assertEqual(cfg.CONF.default_action_timeout, cluster.timeout)
self.assertEqual('INIT', cluster.status)
self.assertEqual('Initializing', cluster.status_reason)
self.assertEqual({}, cluster.data)
self.assertEqual({}, cluster.metadata)
self.assertEqual({'profile': None, 'nodes': [], 'policies': []},
cluster.rt)
def test_init_with_none(self):
kwargs = {
'min_size': None,
'max_size': None,
'metadata': None
}
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID, **kwargs)
self.assertEqual(0, cluster.min_size)
self.assertEqual(-1, cluster.max_size)
self.assertEqual({}, cluster.metadata)
@mock.patch.object(cm.Cluster, '_load_runtime_data')
def test_init_with_context(self, mock_load):
cm.Cluster('test-cluster', 0, PROFILE_ID, context=self.context)
mock_load.assert_called_once_with(self.context)
@mock.patch.object(cpo.ClusterPolicy, 'get_all')
@mock.patch.object(pcb.Policy, 'load')
@mock.patch.object(pfb.Profile, 'load')
@mock.patch.object(node_mod.Node, 'load_all')
def test__load_runtime_data(self, mock_nodes, mock_profile, mock_policy,
mock_pb):
x_binding = mock.Mock()
x_binding.policy_id = POLICY_ID
mock_pb.return_value = [x_binding]
x_policy = mock.Mock()
mock_policy.return_value = x_policy
x_profile = mock.Mock()
mock_profile.return_value = x_profile
x_node_1 = mock.Mock()
x_node_2 = mock.Mock()
mock_nodes.return_value = [x_node_1, x_node_2]
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.id = CLUSTER_ID
cluster._load_runtime_data(self.context)
rt = cluster.rt
self.assertEqual(x_profile, rt['profile'])
self.assertEqual([x_node_1, x_node_2], rt['nodes'])
self.assertEqual(2, len(rt['nodes']))
self.assertTrue(isinstance(rt['nodes'], list))
self.assertEqual([x_policy], rt['policies'])
mock_pb.assert_called_once_with(self.context, CLUSTER_ID)
mock_policy.assert_called_once_with(self.context,
POLICY_ID,
project_safe=False)
mock_profile.assert_called_once_with(self.context,
profile_id=PROFILE_ID,
project_safe=False)
mock_nodes.assert_called_once_with(self.context,
cluster_id=CLUSTER_ID)
def test__load_runtime_data_id_is_none(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster._load_runtime_data(self.context)
rt = cluster.rt
self.assertIsNone(rt['profile'])
self.assertEqual([], rt['nodes'])
self.assertEqual(0, len(rt['nodes']))
self.assertTrue(isinstance(rt['nodes'], list))
self.assertEqual([], rt['policies'])
def test_store_for_create(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID,
user=self.context.user,
project=self.context.project)
mock_load = self.patchobject(cluster, '_load_runtime_data')
self.assertIsNone(cluster.id)
cluster_id = cluster.store(self.context)
self.assertIsNotNone(cluster_id)
mock_load.assert_called_once_with(self.context)
result = co.Cluster.get(self.context, cluster_id=cluster_id)
self.assertIsNotNone(result)
self.assertEqual('test-cluster', result.name)
self.assertEqual(PROFILE_ID, result.profile_id)
self.assertEqual(self.context.user, result.user)
self.assertEqual(self.context.project, result.project)
self.assertEqual(self.context.domain, result.domain)
self.assertIsNotNone(result.init_at)
self.assertIsNone(result.created_at)
self.assertIsNone(result.updated_at)
self.assertEqual(0, result.min_size)
self.assertEqual(-1, result.max_size)
self.assertEqual(0, result.desired_capacity)
self.assertEqual(1, result.next_index)
self.assertEqual(cfg.CONF.default_action_timeout, result.timeout)
self.assertEqual('INIT', result.status)
self.assertEqual('Initializing', result.status_reason)
self.assertEqual({}, result.data)
self.assertEqual({}, result.metadata)
def test_store_for_update(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID,
user=self.context.user,
project=self.context.project)
mock_load = self.patchobject(cluster, '_load_runtime_data')
self.assertIsNone(cluster.id)
cluster_id = cluster.store(self.context)
self.assertIsNotNone(cluster_id)
mock_load.assert_called_once_with(self.context)
# do an update
cluster.name = 'test-cluster-1'
cluster.min_size = 1
cluster.max_size = 3
cluster.desired_capacity = 2
cluster.timeout = 120
cluster.data = {'FOO': 'BAR'}
cluster.metadata = {'KEY': 'VALUE'}
new_id = cluster.store(self.context)
self.assertEqual(cluster_id, new_id)
result = co.Cluster.get(self.context, cluster_id)
self.assertIsNotNone(result)
self.assertEqual('test-cluster-1', result.name)
self.assertEqual(self.context.user, result.user)
self.assertEqual(self.context.project, result.project)
self.assertEqual(1, result.min_size)
self.assertEqual(3, result.max_size)
self.assertEqual(2, result.desired_capacity)
self.assertEqual(120, result.timeout)
self.assertEqual({'FOO': 'BAR'}, result.data)
self.assertEqual({'KEY': 'VALUE'}, result.metadata)
@mock.patch.object(cm.Cluster, '_from_object')
def test_load_via_db_object(self, mock_init):
x_obj = mock.Mock()
result = cm.Cluster.load(self.context, dbcluster=x_obj)
self.assertEqual(mock_init.return_value, result)
mock_init.assert_called_once_with(self.context, x_obj)
@mock.patch.object(co.Cluster, 'get')
@mock.patch.object(cm.Cluster, '_from_object')
def test_load_via_cluster_id(self, mock_init, mock_get):
x_obj = mock.Mock()
mock_get.return_value = x_obj
result = cm.Cluster.load(self.context, cluster_id=CLUSTER_ID)
self.assertEqual(mock_init.return_value, result)
mock_get.assert_called_once_with(self.context, CLUSTER_ID,
project_safe=True)
mock_init.assert_called_once_with(self.context, x_obj)
@mock.patch.object(co.Cluster, 'get')
def test_load_not_found(self, mock_get):
mock_get.return_value = None
ex = self.assertRaises(exception.ResourceNotFound,
cm.Cluster.load,
self.context, cluster_id=CLUSTER_ID)
self.assertEqual("The cluster '%s' could not be found." % CLUSTER_ID,
six.text_type(ex))
mock_get.assert_called_once_with(self.context, CLUSTER_ID,
project_safe=True)
@mock.patch.object(cm.Cluster, '_from_object')
@mock.patch.object(co.Cluster, 'get_all')
def test_load_all(self, mock_get, mock_init):
x_obj_1 = mock.Mock()
x_obj_2 = mock.Mock()
mock_get.return_value = [x_obj_1, x_obj_2]
x_cluster_1 = mock.Mock()
x_cluster_2 = mock.Mock()
mock_init.side_effect = [x_cluster_1, x_cluster_2]
result = cm.Cluster.load_all(self.context)
self.assertEqual([x_cluster_1, x_cluster_2], [c for c in result])
mock_get.assert_called_once_with(self.context,
limit=None, marker=None,
sort=None, filters=None,
project_safe=True)
mock_init.assert_has_calls([
mock.call(self.context, x_obj_1),
mock.call(self.context, x_obj_2)])
@mock.patch.object(co.Cluster, 'update')
def test_set_status_for_create(self, mock_update):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID,
id=CLUSTER_ID, status='CREATING')
cluster.set_status(self.context, consts.CS_ACTIVE, 'Cluster created')
self.assertEqual(consts.CS_ACTIVE, cluster.status)
self.assertEqual('Cluster created', cluster.status_reason)
self.assertIsNotNone(cluster.created_at)
self.assertIsNone(cluster.updated_at)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{
'created_at': mock.ANY,
'status': consts.CS_ACTIVE,
'status_reason': 'Cluster created'
}
)
@mock.patch.object(co.Cluster, 'update')
def test_set_status_for_update(self, mock_update):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID,
id=CLUSTER_ID, status='UPDATING')
cluster.set_status(self.context, consts.CS_ACTIVE, 'Cluster updated')
self.assertEqual(consts.CS_ACTIVE, cluster.status)
self.assertEqual('Cluster updated', cluster.status_reason)
self.assertIsNotNone(cluster.updated_at)
@mock.patch.object(co.Cluster, 'update')
def test_set_status_for_resize(self, mock_update):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID,
id=CLUSTER_ID, status='RESIZING')
cluster.set_status(self.context, consts.CS_ACTIVE, 'Cluster resized')
self.assertEqual(consts.CS_ACTIVE, cluster.status)
self.assertEqual('Cluster resized', cluster.status_reason)
self.assertIsNotNone(cluster.updated_at)
@mock.patch.object(pfb.Profile, 'load')
@mock.patch.object(co.Cluster, 'update')
def test_set_status_for_update_with_profile(self, mock_update,
mock_load):
x_profile = mock.Mock()
mock_load.return_value = x_profile
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID, id=CLUSTER_ID,
status='UPDATING')
new_profile_id = 'a64f0b03-4b77-49d5-89e0-7bcc77c4ce67'
cluster.set_status(self.context, consts.CS_ACTIVE, 'Cluster updated',
profile_id=new_profile_id)
self.assertEqual(consts.CS_ACTIVE, cluster.status)
self.assertEqual('Cluster updated', cluster.status_reason)
self.assertIsNotNone(cluster.updated_at)
self.assertEqual(x_profile, cluster.rt['profile'])
self.assertEqual(new_profile_id, cluster.profile_id)
mock_load.assert_called_once_with(self.context,
profile_id=new_profile_id)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{
'status': consts.CS_ACTIVE,
'status_reason': 'Cluster updated',
'profile_id': new_profile_id,
'updated_at': mock.ANY,
}
)
@mock.patch.object(co.Cluster, 'update')
def test_set_status_without_reason(self, mock_update):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID, id=CLUSTER_ID,
status='UPDATING',
status_reason='Update in progress')
cluster.set_status(self.context, consts.CS_WARNING)
self.assertEqual(consts.CS_WARNING, cluster.status)
self.assertEqual('Update in progress', cluster.status_reason)
mock_update.assert_called_once_with(self.context, CLUSTER_ID,
{'status': consts.CS_WARNING})
def test_do_create(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
mock_status = self.patchobject(cluster, 'set_status')
res = cluster.do_create(self.context)
self.assertTrue(res)
mock_status.assert_called_once_with(
self.context, consts.CS_CREATING, 'Creation in progress')
def test_do_create_wrong_status(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.status = consts.CS_ACTIVE
res = cluster.do_create(self.context)
self.assertFalse(res)
@mock.patch.object(co.Cluster, 'delete')
def test_do_delete(self, mock_delete):
mock_delete.return_value = None
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.id = CLUSTER_ID
res = cluster.do_delete(self.context)
mock_delete.assert_called_once_with(self.context, CLUSTER_ID)
self.assertTrue(res)
def test_do_update(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
mock_status = self.patchobject(cluster, 'set_status')
res = cluster.do_update(self.context)
mock_status.assert_called_once_with(self.context, consts.CS_UPDATING,
'Update in progress')
self.assertTrue(res)
def test_do_check(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
mock_status = self.patchobject(cluster, 'set_status')
res = cluster.do_check(self.context)
mock_status.assert_called_once_with(self.context, consts.CS_CHECKING,
'Check in progress')
self.assertTrue(res)
def test_do_recover(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
mock_status = self.patchobject(cluster, 'set_status')
res = cluster.do_recover(self.context)
mock_status.assert_called_once_with(self.context, consts.CS_RECOVERING,
'Recovery in progress')
self.assertTrue(res)
def test_do_operation(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
mock_status = self.patchobject(cluster, 'set_status')
res = cluster.do_operation(self.context, operation='dance')
mock_status.assert_called_once_with(self.context, consts.CS_OPERATING,
'Operation dance in progress')
self.assertTrue(res)
def test_nodes_property(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
self.assertEqual([], cluster.nodes)
# with nodes
node1 = mock.Mock()
node2 = mock.Mock()
cluster.rt['nodes'] = [node1, node2]
self.assertEqual([node1, node2], cluster.nodes)
def test_policies_property(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
self.assertEqual([], cluster.policies)
# with policies attached
policy1 = mock.Mock()
policy2 = mock.Mock()
cluster.rt['policies'] = [policy1, policy2]
self.assertEqual([policy1, policy2], cluster.policies)
def test_add_node(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
self.assertEqual([], cluster.nodes)
# add one node
node = mock.Mock()
cluster.add_node(node)
self.assertEqual([node], cluster.nodes)
# add another node
another_node = mock.Mock()
cluster.add_node(another_node)
self.assertEqual([node, another_node], cluster.nodes)
def test_remove_node(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
self.assertEqual([], cluster.nodes)
# remove from empty list should be okay
res = cluster.remove_node('BOGUS')
self.assertIsNone(res)
# add one node
node1 = mock.Mock()
node1.id = '62d52dd6-5f83-4340-b079-349da2f9ffd9'
cluster.add_node(node1)
self.assertEqual([node1], cluster.nodes)
# remove non-existent node should be okay
node2 = mock.Mock()
node2.id = 'd68214b2-e466-457f-a661-c8413a094a10'
res = cluster.remove_node(node2)
self.assertIsNone(res)
self.assertEqual([node1], cluster.nodes)
# add another node
cluster.add_node(node2)
self.assertEqual([node1, node2], cluster.nodes)
# remove first node
res = cluster.remove_node(node1.id)
self.assertIsNone(res)
self.assertEqual([node2], cluster.nodes)
# reload and remove node
node3 = mock.Mock()
node3.id = 'd68214b2-e466-457f-a661-c8413a094a10'
res = cluster.remove_node(node3.id)
self.assertIsNone(res)
self.assertEqual([], cluster.nodes)
@mock.patch.object(pcb.Policy, 'load')
@mock.patch.object(cpm, 'ClusterPolicy')
def test_attach_policy(self, mock_cp, mock_load):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.id = CLUSTER_ID
policy = mock.Mock()
policy.attach.return_value = (True, None)
policy.PRIORITY = 10
mock_load.return_value = policy
binding = mock.Mock()
mock_cp.return_value = binding
values = {'enabled': True}
res, reason = cluster.attach_policy(self.context, POLICY_ID, values)
policy.attach.assert_called_once_with(cluster)
mock_load.assert_called_once_with(self.context, POLICY_ID)
mock_cp.assert_called_once_with(CLUSTER_ID, POLICY_ID, priority=10,
enabled=True, data=None)
binding.store.assert_called_once_with(self.context)
self.assertIn(policy, cluster.policies)
@mock.patch.object(pcb.Policy, 'load')
def test_attach_policy_already_attached(self, mock_load):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
policy_id = '62d52dd6-5f83-4340-b079-349da2f9ffd9'
existing = mock.Mock(id=policy_id)
cluster.rt['policies'] = [existing]
policy = mock.Mock()
mock_load.return_value = policy
# do it
res, reason = cluster.attach_policy(self.context, policy_id, {})
self.assertTrue(res)
self.assertEqual('Policy already attached.', reason)
mock_load.assert_called_once_with(self.context, policy_id)
@mock.patch.object(pcb.Policy, 'load')
def test_attach_policy_type_conflict(self, mock_load):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.id = CLUSTER_ID
existing = mock.Mock()
existing.id = POLICY_ID
existing.type = 'POLICY_TYPE_ONE'
cluster.rt['policies'] = [existing]
policy = mock.Mock()
policy.singleton = True
policy.type = 'POLICY_TYPE_ONE'
mock_load.return_value = policy
# do it
new_policy_id = '62d52dd6-5f83-4340-b079-349da2f9ffd9'
res, reason = cluster.attach_policy(self.context, new_policy_id, {})
# assert
self.assertFalse(res)
expected = ('Only one instance of policy type (POLICY_TYPE_ONE) can '
'be attached to a cluster, but another instance '
'(%s) is found attached to the cluster '
'(%s) already.' % (POLICY_ID, CLUSTER_ID))
self.assertEqual(expected, reason)
mock_load.assert_called_once_with(self.context, new_policy_id)
@mock.patch.object(cpm, 'ClusterPolicy')
@mock.patch.object(pcb.Policy, 'load')
def test_attach_policy_type_conflict_but_ok(self, mock_load, mock_cp):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
existing = mock.Mock()
existing.id = POLICY_ID
existing.type = 'POLICY_TYPE_ONE'
cluster.rt['policies'] = [existing]
policy = mock.Mock()
policy.singleton = False
policy.type = 'POLICY_TYPE_ONE'
policy.attach.return_value = (True, None)
policy.PRIORITY = 10
mock_load.return_value = policy
binding = mock.Mock()
mock_cp.return_value = binding
values = {'enabled': True}
# do it
new_policy_id = '62d52dd6-5f83-4340-b079-349da2f9ffd9'
res, reason = cluster.attach_policy(self.context, new_policy_id,
values)
# assert
self.assertTrue(res)
self.assertEqual('Policy attached.', reason)
policy.attach.assert_called_once_with(cluster)
mock_load.assert_called_once_with(self.context, new_policy_id)
mock_cp.assert_called_once_with(cluster.id, new_policy_id, priority=10,
enabled=True, data=None)
binding.store.assert_called_once_with(self.context)
self.assertIn(policy, cluster.policies)
@mock.patch.object(pcb.Policy, 'load')
def test_attach_policy_failed_do_attach(self, mock_load):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
policy = mock.Mock()
policy.attach.return_value = (False, 'Bad things happened.')
mock_load.return_value = policy
# do it
new_id = '62d52dd6-5f83-4340-b079-349da2f9ffd9'
res, reason = cluster.attach_policy(self.context, new_id, {})
self.assertFalse(res)
self.assertEqual('Bad things happened.', reason)
policy.attach.assert_called_once_with(cluster)
mock_load.assert_called_once_with(self.context, new_id)
@mock.patch.object(cpo.ClusterPolicy, 'delete')
@mock.patch.object(pcb.Policy, 'load')
def test_detach_policy(self, mock_load, mock_detach):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.id = CLUSTER_ID
policy = mock.Mock()
policy.id = POLICY_ID
existing = mock.Mock()
existing.id = POLICY_ID
cluster.rt['policies'] = [existing]
policy.detach.return_value = (True, None)
mock_load.return_value = policy
res, reason = cluster.detach_policy(self.context, POLICY_ID)
self.assertTrue(res)
self.assertEqual('Policy detached.', reason)
policy.detach.assert_called_once_with(cluster)
mock_load.assert_called_once_with(self.context, POLICY_ID)
mock_detach.assert_called_once_with(self.context, CLUSTER_ID,
POLICY_ID)
self.assertEqual([], cluster.rt['policies'])
def test_detach_policy_not_attached(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.rt['policies'] = []
res, reason = cluster.detach_policy(self.context, POLICY_ID)
self.assertFalse(res)
self.assertEqual('Policy not attached.', reason)
@mock.patch.object(pcb.Policy, 'load')
def test_detach_policy_failed_detach(self, mock_load):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
policy = mock.Mock()
policy.id = POLICY_ID
policy.detach.return_value = False, 'Things went wrong.'
mock_load.return_value = policy
cluster.rt['policies'] = [policy]
res, reason = cluster.detach_policy(self.context, POLICY_ID)
self.assertFalse(res)
self.assertEqual('Things went wrong.', reason)
mock_load.assert_called_once_with(self.context, POLICY_ID)
policy.detach.assert_called_once_with(cluster)
@mock.patch.object(cpo.ClusterPolicy, 'update')
def test_update_policy(self, mock_update):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.id = CLUSTER_ID
existing = mock.Mock()
existing.id = POLICY_ID
existing.type = "senlin.poicy.foo"
cluster.rt['policies'] = [existing]
values = {
'enabled': False
}
res, reason = cluster.update_policy(self.context, POLICY_ID, **values)
self.assertTrue(res)
self.assertEqual('Policy updated.', reason)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID, POLICY_ID, {'enabled': False})
def test_update_policy_not_attached(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
cluster.rt['policies'] = []
values = {'enabled': False}
# do it
res, reason = cluster.update_policy(self.context, POLICY_ID, **values)
self.assertFalse(res)
self.assertEqual('Policy not attached.', reason)
def test_update_policy_no_update_needed(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
existing = mock.Mock()
existing.id = POLICY_ID
cluster.rt['policies'] = [existing]
values = {}
# do it
res, reason = cluster.update_policy(self.context, POLICY_ID, **values)
self.assertTrue(res)
self.assertEqual('No update is needed.', reason)
@mock.patch.object(cpo.ClusterPolicy, "update")
@mock.patch.object(health_manager, "enable")
def test_update_policy_enable_health(self, mock_enable, mock_update):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID, id=CLUSTER_ID)
existing = mock.Mock(id=POLICY_ID, type="senlin.policy.health")
cluster.rt['policies'] = [existing]
values = {"enabled": True}
# do it
res, reason = cluster.update_policy(self.context, POLICY_ID, **values)
self.assertTrue(res)
mock_enable.assert_called_once_with(CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID, POLICY_ID, {'enabled': True})
@mock.patch.object(cpo.ClusterPolicy, "update")
@mock.patch.object(health_manager, "disable")
def test_update_policy_disable_health(self, mock_disable, mock_update):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID, id=CLUSTER_ID)
existing = mock.Mock(id=POLICY_ID, type="senlin.policy.health")
cluster.rt['policies'] = [existing]
values = {"enabled": False}
# do it
res, reason = cluster.update_policy(self.context, POLICY_ID, **values)
self.assertTrue(res)
mock_disable.assert_called_once_with(CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID, POLICY_ID, {'enabled': False})
def test_get_region_distribution(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
node1 = mock.Mock()
node1.data = {'placement': {'region_name': 'R1'}}
node2 = mock.Mock()
node2.data = {'placement': {'region_name': 'R2'}}
node3 = mock.Mock()
node3.data = {'key': 'value'}
node4 = mock.Mock()
node4.data = {'placement': {'region_name': 'BAD'}}
nodes = [node1, node2, node3, node4]
for n in nodes:
cluster.add_node(n)
result = cluster.get_region_distribution(['R1', 'R2', 'R3'])
self.assertEqual(3, len(result))
self.assertEqual(1, result['R1'])
self.assertEqual(1, result['R2'])
self.assertEqual(0, result['R3'])
def test_get_zone_distribution(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
node1 = mock.Mock()
node1.data = {}
node1.get_details.return_value = {
'OS-EXT-AZ:availability_zone': 'AZ1',
}
node2 = mock.Mock()
node2.data = {
'foobar': 'irrelevant'
}
node3 = mock.Mock()
node3.data = {
'placement': {
'zone': 'AZ2'
}
}
nodes = [node1, node2, node3]
for n in nodes:
cluster.add_node(n)
result = cluster.get_zone_distribution(self.context,
['AZ1', 'AZ2', 'AZ3'])
self.assertEqual(3, len(result))
self.assertEqual(1, result['AZ1'])
self.assertEqual(1, result['AZ2'])
self.assertEqual(0, result['AZ3'])
node1.get_details.assert_called_once_with(self.context)
def test_nodes_by_region(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
node1 = mock.Mock(data={'placement': {'region_name': 'R1'}})
node2 = mock.Mock(data={'placement': {'region_name': 'R2'}})
node3 = mock.Mock(data={'key': 'value'})
node4 = mock.Mock(data={'placement': {'region_name': 'BAD'}})
nodes = [node1, node2, node3, node4]
for n in nodes:
cluster.add_node(n)
result = cluster.nodes_by_region('R1')
self.assertEqual(1, len(result))
self.assertEqual(node1, result[0])
result = cluster.nodes_by_region('R2')
self.assertEqual(1, len(result))
self.assertEqual(node2, result[0])
result = cluster.nodes_by_region('R3')
self.assertEqual(0, len(result))
def test_nodes_by_zone(self):
cluster = cm.Cluster('test-cluster', 0, PROFILE_ID)
node1 = mock.Mock(data={'placement': {'zone': 'AZ1'}})
node2 = mock.Mock(data={'placement': {'zone': 'AZ2'}})
node3 = mock.Mock(data={'key': 'value'})
node4 = mock.Mock(data={'placement': {'zone': 'BAD'}})
nodes = [node1, node2, node3, node4]
for n in nodes:
cluster.add_node(n)
result = cluster.nodes_by_zone('AZ1')
self.assertEqual(1, len(result))
self.assertEqual(node1, result[0])
result = cluster.nodes_by_zone('AZ2')
self.assertEqual(1, len(result))
self.assertEqual(node2, result[0])
result = cluster.nodes_by_region('AZ3')
self.assertEqual(0, len(result))
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_below_min_size(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 5, PROFILE_ID,
min_size=2, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ERROR')
node3 = mock.Mock(status='WARNING')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST')
rt = cluster.rt
self.assertEqual(3, len(rt['nodes']))
self.assertTrue(isinstance(rt['nodes'], list))
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'status': consts.CS_ERROR,
'status_reason': 'TEST: number of active nodes is below '
'min_size (2).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_below_desired_capacity(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 5, PROFILE_ID,
min_size=1, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ERROR')
node3 = mock.Mock(status='WARNING')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST')
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'status': consts.CS_WARNING,
'status_reason': 'TEST: number of active nodes is below '
'desired_capacity (5).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_equal_desired_capacity(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 3, PROFILE_ID,
min_size=1, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ACTIVE')
node3 = mock.Mock(status='ACTIVE')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST')
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'status': consts.CS_ACTIVE,
'status_reason': 'TEST: number of active nodes is equal or above '
'desired_capacity (3).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_above_desired_capacity(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 2, PROFILE_ID,
min_size=1, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ACTIVE')
node3 = mock.Mock(status='ACTIVE')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST')
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'status': consts.CS_ACTIVE,
'status_reason': 'TEST: number of active nodes is equal or above '
'desired_capacity (2).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_above_max_size(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 2, PROFILE_ID,
max_size=2, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ACTIVE')
node3 = mock.Mock(status='ACTIVE')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST')
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'status': consts.CS_WARNING,
'status_reason': 'TEST: number of active nodes is above '
'max_size (2).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_with_new_desired(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 5, PROFILE_ID, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ERROR')
node3 = mock.Mock(status='WARNING')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST', desired_capacity=2)
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'desired_capacity': 2,
'status': consts.CS_WARNING,
'status_reason': 'TEST: number of active nodes is below '
'desired_capacity (2).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status__new_desired_is_zero(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 5, PROFILE_ID, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ERROR')
node3 = mock.Mock(status='WARNING')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST', desired_capacity=0)
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'desired_capacity': 0,
'status': consts.CS_ACTIVE,
'status_reason': 'TEST: number of active nodes is equal or above '
'desired_capacity (0).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_with_new_min(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 5, PROFILE_ID,
id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ERROR')
node3 = mock.Mock(status='WARNING')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST', min_size=2)
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'min_size': 2,
'status': consts.CS_ERROR,
'status_reason': 'TEST: number of active nodes is below '
'min_size (2).'})
@mock.patch.object(co.Cluster, 'update')
@mock.patch.object(node_mod.Node, 'load_all')
def test_eval_status_with_new_max(self, mock_load, mock_update):
cluster = cm.Cluster('test-cluster', 2, PROFILE_ID,
max_size=5, id=CLUSTER_ID)
node1 = mock.Mock(status='ACTIVE')
node2 = mock.Mock(status='ACTIVE')
node3 = mock.Mock(status='ACTIVE')
mock_load.return_value = [node1, node2, node3]
cluster.eval_status(self.context, 'TEST', max_size=6)
mock_load.assert_called_once_with(self.context, cluster_id=CLUSTER_ID)
mock_update.assert_called_once_with(
self.context, CLUSTER_ID,
{'max_size': 6,
'status': consts.CS_ACTIVE,
'status_reason': 'TEST: number of active nodes is equal or above '
'desired_capacity (2).'})