remove 'health_check' param for scaling actions
this patch remove all 'health_check' in scaling actions, we think the user should run cluster_check to check all physical resources' current status. Change-Id: I8e7af7283578d537935bd4c9bcf1e474d0dfc627
This commit is contained in:
parent
a9844dffea
commit
2e2077de55
@ -428,7 +428,6 @@ Request Parameters
|
|||||||
- cluster_id: cluster_id_url
|
- cluster_id: cluster_id_url
|
||||||
- action: action_request
|
- action: action_request
|
||||||
- count: scale_count
|
- count: scale_count
|
||||||
- health_check: health_check
|
|
||||||
|
|
||||||
|
|
||||||
The ``action_name`` in the request body has to be ``scale_in``.
|
The ``action_name`` in the request body has to be ``scale_in``.
|
||||||
|
@ -740,15 +740,6 @@ events:
|
|||||||
description: |
|
description: |
|
||||||
A list of event objects.
|
A list of event objects.
|
||||||
|
|
||||||
health_check:
|
|
||||||
type: string
|
|
||||||
in: body
|
|
||||||
required: False
|
|
||||||
description: |
|
|
||||||
A boolean parameter indicates whether check physical resource when
|
|
||||||
scaling.
|
|
||||||
min_version: 1.7
|
|
||||||
|
|
||||||
host:
|
host:
|
||||||
type: string
|
type: string
|
||||||
in: body
|
in: body
|
||||||
|
@ -186,13 +186,10 @@ class ClusterController(wsgi.Controller):
|
|||||||
|
|
||||||
def _do_scale_in(self, req, cid, data):
|
def _do_scale_in(self, req, cid, data):
|
||||||
count = data.get('count', None)
|
count = data.get('count', None)
|
||||||
health = data.get('health_check', None)
|
|
||||||
params = {'identity': cid}
|
params = {'identity': cid}
|
||||||
|
|
||||||
if count is not None:
|
if count is not None:
|
||||||
params['count'] = count
|
params['count'] = count
|
||||||
if health is not None:
|
|
||||||
params['health_check'] = health
|
|
||||||
|
|
||||||
obj = util.parse_request('ClusterScaleInRequest', req, params)
|
obj = util.parse_request('ClusterScaleInRequest', req, params)
|
||||||
return self.rpc_client.call(req.context, 'cluster_scale_in', obj)
|
return self.rpc_client.call(req.context, 'cluster_scale_in', obj)
|
||||||
|
@ -801,31 +801,6 @@ class ClusterAction(base.Action):
|
|||||||
|
|
||||||
return result, reason
|
return result, reason
|
||||||
|
|
||||||
def _check_nodes(self):
|
|
||||||
|
|
||||||
child = []
|
|
||||||
res = self.RES_OK
|
|
||||||
reason = _('Nodes status checking completed.')
|
|
||||||
for node in self.entity.nodes:
|
|
||||||
node_id = node.id
|
|
||||||
action_id = base.Action.create(
|
|
||||||
self.context, node_id, consts.NODE_CHECK,
|
|
||||||
name='node_check_%s' % node_id[:8],
|
|
||||||
cause=consts.CAUSE_DERIVED
|
|
||||||
)
|
|
||||||
child.append(action_id)
|
|
||||||
|
|
||||||
if child:
|
|
||||||
dobj.Dependency.create(self.context, [c for c in child], self.id)
|
|
||||||
for cid in child:
|
|
||||||
ao.Action.update(self.context, cid,
|
|
||||||
{'status': base.Action.READY})
|
|
||||||
dispatcher.start_action()
|
|
||||||
|
|
||||||
res, reason = self._wait_for_dependents()
|
|
||||||
|
|
||||||
return res, reason
|
|
||||||
|
|
||||||
@profiler.trace('ClusterAction.do_scale_in', hide_args=False)
|
@profiler.trace('ClusterAction.do_scale_in', hide_args=False)
|
||||||
def do_scale_in(self):
|
def do_scale_in(self):
|
||||||
"""Handler for the CLUSTER_SCALE_IN action.
|
"""Handler for the CLUSTER_SCALE_IN action.
|
||||||
@ -841,11 +816,9 @@ class ClusterAction(base.Action):
|
|||||||
candidates = pd.get('candidates', [])
|
candidates = pd.get('candidates', [])
|
||||||
# if scaling policy is attached, get 'count' from action data
|
# if scaling policy is attached, get 'count' from action data
|
||||||
count = len(candidates) or pd['count']
|
count = len(candidates) or pd['count']
|
||||||
health_check = pd.get('health_check', False)
|
|
||||||
else:
|
else:
|
||||||
# If no scaling policy is attached, use the input count directly
|
# If no scaling policy is attached, use the input count directly
|
||||||
candidates = []
|
candidates = []
|
||||||
health_check = self.inputs.get('health_check', False)
|
|
||||||
value = self.inputs.get('count', 1)
|
value = self.inputs.get('count', 1)
|
||||||
success, count = utils.get_positive_int(value)
|
success, count = utils.get_positive_int(value)
|
||||||
if not success:
|
if not success:
|
||||||
@ -871,14 +844,6 @@ class ClusterAction(base.Action):
|
|||||||
_('Cluster scale in started.'),
|
_('Cluster scale in started.'),
|
||||||
desired_capacity=new_size)
|
desired_capacity=new_size)
|
||||||
|
|
||||||
# check nodes' current status if health_check set to True
|
|
||||||
if health_check is True:
|
|
||||||
# do we need to care about the result
|
|
||||||
result, reason = self._check_nodes()
|
|
||||||
if result == self.RES_OK:
|
|
||||||
nodes = no.Node.get_all_by_cluster(self.context, self.target)
|
|
||||||
self.entity.update_node(nodes)
|
|
||||||
|
|
||||||
# Choose victims randomly
|
# Choose victims randomly
|
||||||
if len(candidates) == 0:
|
if len(candidates) == 0:
|
||||||
candidates = scaleutils.nodes_by_random(self.entity.nodes, count)
|
candidates = scaleutils.nodes_by_random(self.entity.nodes, count)
|
||||||
|
@ -1332,9 +1332,6 @@ class EngineService(service.Service):
|
|||||||
LOG.info('Scaling in cluster %s', db_cluster.name)
|
LOG.info('Scaling in cluster %s', db_cluster.name)
|
||||||
inputs = {}
|
inputs = {}
|
||||||
|
|
||||||
req.obj_set_defaults()
|
|
||||||
inputs['health_check'] = req.health_check
|
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
'name': 'cluster_scale_in_%s' % db_cluster.id[:8],
|
'name': 'cluster_scale_in_%s' % db_cluster.id[:8],
|
||||||
'cause': consts.CAUSE_RPC,
|
'cause': consts.CAUSE_RPC,
|
||||||
|
@ -169,13 +169,6 @@ class ClusterReplaceNodesRequest(base.SenlinObject):
|
|||||||
@base.SenlinObjectRegistry.register
|
@base.SenlinObjectRegistry.register
|
||||||
class ClusterResizeRequest(base.SenlinObject):
|
class ClusterResizeRequest(base.SenlinObject):
|
||||||
|
|
||||||
# VERSION 1.0: initial version
|
|
||||||
# VERSION 1.1: added field 'health_check'
|
|
||||||
VERSION = '1.1'
|
|
||||||
VERSION_MAP = {
|
|
||||||
'1.7': '1.1',
|
|
||||||
}
|
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'identity': fields.StringField(),
|
'identity': fields.StringField(),
|
||||||
'adjustment_type': fields.AdjustmentTypeField(nullable=True),
|
'adjustment_type': fields.AdjustmentTypeField(nullable=True),
|
||||||
@ -184,67 +177,27 @@ class ClusterResizeRequest(base.SenlinObject):
|
|||||||
'max_size': fields.CapacityField(nullable=True, minimum=-1),
|
'max_size': fields.CapacityField(nullable=True, minimum=-1),
|
||||||
'min_step': fields.NonNegativeIntegerField(nullable=True),
|
'min_step': fields.NonNegativeIntegerField(nullable=True),
|
||||||
'strict': fields.BooleanField(nullable=True, default=True),
|
'strict': fields.BooleanField(nullable=True, default=True),
|
||||||
'health_check': fields.BooleanField(nullable=True, default=False)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def obj_make_compatible(self, primitive, target_version):
|
|
||||||
super(ClusterResizeRequest, self).obj_make_compatible(
|
|
||||||
primitive, target_version)
|
|
||||||
target_version = versionutils.convert_version_to_tuple(target_version)
|
|
||||||
if target_version < (1, 1):
|
|
||||||
if 'health_check' in primitive['senlin_object.data']:
|
|
||||||
del primitive['senlin_object.data']['health_check']
|
|
||||||
|
|
||||||
|
|
||||||
@base.SenlinObjectRegistry.register
|
@base.SenlinObjectRegistry.register
|
||||||
class ClusterScaleInRequest(base.SenlinObject):
|
class ClusterScaleInRequest(base.SenlinObject):
|
||||||
|
|
||||||
# VERSION 1.0: initial version
|
|
||||||
# VERSION 1.1: added field 'health_check'
|
|
||||||
VERSION = '1.1'
|
|
||||||
VERSION_MAP = {
|
|
||||||
'1.7': '1.1',
|
|
||||||
}
|
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'identity': fields.StringField(),
|
'identity': fields.StringField(),
|
||||||
'count': fields.NonNegativeIntegerField(nullable=True),
|
'count': fields.NonNegativeIntegerField(nullable=True),
|
||||||
'health_check': fields.BooleanField(nullable=True, default=False)
|
'health_check': fields.BooleanField(nullable=True, default=False)
|
||||||
}
|
}
|
||||||
|
|
||||||
def obj_make_compatible(self, primitive, target_version):
|
|
||||||
super(ClusterScaleInRequest, self).obj_make_compatible(
|
|
||||||
primitive, target_version)
|
|
||||||
target_version = versionutils.convert_version_to_tuple(target_version)
|
|
||||||
if target_version < (1, 1):
|
|
||||||
if 'health_check' in primitive['senlin_object.data']:
|
|
||||||
del primitive['senlin_object.data']['health_check']
|
|
||||||
|
|
||||||
|
|
||||||
@base.SenlinObjectRegistry.register
|
@base.SenlinObjectRegistry.register
|
||||||
class ClusterScaleOutRequest(base.SenlinObject):
|
class ClusterScaleOutRequest(base.SenlinObject):
|
||||||
|
|
||||||
# VERSION 1.0: initial version
|
|
||||||
# VERSION 1.1: added field 'health_check'
|
|
||||||
VERSION = '1.1'
|
|
||||||
VERSION_MAP = {
|
|
||||||
'1.7': '1.1',
|
|
||||||
}
|
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'identity': fields.StringField(),
|
'identity': fields.StringField(),
|
||||||
'count': fields.NonNegativeIntegerField(nullable=True),
|
'count': fields.NonNegativeIntegerField(nullable=True),
|
||||||
'health_check': fields.BooleanField(nullable=True, default=False)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def obj_make_compatible(self, primitive, target_version):
|
|
||||||
super(ClusterScaleOutRequest, self).obj_make_compatible(
|
|
||||||
primitive, target_version)
|
|
||||||
target_version = versionutils.convert_version_to_tuple(target_version)
|
|
||||||
if target_version < (1, 1):
|
|
||||||
if 'health_check' in primitive['senlin_object.data']:
|
|
||||||
del primitive['senlin_object.data']['health_check']
|
|
||||||
|
|
||||||
|
|
||||||
@base.SenlinObjectRegistry.register
|
@base.SenlinObjectRegistry.register
|
||||||
class ClusterAttachPolicyRequest(base.SenlinObject):
|
class ClusterAttachPolicyRequest(base.SenlinObject):
|
||||||
|
@ -31,8 +31,7 @@ class TestClusterActionScaleIn(base.BaseSenlinAPITest):
|
|||||||
def test_cluster_action_scale_in(self):
|
def test_cluster_action_scale_in(self):
|
||||||
params = {
|
params = {
|
||||||
"scale_in": {
|
"scale_in": {
|
||||||
"count": "1",
|
"count": "1"
|
||||||
"health_check": False
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Trigger cluster action
|
# Trigger cluster action
|
||||||
@ -67,25 +66,6 @@ class TestClusterScaleInInvalidRequest(base.BaseSenlinAPITest):
|
|||||||
"The value for count must be an integer: 'bad-count'.",
|
"The value for count must be an integer: 'bad-count'.",
|
||||||
str(message))
|
str(message))
|
||||||
|
|
||||||
@decorators.idempotent_id('ee7be9d4-7c9b-4054-9ca1-45e5284972ad')
|
|
||||||
def test_cluster_scale_in_invalid_health_check(self):
|
|
||||||
params = {
|
|
||||||
"scale_in": {
|
|
||||||
"health_check": "bad-health"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Verify badrequest exception(400) is raised.
|
|
||||||
ex = self.assertRaises(exceptions.BadRequest,
|
|
||||||
self.client.trigger_action,
|
|
||||||
'clusters', 'fake', params)
|
|
||||||
|
|
||||||
message = ex.resp_body['error']['message']
|
|
||||||
self.assertEqual(
|
|
||||||
"Unrecognized value 'bad-health', acceptable values are: '0',"
|
|
||||||
" '1', 'f', 'false', 'n', 'no', 'off', 'on', 't', 'true',"
|
|
||||||
" 'y', 'yes'", str(message))
|
|
||||||
|
|
||||||
|
|
||||||
class TestClusterScaleInNegativeBadRequest(base.BaseSenlinAPITest):
|
class TestClusterScaleInNegativeBadRequest(base.BaseSenlinAPITest):
|
||||||
|
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from senlin.common import consts
|
|
||||||
from senlin.engine.actions import base as ab
|
|
||||||
from senlin.engine.actions import cluster_action as ca
|
|
||||||
from senlin.engine import cluster as cm
|
|
||||||
from senlin.engine import dispatcher
|
|
||||||
from senlin.objects import action as ao
|
|
||||||
from senlin.objects import dependency as dobj
|
|
||||||
from senlin.tests.unit.common import base
|
|
||||||
from senlin.tests.unit.common import utils
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch.object(cm.Cluster, 'load')
|
|
||||||
class ClusterCheckNodesTest(base.SenlinTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(ClusterCheckNodesTest, self).setUp()
|
|
||||||
self.ctx = utils.dummy_context()
|
|
||||||
|
|
||||||
@mock.patch.object(ao.Action, 'update')
|
|
||||||
@mock.patch.object(ab.Action, 'create')
|
|
||||||
@mock.patch.object(dobj.Dependency, 'create')
|
|
||||||
@mock.patch.object(dispatcher, 'start_action')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_wait_for_dependents')
|
|
||||||
def test__check_nodes(self, mock_wait, mock_start, mock_dep,
|
|
||||||
mock_action, mock_update, mock_load):
|
|
||||||
node1 = mock.Mock(id='NODE_1')
|
|
||||||
node2 = mock.Mock(id='NODE_2')
|
|
||||||
cluster = mock.Mock(id='FAKE_ID', status='old status',
|
|
||||||
status_reason='old reason')
|
|
||||||
cluster.nodes = [node1, node2]
|
|
||||||
mock_load.return_value = cluster
|
|
||||||
mock_action.side_effect = ['NODE_ACTION_1', 'NODE_ACTION_2']
|
|
||||||
|
|
||||||
action = ca.ClusterAction('FAKE_CLUSTER', 'CLUSTER_CHECK', self.ctx)
|
|
||||||
action.id = 'CLUSTER_ACTION_ID'
|
|
||||||
|
|
||||||
mock_wait.return_value = (action.RES_OK, 'Everything is Okay')
|
|
||||||
|
|
||||||
# do it
|
|
||||||
res_code, res_msg = action._check_nodes()
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
self.assertEqual(action.RES_OK, res_code)
|
|
||||||
self.assertEqual('Everything is Okay', res_msg)
|
|
||||||
|
|
||||||
mock_load.assert_called_once_with(action.context, 'FAKE_CLUSTER')
|
|
||||||
mock_action.assert_has_calls([
|
|
||||||
mock.call(action.context, 'NODE_1', 'NODE_CHECK',
|
|
||||||
name='node_check_NODE_1',
|
|
||||||
cause=consts.CAUSE_DERIVED),
|
|
||||||
mock.call(action.context, 'NODE_2', 'NODE_CHECK',
|
|
||||||
name='node_check_NODE_2',
|
|
||||||
cause=consts.CAUSE_DERIVED)
|
|
||||||
])
|
|
||||||
mock_dep.assert_called_once_with(action.context,
|
|
||||||
['NODE_ACTION_1', 'NODE_ACTION_2'],
|
|
||||||
'CLUSTER_ACTION_ID')
|
|
||||||
mock_update.assert_has_calls([
|
|
||||||
mock.call(action.context, 'NODE_ACTION_1', {'status': 'READY'}),
|
|
||||||
mock.call(action.context, 'NODE_ACTION_2', {'status': 'READY'}),
|
|
||||||
])
|
|
||||||
mock_start.assert_called_once_with()
|
|
||||||
mock_wait.assert_called_once_with()
|
|
||||||
|
|
||||||
def test__check_nodes_empty(self, mock_load):
|
|
||||||
cluster = mock.Mock(id='FAKE_ID', nodes=[], status='old status',
|
|
||||||
status_reason='old reason')
|
|
||||||
mock_load.return_value = cluster
|
|
||||||
|
|
||||||
action = ca.ClusterAction(cluster.id, 'CLUSTER_CHECK', self.ctx)
|
|
||||||
|
|
||||||
# do it
|
|
||||||
res_code, res_msg = action._check_nodes()
|
|
||||||
|
|
||||||
self.assertEqual(action.RES_OK, res_code)
|
|
||||||
self.assertEqual('Nodes status checking completed.', res_msg)
|
|
||||||
|
|
||||||
@mock.patch.object(ao.Action, 'update')
|
|
||||||
@mock.patch.object(ab.Action, 'create')
|
|
||||||
@mock.patch.object(dobj.Dependency, 'create')
|
|
||||||
@mock.patch.object(dispatcher, 'start_action')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_wait_for_dependents')
|
|
||||||
def test__check_nodes_failed_waiting(self, mock_wait, mock_start,
|
|
||||||
mock_dep, mock_action, mock_update,
|
|
||||||
mock_load):
|
|
||||||
node = mock.Mock(id='NODE_1')
|
|
||||||
cluster = mock.Mock(id='CLUSTER_ID', status='old status',
|
|
||||||
status_reason='old reason')
|
|
||||||
cluster.nodes = [node]
|
|
||||||
mock_load.return_value = cluster
|
|
||||||
mock_action.return_value = 'NODE_ACTION_ID'
|
|
||||||
|
|
||||||
action = ca.ClusterAction('FAKE_CLUSTER', 'CLUSTER_CHECK', self.ctx)
|
|
||||||
action.id = 'CLUSTER_ACTION_ID'
|
|
||||||
|
|
||||||
mock_wait.return_value = (action.RES_TIMEOUT, 'Timeout!')
|
|
||||||
|
|
||||||
res_code, res_msg = action._check_nodes()
|
|
||||||
|
|
||||||
self.assertEqual(action.RES_TIMEOUT, res_code)
|
|
||||||
self.assertEqual('Timeout!', res_msg)
|
|
||||||
|
|
||||||
mock_load.assert_called_once_with(self.ctx, 'FAKE_CLUSTER')
|
|
||||||
mock_action.assert_called_once_with(
|
|
||||||
action.context, 'NODE_1', 'NODE_CHECK',
|
|
||||||
name='node_check_NODE_1',
|
|
||||||
cause=consts.CAUSE_DERIVED,
|
|
||||||
)
|
|
||||||
mock_dep.assert_called_once_with(action.context, ['NODE_ACTION_ID'],
|
|
||||||
'CLUSTER_ACTION_ID')
|
|
||||||
mock_update.assert_called_once_with(action.context, 'NODE_ACTION_ID',
|
|
||||||
{'status': 'READY'})
|
|
||||||
mock_start.assert_called_once_with()
|
|
||||||
mock_wait.assert_called_once_with()
|
|
@ -29,15 +29,14 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
self.ctx = utils.dummy_context()
|
self.ctx = utils.dummy_context()
|
||||||
|
|
||||||
@mock.patch.object(scaleutils, 'nodes_by_random')
|
@mock.patch.object(scaleutils, 'nodes_by_random')
|
||||||
@mock.patch.object(ca.ClusterAction, '_check_nodes')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
||||||
@mock.patch.object(no.Node, 'count_by_cluster')
|
@mock.patch.object(no.Node, 'count_by_cluster')
|
||||||
def test_do_scale_in_no_pd_no_count(self, mock_count, mock_delete,
|
def test_do_scale_in_no_pd_no_count(self, mock_count, mock_delete,
|
||||||
mock_check, mock_select, mock_load):
|
mock_select, mock_load):
|
||||||
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
||||||
mock_load.return_value = cluster
|
mock_load.return_value = cluster
|
||||||
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx,
|
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx,
|
||||||
data={}, inputs={'health_check': False})
|
data={}, inputs={})
|
||||||
mock_count.return_value = 10
|
mock_count.return_value = 10
|
||||||
mock_delete.return_value = (action.RES_OK, 'Life is beautiful.')
|
mock_delete.return_value = (action.RES_OK, 'Life is beautiful.')
|
||||||
|
|
||||||
@ -49,7 +48,6 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
self.assertEqual('Cluster scaling succeeded.', res_msg)
|
self.assertEqual('Cluster scaling succeeded.', res_msg)
|
||||||
|
|
||||||
# deleting 1 nodes
|
# deleting 1 nodes
|
||||||
self.assertFalse(mock_check.called)
|
|
||||||
mock_count.assert_called_once_with(action.context, 'CID')
|
mock_count.assert_called_once_with(action.context, 'CID')
|
||||||
mock_delete.assert_called_once_with(mock.ANY)
|
mock_delete.assert_called_once_with(mock.ANY)
|
||||||
mock_select.assert_called_once_with(cluster.nodes, 1)
|
mock_select.assert_called_once_with(cluster.nodes, 1)
|
||||||
@ -59,12 +57,11 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
cluster.eval_status.assert_called_once_with(
|
cluster.eval_status.assert_called_once_with(
|
||||||
action.context, consts.CLUSTER_SCALE_IN)
|
action.context, consts.CLUSTER_SCALE_IN)
|
||||||
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_check_nodes')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_sleep')
|
@mock.patch.object(ca.ClusterAction, '_sleep')
|
||||||
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
||||||
@mock.patch.object(no.Node, 'count_by_cluster')
|
@mock.patch.object(no.Node, 'count_by_cluster')
|
||||||
def test_do_scale_in_with_pd_no_input(self, mock_count, mock_delete,
|
def test_do_scale_in_with_pd_no_input(self, mock_count, mock_delete,
|
||||||
mock_sleep, mock_check, mock_load):
|
mock_sleep, mock_load):
|
||||||
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
||||||
mock_load.return_value = cluster
|
mock_load.return_value = cluster
|
||||||
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx)
|
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx)
|
||||||
@ -73,7 +70,6 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
'count': 2,
|
'count': 2,
|
||||||
'grace_period': 2,
|
'grace_period': 2,
|
||||||
'candidates': ['NODE_ID_3', 'NODE_ID_4'],
|
'candidates': ['NODE_ID_3', 'NODE_ID_4'],
|
||||||
'health_check': False
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
action.inputs = {}
|
action.inputs = {}
|
||||||
@ -93,8 +89,6 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
self.assertEqual(2, len(mock_delete.call_args[0][0]))
|
self.assertEqual(2, len(mock_delete.call_args[0][0]))
|
||||||
self.assertIn('NODE_ID_3', mock_delete.call_args[0][0])
|
self.assertIn('NODE_ID_3', mock_delete.call_args[0][0])
|
||||||
self.assertIn('NODE_ID_4', mock_delete.call_args[0][0])
|
self.assertIn('NODE_ID_4', mock_delete.call_args[0][0])
|
||||||
self.assertFalse(mock_check.called)
|
|
||||||
self.assertFalse(cluster.update_node.called)
|
|
||||||
cluster.set_status.assert_called_once_with(
|
cluster.set_status.assert_called_once_with(
|
||||||
action.context, consts.CS_RESIZING, 'Cluster scale in started.',
|
action.context, consts.CS_RESIZING, 'Cluster scale in started.',
|
||||||
desired_capacity=3)
|
desired_capacity=3)
|
||||||
@ -103,16 +97,14 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
mock_sleep.assert_called_once_with(2)
|
mock_sleep.assert_called_once_with(2)
|
||||||
|
|
||||||
@mock.patch.object(scaleutils, 'nodes_by_random')
|
@mock.patch.object(scaleutils, 'nodes_by_random')
|
||||||
@mock.patch.object(ca.ClusterAction, '_check_nodes')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
||||||
@mock.patch.object(no.Node, 'count_by_cluster')
|
@mock.patch.object(no.Node, 'count_by_cluster')
|
||||||
def test_do_scale_in_no_pd_with_input(self, mock_count, mock_delete,
|
def test_do_scale_in_no_pd_with_input(self, mock_count, mock_delete,
|
||||||
mock_check, mock_select, mock_load):
|
mock_select, mock_load):
|
||||||
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
||||||
mock_load.return_value = cluster
|
mock_load.return_value = cluster
|
||||||
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx,
|
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx,
|
||||||
data={}, inputs={'count': 3,
|
data={}, inputs={'count': 3})
|
||||||
'health_check': False})
|
|
||||||
mock_count.return_value = 11
|
mock_count.return_value = 11
|
||||||
mock_delete.return_value = (action.RES_OK, 'Life is beautiful.')
|
mock_delete.return_value = (action.RES_OK, 'Life is beautiful.')
|
||||||
|
|
||||||
@ -124,8 +116,6 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
self.assertEqual('Cluster scaling succeeded.', res_msg)
|
self.assertEqual('Cluster scaling succeeded.', res_msg)
|
||||||
|
|
||||||
# deleting 3 nodes
|
# deleting 3 nodes
|
||||||
self.assertFalse(mock_check.called)
|
|
||||||
self.assertFalse(cluster.update_node.called)
|
|
||||||
mock_count.assert_called_once_with(action.context, 'CID')
|
mock_count.assert_called_once_with(action.context, 'CID')
|
||||||
mock_delete.assert_called_once_with(mock.ANY)
|
mock_delete.assert_called_once_with(mock.ANY)
|
||||||
mock_select.assert_called_once_with(cluster.nodes, 3)
|
mock_select.assert_called_once_with(cluster.nodes, 3)
|
||||||
@ -135,88 +125,6 @@ class ClusterScaleInTest(base.SenlinTestCase):
|
|||||||
cluster.eval_status.assert_called_once_with(
|
cluster.eval_status.assert_called_once_with(
|
||||||
action.context, consts.CLUSTER_SCALE_IN)
|
action.context, consts.CLUSTER_SCALE_IN)
|
||||||
|
|
||||||
@mock.patch.object(scaleutils, 'nodes_by_random')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_check_nodes')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
|
||||||
@mock.patch.object(no.Node, 'count_by_cluster')
|
|
||||||
@mock.patch.object(no.Node, 'get_all_by_cluster')
|
|
||||||
def test_do_scale_in_health_check(self, mock_get, mock_count, mock_delete,
|
|
||||||
mock_check, mock_select, mock_load):
|
|
||||||
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
|
||||||
mock_load.return_value = cluster
|
|
||||||
node1 = mock.Mock(id='fake1')
|
|
||||||
node2 = mock.Mock(id='fake2')
|
|
||||||
node3 = mock.Mock(id='fake3')
|
|
||||||
cluster.nodes = [node1, node2, node3]
|
|
||||||
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx,
|
|
||||||
data={}, inputs={'count': 3,
|
|
||||||
'health_check': True})
|
|
||||||
mock_count.return_value = 11
|
|
||||||
mock_delete.return_value = (action.RES_OK, 'Life is beautiful.')
|
|
||||||
mock_check.return_value = (action.RES_OK, 'checking completed.')
|
|
||||||
mock_get.return_value = [node1, node2, node3]
|
|
||||||
|
|
||||||
# do it
|
|
||||||
res_code, res_msg = action.do_scale_in()
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
self.assertEqual(action.RES_OK, res_code)
|
|
||||||
self.assertEqual('Cluster scaling succeeded.', res_msg)
|
|
||||||
|
|
||||||
# deleting 3 nodes
|
|
||||||
mock_get.assert_called_once_with(action.context, 'CID')
|
|
||||||
mock_count.assert_called_once_with(action.context, 'CID')
|
|
||||||
mock_delete.assert_called_once_with(mock.ANY)
|
|
||||||
mock_select.assert_called_once_with(cluster.nodes, 3)
|
|
||||||
mock_check.assert_called_once_with()
|
|
||||||
cluster.update_node.assert_called_once_with([node1, node2, node3])
|
|
||||||
cluster.set_status.assert_called_once_with(
|
|
||||||
action.context, consts.CS_RESIZING, 'Cluster scale in started.',
|
|
||||||
desired_capacity=8)
|
|
||||||
cluster.eval_status.assert_called_once_with(
|
|
||||||
action.context, consts.CLUSTER_SCALE_IN)
|
|
||||||
|
|
||||||
@mock.patch.object(scaleutils, 'nodes_by_random')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_check_nodes')
|
|
||||||
@mock.patch.object(ca.ClusterAction, '_delete_nodes')
|
|
||||||
@mock.patch.object(no.Node, 'count_by_cluster')
|
|
||||||
@mock.patch.object(no.Node, 'get_all_by_cluster')
|
|
||||||
def test_do_scale_in_health_check_failed(self, mock_get, mock_count,
|
|
||||||
mock_delete, mock_check,
|
|
||||||
mock_select, mock_load):
|
|
||||||
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
|
||||||
mock_load.return_value = cluster
|
|
||||||
node1 = mock.Mock(id='fake1')
|
|
||||||
node2 = mock.Mock(id='fake2')
|
|
||||||
node3 = mock.Mock(id='fake3')
|
|
||||||
cluster.nodes = [node1, node2, node3]
|
|
||||||
action = ca.ClusterAction(cluster.id, 'CLUSTER_ACTION', self.ctx,
|
|
||||||
data={}, inputs={'count': 3,
|
|
||||||
'health_check': True})
|
|
||||||
mock_count.return_value = 11
|
|
||||||
mock_delete.return_value = (action.RES_OK, 'Life is beautiful.')
|
|
||||||
mock_check.return_value = (action.RES_ERROR, 'boom!')
|
|
||||||
|
|
||||||
# do it
|
|
||||||
res_code, res_msg = action.do_scale_in()
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
self.assertEqual(action.RES_OK, res_code)
|
|
||||||
self.assertEqual('Cluster scaling succeeded.', res_msg)
|
|
||||||
|
|
||||||
# deleting 3 nodes
|
|
||||||
self.assertFalse(mock_get.called)
|
|
||||||
self.assertFalse(cluster.update_node.called)
|
|
||||||
mock_count.assert_called_once_with(action.context, 'CID')
|
|
||||||
mock_delete.assert_called_once_with(mock.ANY)
|
|
||||||
mock_select.assert_called_once_with(cluster.nodes, 3)
|
|
||||||
mock_check.assert_called_once_with()
|
|
||||||
cluster.set_status.assert_called_once_with(
|
|
||||||
action.context, consts.CS_RESIZING, 'Cluster scale in started.',
|
|
||||||
desired_capacity=8)
|
|
||||||
cluster.eval_status.assert_called_once_with(
|
|
||||||
action.context, consts.CLUSTER_SCALE_IN)
|
|
||||||
|
|
||||||
def test_do_scale_in_negative_count(self, mock_load):
|
def test_do_scale_in_negative_count(self, mock_load):
|
||||||
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
cluster = mock.Mock(id='CID', min_size=1, max_size=-1)
|
||||||
mock_load.return_value = cluster
|
mock_load.return_value = cluster
|
||||||
|
@ -1304,34 +1304,7 @@ class ClusterTest(base.SenlinTestCase):
|
|||||||
name='cluster_scale_in_12345678',
|
name='cluster_scale_in_12345678',
|
||||||
cause=consts.CAUSE_RPC,
|
cause=consts.CAUSE_RPC,
|
||||||
status=am.Action.READY,
|
status=am.Action.READY,
|
||||||
inputs={'count': 2, 'health_check': False},
|
inputs={'count': 2},
|
||||||
)
|
|
||||||
notify.assert_called_once_with()
|
|
||||||
|
|
||||||
@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_full(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, health_check=True)
|
|
||||||
|
|
||||||
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, 'health_check': True},
|
|
||||||
)
|
)
|
||||||
notify.assert_called_once_with()
|
notify.assert_called_once_with()
|
||||||
|
|
||||||
@ -1368,7 +1341,7 @@ class ClusterTest(base.SenlinTestCase):
|
|||||||
name='cluster_scale_in_FOO',
|
name='cluster_scale_in_FOO',
|
||||||
cause=consts.CAUSE_RPC,
|
cause=consts.CAUSE_RPC,
|
||||||
status=am.Action.READY,
|
status=am.Action.READY,
|
||||||
inputs={'health_check': False},
|
inputs={},
|
||||||
)
|
)
|
||||||
notify.assert_called_once_with()
|
notify.assert_called_once_with()
|
||||||
|
|
||||||
|
@ -333,7 +333,6 @@ class TestClusterResize(test_base.SenlinTestCase):
|
|||||||
self.assertFalse(sot.obj_attr_is_set('max_size'))
|
self.assertFalse(sot.obj_attr_is_set('max_size'))
|
||||||
self.assertFalse(sot.obj_attr_is_set('min_step'))
|
self.assertFalse(sot.obj_attr_is_set('min_step'))
|
||||||
self.assertFalse(sot.obj_attr_is_set('strict'))
|
self.assertFalse(sot.obj_attr_is_set('strict'))
|
||||||
self.assertFalse(sot.obj_attr_is_set('health_check'))
|
|
||||||
|
|
||||||
def test_init_with_params(self):
|
def test_init_with_params(self):
|
||||||
sot = clusters.ClusterResizeRequest(identity='foo',
|
sot = clusters.ClusterResizeRequest(identity='foo',
|
||||||
@ -352,9 +351,6 @@ class TestClusterResize(test_base.SenlinTestCase):
|
|||||||
self.assertEqual(1, sot.min_step)
|
self.assertEqual(1, sot.min_step)
|
||||||
self.assertFalse(sot.strict)
|
self.assertFalse(sot.strict)
|
||||||
|
|
||||||
sot.obj_set_defaults()
|
|
||||||
self.assertFalse(sot.health_check)
|
|
||||||
|
|
||||||
def test_init_failed_type(self):
|
def test_init_failed_type(self):
|
||||||
ex = self.assertRaises(ValueError,
|
ex = self.assertRaises(ValueError,
|
||||||
clusters.ClusterResizeRequest,
|
clusters.ClusterResizeRequest,
|
||||||
@ -398,15 +394,6 @@ class TestClusterResize(test_base.SenlinTestCase):
|
|||||||
identity='foo', strict='fake')
|
identity='foo', strict='fake')
|
||||||
self.assertIn("Unrecognized value 'fake'", six.text_type(ex))
|
self.assertIn("Unrecognized value 'fake'", six.text_type(ex))
|
||||||
|
|
||||||
def test_init_invalid_boolean(self):
|
|
||||||
ex = self.assertRaises(ValueError,
|
|
||||||
clusters.ClusterResizeRequest,
|
|
||||||
identity='foo', health_check="foo")
|
|
||||||
self.assertEqual(
|
|
||||||
"Unrecognized value 'foo', acceptable values are: '0', '1', "
|
|
||||||
"'f', 'false', 'n', 'no', 'off', 'on', 't', 'true', 'y', 'yes'",
|
|
||||||
six.text_type(ex))
|
|
||||||
|
|
||||||
|
|
||||||
class TestClusterScaleIn(test_base.SenlinTestCase):
|
class TestClusterScaleIn(test_base.SenlinTestCase):
|
||||||
|
|
||||||
@ -416,9 +403,6 @@ class TestClusterScaleIn(test_base.SenlinTestCase):
|
|||||||
self.assertEqual('foo', sot.identity)
|
self.assertEqual('foo', sot.identity)
|
||||||
self.assertEqual(5, sot.count)
|
self.assertEqual(5, sot.count)
|
||||||
|
|
||||||
sot.obj_set_defaults()
|
|
||||||
self.assertFalse(sot.health_check)
|
|
||||||
|
|
||||||
def test_init_failed(self):
|
def test_init_failed(self):
|
||||||
ex = self.assertRaises(ValueError,
|
ex = self.assertRaises(ValueError,
|
||||||
clusters.ClusterScaleInRequest,
|
clusters.ClusterScaleInRequest,
|
||||||
@ -426,15 +410,6 @@ class TestClusterScaleIn(test_base.SenlinTestCase):
|
|||||||
self.assertEqual("Value must be >= 0 for field 'count'.",
|
self.assertEqual("Value must be >= 0 for field 'count'.",
|
||||||
six.text_type(ex))
|
six.text_type(ex))
|
||||||
|
|
||||||
def test_init_invalid_boolean(self):
|
|
||||||
ex = self.assertRaises(ValueError,
|
|
||||||
clusters.ClusterScaleInRequest,
|
|
||||||
identity='foo', count=1, health_check="foo")
|
|
||||||
self.assertEqual(
|
|
||||||
"Unrecognized value 'foo', acceptable values are: '0', '1', "
|
|
||||||
"'f', 'false', 'n', 'no', 'off', 'on', 't', 'true', 'y', 'yes'",
|
|
||||||
six.text_type(ex))
|
|
||||||
|
|
||||||
|
|
||||||
class TestClusterScaleOut(test_base.SenlinTestCase):
|
class TestClusterScaleOut(test_base.SenlinTestCase):
|
||||||
|
|
||||||
@ -444,9 +419,6 @@ class TestClusterScaleOut(test_base.SenlinTestCase):
|
|||||||
self.assertEqual('foo', sot.identity)
|
self.assertEqual('foo', sot.identity)
|
||||||
self.assertEqual(5, sot.count)
|
self.assertEqual(5, sot.count)
|
||||||
|
|
||||||
sot.obj_set_defaults()
|
|
||||||
self.assertFalse(sot.health_check)
|
|
||||||
|
|
||||||
def test_init_failed(self):
|
def test_init_failed(self):
|
||||||
ex = self.assertRaises(ValueError,
|
ex = self.assertRaises(ValueError,
|
||||||
clusters.ClusterScaleOutRequest,
|
clusters.ClusterScaleOutRequest,
|
||||||
@ -454,15 +426,6 @@ class TestClusterScaleOut(test_base.SenlinTestCase):
|
|||||||
self.assertEqual("Value must be >= 0 for field 'count'.",
|
self.assertEqual("Value must be >= 0 for field 'count'.",
|
||||||
six.text_type(ex))
|
six.text_type(ex))
|
||||||
|
|
||||||
def test_init_invalid_boolean(self):
|
|
||||||
ex = self.assertRaises(ValueError,
|
|
||||||
clusters.ClusterScaleOutRequest,
|
|
||||||
identity='foo', count=1, health_check="foo")
|
|
||||||
self.assertEqual(
|
|
||||||
"Unrecognized value 'foo', acceptable values are: '0', '1', "
|
|
||||||
"'f', 'false', 'n', 'no', 'off', 'on', 't', 'true', 'y', 'yes'",
|
|
||||||
six.text_type(ex))
|
|
||||||
|
|
||||||
|
|
||||||
class TestClusterAttachPolicy(test_base.SenlinTestCase):
|
class TestClusterAttachPolicy(test_base.SenlinTestCase):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user