854 lines
31 KiB
Python
854 lines
31 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 copy
|
|
from unittest import mock
|
|
|
|
|
|
from senlin.common import consts
|
|
from senlin.common import context
|
|
from senlin.common import exception as exc
|
|
from senlin.common import scaleutils
|
|
from senlin.objects import cluster_policy as cpo
|
|
from senlin.policies import affinity_policy as ap
|
|
from senlin.policies import base as pb
|
|
from senlin.tests.unit.common import base
|
|
from senlin.tests.unit.common import utils
|
|
|
|
|
|
class TestAffinityPolicy(base.SenlinTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestAffinityPolicy, self).setUp()
|
|
self.context = utils.dummy_context()
|
|
self.spec = {
|
|
'type': 'senlin.policy.affinity',
|
|
'version': '1.0',
|
|
'properties': {
|
|
'servergroup': {}
|
|
},
|
|
}
|
|
|
|
def test_policy_init(self):
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
self.assertIsNone(policy.id)
|
|
self.assertEqual('test-policy', policy.name)
|
|
self.assertEqual('senlin.policy.affinity-1.0', policy.type)
|
|
self.assertFalse(policy.enable_drs)
|
|
self.assertIsNone(policy._novaclient)
|
|
|
|
@mock.patch.object(pb.Policy, 'validate')
|
|
def test_validate_okay(self, mock_base_validate):
|
|
new_spec = copy.deepcopy(self.spec)
|
|
new_spec['properties']['availability_zone'] = 'NEWAZ'
|
|
policy = ap.AffinityPolicy('test-policy', new_spec)
|
|
nc = mock.Mock()
|
|
nc.validate_azs.return_value = ['NEWAZ']
|
|
policy._novaclient = nc
|
|
ctx = mock.Mock(user='U1', project='P1')
|
|
|
|
res = policy.validate(ctx, True)
|
|
|
|
self.assertTrue(res)
|
|
mock_base_validate.assert_called_once_with(ctx, True)
|
|
nc.validate_azs.assert_called_once_with(['NEWAZ'])
|
|
|
|
@mock.patch.object(pb.Policy, 'validate')
|
|
def test_validate_no_validate_props(self, mock_base_validate):
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
ctx = mock.Mock(user='U1', project='P1')
|
|
|
|
res = policy.validate(ctx, False)
|
|
|
|
self.assertTrue(res)
|
|
mock_base_validate.assert_called_once_with(ctx, False)
|
|
|
|
@mock.patch.object(pb.Policy, 'validate')
|
|
def test_validate_az_not_specified(self, mock_base_validate):
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
nc = mock.Mock()
|
|
policy._novaclient = nc
|
|
ctx = mock.Mock(user='U1', project='P1')
|
|
|
|
res = policy.validate(ctx, True)
|
|
|
|
self.assertTrue(res)
|
|
mock_base_validate.assert_called_once_with(ctx, True)
|
|
self.assertEqual(0, nc.validate_azs.call_count)
|
|
|
|
@mock.patch.object(pb.Policy, 'validate')
|
|
def test_validate_az_not_found(self, mock_base_validate):
|
|
new_spec = copy.deepcopy(self.spec)
|
|
new_spec['properties']['availability_zone'] = 'NEWAZ'
|
|
policy = ap.AffinityPolicy('test-policy', new_spec)
|
|
nc = mock.Mock()
|
|
nc.validate_azs.return_value = [] # this means not found
|
|
policy._novaclient = nc
|
|
ctx = mock.Mock(user='U1', project='P1')
|
|
|
|
ex = self.assertRaises(exc.InvalidSpec,
|
|
policy.validate,
|
|
ctx, True)
|
|
|
|
mock_base_validate.assert_called_once_with(ctx, True)
|
|
nc.validate_azs.assert_called_once_with(['NEWAZ'])
|
|
self.assertEqual("The specified availability_zone 'NEWAZ' could not "
|
|
"be found.", str(ex))
|
|
|
|
def test_attach_using_profile_hints(self):
|
|
x_profile = mock.Mock()
|
|
x_profile.type = 'os.nova.server-1.0'
|
|
x_profile.spec = {
|
|
'scheduler_hints': {
|
|
'group': 'KONGFOO',
|
|
}
|
|
}
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='UU', project='PP',
|
|
rt={'profile': x_profile})
|
|
x_group = mock.Mock(id='GROUP_ID', policies=[u'anti-affinity'])
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_find.return_value = x_group
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
x_data = mock.Mock()
|
|
mock_build = self.patchobject(policy, '_build_policy_data',
|
|
return_value=x_data)
|
|
|
|
# do it
|
|
res, data = policy.attach(cluster)
|
|
|
|
# assertions
|
|
self.assertEqual(x_data, data)
|
|
self.assertTrue(res)
|
|
|
|
mock_nova.assert_called_once_with('UU', 'PP')
|
|
x_nova.server_group_find.assert_called_once_with('KONGFOO', True)
|
|
mock_build.assert_called_once_with({
|
|
'servergroup_id': 'GROUP_ID',
|
|
'inherited_group': True
|
|
})
|
|
|
|
def test_attach_with_group_found(self):
|
|
self.spec['properties']['servergroup']['name'] = 'KONGFU'
|
|
x_profile = mock.Mock()
|
|
x_profile.type = 'os.nova.server-1.0'
|
|
x_profile.spec = {'foo': 'bar'}
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='UU', project='PP',
|
|
rt={'profile': x_profile})
|
|
x_group = mock.Mock(id='GROUP_ID', policies=['anti-affinity'])
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_find.return_value = x_group
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
x_data = mock.Mock()
|
|
mock_build = self.patchobject(policy, '_build_policy_data',
|
|
return_value=x_data)
|
|
|
|
# do it
|
|
res, data = policy.attach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual(x_data, data)
|
|
|
|
mock_nova.assert_called_once_with('UU', 'PP')
|
|
x_nova.server_group_find.assert_called_once_with('KONGFU', True)
|
|
mock_build.assert_called_once_with({
|
|
'servergroup_id': 'GROUP_ID',
|
|
'inherited_group': True
|
|
})
|
|
|
|
def test_attach_with_group_not_found(self):
|
|
self.spec['properties']['servergroup']['name'] = 'KONGFU'
|
|
x_profile = mock.Mock()
|
|
x_profile.spec = {'foo': 'bar'}
|
|
x_profile.type = 'os.nova.server-1.0'
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='USER', project='PROJ',
|
|
rt={'profile': x_profile})
|
|
x_group = mock.Mock(id='GROUP_ID')
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_find.return_value = None
|
|
x_nova.server_group_create.return_value = x_group
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
x_data = mock.Mock()
|
|
mock_build = self.patchobject(policy, '_build_policy_data',
|
|
return_value=x_data)
|
|
|
|
# do it
|
|
res, data = policy.attach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual(x_data, data)
|
|
|
|
mock_nova.assert_called_once_with('USER', 'PROJ')
|
|
x_nova.server_group_find.assert_called_once_with('KONGFU', True)
|
|
x_nova.server_group_create.assert_called_once_with(
|
|
name='KONGFU',
|
|
policies=[policy.ANTI_AFFINITY])
|
|
mock_build.assert_called_once_with({
|
|
'servergroup_id': 'GROUP_ID',
|
|
'inherited_group': False
|
|
})
|
|
|
|
def test_attach_with_group_name_not_provided(self):
|
|
x_profile = mock.Mock()
|
|
x_profile.spec = {'foo': 'bar'}
|
|
x_profile.type = 'os.nova.server-1.0'
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='USER', project='PROJ',
|
|
rt={'profile': x_profile})
|
|
x_group = mock.Mock(id='GROUP_ID')
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_create.return_value = x_group
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
x_data = mock.Mock()
|
|
mock_build = self.patchobject(policy, '_build_policy_data',
|
|
return_value=x_data)
|
|
|
|
# do it
|
|
res, data = policy.attach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual(x_data, data)
|
|
|
|
mock_nova.assert_called_once_with('USER', 'PROJ')
|
|
x_nova.server_group_create.assert_called_once_with(
|
|
name=mock.ANY,
|
|
policies=[policy.ANTI_AFFINITY])
|
|
mock_build.assert_called_once_with({
|
|
'servergroup_id': 'GROUP_ID',
|
|
'inherited_group': False
|
|
})
|
|
|
|
@mock.patch.object(pb.Policy, 'attach')
|
|
def test_attach_failed_base_return_false(self, mock_attach):
|
|
cluster = mock.Mock()
|
|
mock_attach.return_value = (False, 'Something is wrong.')
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
|
|
res, data = policy.attach(cluster)
|
|
|
|
self.assertFalse(res)
|
|
self.assertEqual('Something is wrong.', data)
|
|
|
|
def test_attach_failed_finding(self):
|
|
self.spec['properties']['servergroup']['name'] = 'KONGFU'
|
|
x_profile = mock.Mock()
|
|
x_profile.type = 'os.nova.server-1.0'
|
|
x_profile.spec = {'foo': 'bar'}
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='USER', project='PROJ',
|
|
rt={'profile': x_profile})
|
|
x_nova = mock.Mock()
|
|
err = exc.InternalError(code=500, message='Boom')
|
|
x_nova.server_group_find.side_effect = err
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
|
|
# do it
|
|
res, data = policy.attach(cluster)
|
|
|
|
# assertions
|
|
self.assertFalse(res)
|
|
self.assertEqual("Failed in retrieving servergroup 'KONGFU'.", data)
|
|
|
|
mock_nova.assert_called_once_with('USER', 'PROJ')
|
|
x_nova.server_group_find.assert_called_once_with('KONGFU', True)
|
|
|
|
def test_attach_policies_not_match(self):
|
|
self.spec['properties']['servergroup']['name'] = 'KONGFU'
|
|
x_profile = mock.Mock()
|
|
x_profile.type = 'os.nova.server-1.0'
|
|
x_profile.spec = {'foo': 'bar'}
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='U1', project='P1',
|
|
rt={'profile': x_profile})
|
|
x_group = mock.Mock(id='GROUP_ID', policies=['affinity'])
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_find.return_value = x_group
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
|
|
# do it
|
|
res, data = policy.attach(cluster)
|
|
|
|
# assertions
|
|
self.assertFalse(res)
|
|
self.assertEqual("Policies specified (anti-affinity) doesn't match "
|
|
"that of the existing servergroup (affinity).",
|
|
data)
|
|
|
|
mock_nova.assert_called_once_with('U1', 'P1')
|
|
x_nova.server_group_find.assert_called_once_with('KONGFU', True)
|
|
|
|
def test_attach_failed_creating_server_group(self):
|
|
self.spec['properties']['servergroup']['name'] = 'KONGFU'
|
|
x_profile = mock.Mock()
|
|
x_profile.type = 'os.nova.server-1.0'
|
|
x_profile.spec = {'foo': 'bar'}
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='U1', project='P1',
|
|
rt={'profile': x_profile})
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_find.return_value = None
|
|
x_nova.server_group_create.side_effect = Exception()
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
|
|
# do it
|
|
res, data = policy.attach(cluster)
|
|
|
|
# assertions
|
|
self.assertEqual('Failed in creating servergroup.', data)
|
|
self.assertFalse(res)
|
|
|
|
mock_nova.assert_called_once_with('U1', 'P1')
|
|
x_nova.server_group_find.assert_called_once_with('KONGFU', True)
|
|
x_nova.server_group_create.assert_called_once_with(
|
|
name=mock.ANY,
|
|
policies=[policy.ANTI_AFFINITY])
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
@mock.patch.object(context, 'get_admin_context')
|
|
def test_detach_inherited(self, mock_context, mock_cp):
|
|
cluster = mock.Mock(id='CLUSTER_ID')
|
|
x_ctx = mock.Mock()
|
|
mock_context.return_value = x_ctx
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': True,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
|
|
# do it
|
|
res, data = policy.detach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual('Servergroup resource deletion succeeded.', data)
|
|
|
|
mock_context.assert_called_once_with()
|
|
mock_cp.assert_called_once_with(x_ctx, 'CLUSTER_ID', 'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
@mock.patch.object(context, 'get_admin_context')
|
|
def test_detach_not_inherited(self, mock_context, mock_cp):
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='USER', project='PROJECT')
|
|
x_ctx = mock.Mock()
|
|
mock_context.return_value = x_ctx
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_delete.return_value = None
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
|
|
# do it
|
|
res, data = policy.detach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual('Servergroup resource deletion succeeded.', data)
|
|
|
|
mock_context.assert_called_once_with()
|
|
mock_cp.assert_called_once_with(x_ctx, 'CLUSTER_ID', 'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
mock_nova.assert_called_once_with('USER', 'PROJECT')
|
|
x_nova.server_group_delete.assert_called_once_with('SERVERGROUP_ID')
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
@mock.patch.object(context, 'get_admin_context')
|
|
def test_detach_binding_not_found(self, mock_context, mock_cp):
|
|
cluster = mock.Mock(id='CLUSTER_ID')
|
|
x_ctx = mock.Mock()
|
|
mock_context.return_value = x_ctx
|
|
|
|
mock_cp.return_value = None
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
|
|
# do it
|
|
res, data = policy.detach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual('Servergroup resource deletion succeeded.', data)
|
|
|
|
mock_context.assert_called_once_with()
|
|
mock_cp.assert_called_once_with(x_ctx, 'CLUSTER_ID', 'POLICY_ID')
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
@mock.patch.object(context, 'get_admin_context')
|
|
def test_detach_binding_data_empty(self, mock_context, mock_cp):
|
|
cluster = mock.Mock(id='CLUSTER_ID')
|
|
x_ctx = mock.Mock()
|
|
mock_context.return_value = x_ctx
|
|
x_binding = mock.Mock(data={})
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
|
|
# do it
|
|
res, data = policy.detach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual('Servergroup resource deletion succeeded.', data)
|
|
|
|
mock_context.assert_called_once_with()
|
|
mock_cp.assert_called_once_with(x_ctx, 'CLUSTER_ID', 'POLICY_ID')
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
@mock.patch.object(context, 'get_admin_context')
|
|
def test_detach_policy_data_empty(self, mock_context, mock_cp):
|
|
cluster = mock.Mock(id='CLUSTER_ID')
|
|
x_ctx = mock.Mock()
|
|
mock_context.return_value = x_ctx
|
|
x_binding = mock.Mock(data={'foo': 'bar'})
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=None)
|
|
# do it
|
|
res, data = policy.detach(cluster)
|
|
|
|
# assertions
|
|
self.assertTrue(res)
|
|
self.assertEqual('Servergroup resource deletion succeeded.', data)
|
|
|
|
mock_context.assert_called_once_with()
|
|
mock_cp.assert_called_once_with(x_ctx, 'CLUSTER_ID', 'POLICY_ID')
|
|
mock_extract.assert_called_once_with({'foo': 'bar'})
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
@mock.patch.object(context, 'get_admin_context')
|
|
def test_detach_failing_delete_sg(self, mock_context, mock_cp):
|
|
cluster = mock.Mock(id='CLUSTER_ID', user='USER', project='PROJ')
|
|
x_ctx = mock.Mock()
|
|
mock_context.return_value = x_ctx
|
|
x_binding = mock.Mock(data={'foo': 'bar'})
|
|
mock_cp.return_value = x_binding
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
x_nova = mock.Mock()
|
|
x_nova.server_group_delete.side_effect = Exception()
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
|
|
# do it
|
|
res, data = policy.detach(cluster)
|
|
|
|
# assertions
|
|
self.assertFalse(res)
|
|
self.assertEqual('Failed in deleting servergroup.', data)
|
|
|
|
mock_context.assert_called_once_with()
|
|
mock_cp.assert_called_once_with(x_ctx, 'CLUSTER_ID', 'POLICY_ID')
|
|
mock_extract.assert_called_once_with({'foo': 'bar'})
|
|
mock_nova.assert_called_once_with('USER', 'PROJ')
|
|
x_nova.server_group_delete.assert_called_once_with('SERVERGROUP_ID')
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op(self, mock_cp):
|
|
x_action = mock.Mock()
|
|
x_action.data = {'creation': {'count': 2}}
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_cp.assert_called_once_with(x_action.context, 'CLUSTER_ID',
|
|
'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
self.assertEqual(
|
|
{
|
|
'creation': {
|
|
'count': 2
|
|
},
|
|
'placement': {
|
|
'count': 2,
|
|
'placements': [
|
|
{
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
},
|
|
{
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
x_action.data)
|
|
x_action.store.assert_called_once_with(x_action.context)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op_use_scaleout_input(self, mock_cp):
|
|
x_action = mock.Mock()
|
|
x_action.data = {}
|
|
x_action.action = consts.CLUSTER_SCALE_OUT
|
|
x_action.inputs = {'count': 2}
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_cp.assert_called_once_with(x_action.context, 'CLUSTER_ID',
|
|
'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
self.assertEqual(
|
|
{
|
|
'placement': {
|
|
'count': 2,
|
|
'placements': [
|
|
{
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
},
|
|
{
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
x_action.data)
|
|
x_action.store.assert_called_once_with(x_action.context)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op_for_node_create(self, mock_cp):
|
|
x_action = mock.Mock()
|
|
x_action.data = {}
|
|
x_action.action = consts.NODE_CREATE
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_cp.assert_called_once_with(x_action.context, 'CLUSTER_ID',
|
|
'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
self.assertEqual(
|
|
{
|
|
'placement': {
|
|
'count': 1,
|
|
'placements': [
|
|
{
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
x_action.data)
|
|
x_action.store.assert_called_once_with(x_action.context)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op_use_resize_params(self, mock_cp):
|
|
def fake_parse_func(action, cluster, current):
|
|
action.data = {
|
|
'creation': {
|
|
'count': 2
|
|
}
|
|
}
|
|
|
|
x_action = mock.Mock()
|
|
x_action.data = {}
|
|
x_action.action = consts.CLUSTER_RESIZE
|
|
x_action.inputs = {
|
|
'adjustment_type': consts.EXACT_CAPACITY,
|
|
'number': 4
|
|
}
|
|
x_cluster = mock.Mock()
|
|
x_cluster.nodes = [mock.Mock(), mock.Mock()]
|
|
x_action.entity = x_cluster
|
|
mock_parse = self.patchobject(scaleutils, 'parse_resize_params',
|
|
side_effect=fake_parse_func)
|
|
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_parse.assert_called_once_with(x_action, x_cluster, 2)
|
|
mock_cp.assert_called_once_with(x_action.context, 'CLUSTER_ID',
|
|
'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
self.assertEqual(
|
|
{
|
|
'creation': {
|
|
'count': 2,
|
|
},
|
|
'placement': {
|
|
'count': 2,
|
|
'placements': [
|
|
{
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
},
|
|
{
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
x_action.data)
|
|
x_action.store.assert_called_once_with(x_action.context)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op_resize_shrinking(self, mock_cp):
|
|
def fake_parse_func(action, cluster, current):
|
|
action.data = {
|
|
'deletion': {
|
|
'count': 2
|
|
}
|
|
}
|
|
|
|
x_action = mock.Mock()
|
|
x_action.data = {}
|
|
x_action.action = consts.CLUSTER_RESIZE
|
|
x_action.inputs = {
|
|
'adjustment_type': consts.EXACT_CAPACITY,
|
|
'number': 10
|
|
}
|
|
x_cluster = mock.Mock()
|
|
x_cluster.nodes = [mock.Mock(), mock.Mock()]
|
|
x_action.entity = x_cluster
|
|
mock_parse = self.patchobject(scaleutils, 'parse_resize_params',
|
|
side_effect=fake_parse_func)
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data')
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_parse.assert_called_once_with(x_action, x_cluster, 2)
|
|
self.assertEqual(0, mock_cp.call_count)
|
|
self.assertEqual(0, mock_extract.call_count)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op_with_zone_name(self, mock_cp):
|
|
self.spec['properties']['availability_zone'] = 'BLUE_ZONE'
|
|
x_action = mock.Mock()
|
|
x_action.data = {'creation': {'count': 2}}
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_cp.assert_called_once_with(x_action.context, 'CLUSTER_ID',
|
|
'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
self.assertEqual(
|
|
{
|
|
'creation': {
|
|
'count': 2
|
|
},
|
|
'placement': {
|
|
'count': 2,
|
|
'placements': [
|
|
{
|
|
'zone': 'BLUE_ZONE',
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
},
|
|
{
|
|
'zone': 'BLUE_ZONE',
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
x_action.data)
|
|
x_action.store.assert_called_once_with(x_action.context)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op_with_drs_enabled(self, mock_cp):
|
|
self.spec['properties']['enable_drs_extension'] = True
|
|
x_action = mock.Mock()
|
|
x_action.data = {'creation': {'count': 2}}
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
x_cluster = mock.Mock(user='USER', project='PROJ')
|
|
x_action.entity = x_cluster
|
|
x_nova = mock.Mock()
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
x_hypervisors = [
|
|
mock.Mock(id='HV_1', hypervisor_hostname='host1'),
|
|
mock.Mock(id='HV_2', hypervisor_hostname='vsphere_drs1')
|
|
]
|
|
x_nova.hypervisor_list.return_value = x_hypervisors
|
|
x_hvinfo = {
|
|
'service': {
|
|
'host': 'drshost1'
|
|
}
|
|
}
|
|
x_nova.hypervisor_get.return_value = x_hvinfo
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_cp.assert_called_once_with(x_action.context, 'CLUSTER_ID',
|
|
'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
mock_nova.assert_called_once_with('USER', 'PROJ')
|
|
x_nova.hypervisor_list.assert_called_once_with()
|
|
x_nova.hypervisor_get.assert_called_once_with('HV_2')
|
|
self.assertEqual(
|
|
{
|
|
'creation': {
|
|
'count': 2
|
|
},
|
|
'placement': {
|
|
'count': 2,
|
|
'placements': [
|
|
{
|
|
'zone': 'nova:drshost1',
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
},
|
|
{
|
|
'zone': 'nova:drshost1',
|
|
'servergroup': 'SERVERGROUP_ID'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
x_action.data)
|
|
x_action.store.assert_called_once_with(x_action.context)
|
|
|
|
@mock.patch.object(cpo.ClusterPolicy, 'get')
|
|
def test_pre_op_with_drs_enabled_no_match(self, mock_cp):
|
|
self.spec['properties']['enable_drs_extension'] = True
|
|
x_action = mock.Mock()
|
|
x_action.data = {'creation': {'count': 2}}
|
|
x_binding = mock.Mock()
|
|
mock_cp.return_value = x_binding
|
|
|
|
policy_data = {
|
|
'servergroup_id': 'SERVERGROUP_ID',
|
|
'inherited_group': False,
|
|
}
|
|
policy = ap.AffinityPolicy('test-policy', self.spec)
|
|
policy.id = 'POLICY_ID'
|
|
mock_extract = self.patchobject(policy, '_extract_policy_data',
|
|
return_value=policy_data)
|
|
x_cluster = mock.Mock(user='USER', project='PROJ')
|
|
x_action.entity = x_cluster
|
|
x_nova = mock.Mock()
|
|
mock_nova = self.patchobject(policy, 'nova', return_value=x_nova)
|
|
x_hypervisors = [
|
|
mock.Mock(id='HV_1', hypervisor_hostname='host1'),
|
|
mock.Mock(id='HV_2', hypervisor_hostname='host2')
|
|
]
|
|
x_nova.hypervisor_list.return_value = x_hypervisors
|
|
|
|
# do it
|
|
policy.pre_op('CLUSTER_ID', x_action)
|
|
|
|
mock_cp.assert_called_once_with(x_action.context, 'CLUSTER_ID',
|
|
'POLICY_ID')
|
|
mock_extract.assert_called_once_with(x_binding.data)
|
|
mock_nova.assert_called_once_with('USER', 'PROJ')
|
|
self.assertEqual(
|
|
{
|
|
'creation': {
|
|
'count': 2
|
|
},
|
|
'status': 'ERROR',
|
|
'status_reason': 'No suitable vSphere host is available.'
|
|
},
|
|
x_action.data)
|
|
x_action.store.assert_called_once_with(x_action.context)
|