Add min_adjustment_step property to ScalingPolicy
Adds `min_adjustment_step` property to ScalingPolicy resource. It represents the minimum number of resources that are added or removed when AutoScaling group scales up or down. This can be used only when specifying value `percent_change_in_capacity` for `adjustment_type` property. Change-Id: Ia8976e52047ab47245566487ce1872a8890bcff2 Closes-Bug: #1447913
This commit is contained in:
parent
d644ea964d
commit
63646f8cfd
|
@ -381,6 +381,11 @@ class ResourcePropertyDependency(HeatException):
|
|||
msg_fmt = _('%(prop1)s cannot be specified without %(prop2)s.')
|
||||
|
||||
|
||||
class ResourcePropertyValueDependency(HeatException):
|
||||
msg_fmt = _('%(prop1)s property should only be specified '
|
||||
'for %(prop2)s with value %(value)s.')
|
||||
|
||||
|
||||
class PropertyUnspecifiedError(HeatException):
|
||||
msg_fmt = _('At least one of the following properties '
|
||||
'must be specified: %(props)s')
|
||||
|
|
|
@ -41,12 +41,18 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def _calculate_new_capacity(current, adjustment, adjustment_type,
|
||||
minimum, maximum):
|
||||
min_adjustment_step, minimum, maximum):
|
||||
"""
|
||||
Given the current capacity, calculates the new capacity which results
|
||||
from applying the given adjustment of the given adjustment-type. The
|
||||
new capacity will be kept within the maximum and minimum bounds.
|
||||
"""
|
||||
def _get_minimum_adjustment(adjustment, min_adjustment_step):
|
||||
if min_adjustment_step and min_adjustment_step > abs(adjustment):
|
||||
adjustment = (min_adjustment_step if adjustment > 0
|
||||
else -min_adjustment_step)
|
||||
return adjustment
|
||||
|
||||
if adjustment_type == CHANGE_IN_CAPACITY:
|
||||
new_capacity = current + adjustment
|
||||
elif adjustment_type == EXACT_CAPACITY:
|
||||
|
@ -60,7 +66,8 @@ def _calculate_new_capacity(current, adjustment, adjustment_type,
|
|||
else:
|
||||
rounded = int(math.floor(delta) if delta > 0.0
|
||||
else math.ceil(delta))
|
||||
new_capacity = current + rounded
|
||||
adjustment = _get_minimum_adjustment(rounded, min_adjustment_step)
|
||||
new_capacity = current + adjustment
|
||||
|
||||
if new_capacity > maximum:
|
||||
LOG.debug('truncating growth to %s' % maximum)
|
||||
|
@ -293,7 +300,8 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
|||
current_capacity = grouputils.get_size(self)
|
||||
self.adjust(current_capacity, adjustment_type=EXACT_CAPACITY)
|
||||
|
||||
def adjust(self, adjustment, adjustment_type=CHANGE_IN_CAPACITY):
|
||||
def adjust(self, adjustment, adjustment_type=CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None):
|
||||
"""
|
||||
Adjust the size of the scaling group if the cooldown permits.
|
||||
"""
|
||||
|
@ -309,7 +317,9 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
|||
upper = self.properties[self.MAX_SIZE]
|
||||
|
||||
new_capacity = _calculate_new_capacity(capacity, adjustment,
|
||||
adjustment_type, lower, upper)
|
||||
adjustment_type,
|
||||
min_adjustment_step,
|
||||
lower, upper)
|
||||
|
||||
# send a notification before, on-error and on-success.
|
||||
notif = {
|
||||
|
|
|
@ -14,26 +14,22 @@
|
|||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common.i18n import _
|
||||
from heat.common.i18n import _LI
|
||||
from heat.engine import attributes
|
||||
from heat.engine import constraints
|
||||
from heat.engine import properties
|
||||
from heat.engine.resources import signal_responder
|
||||
from heat.scaling import cooldown
|
||||
from heat.engine.resources.openstack.heat import scaling_policy as heat_sp
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AWSScalingPolicy(signal_responder.SignalResponder,
|
||||
cooldown.CooldownMixin):
|
||||
class AWSScalingPolicy(heat_sp.AutoScalingPolicy):
|
||||
PROPERTIES = (
|
||||
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
|
||||
COOLDOWN,
|
||||
COOLDOWN, MIN_ADJUSTMENT_STEP,
|
||||
) = (
|
||||
'AutoScalingGroupName', 'ScalingAdjustment', 'AdjustmentType',
|
||||
'Cooldown',
|
||||
'Cooldown', 'MinAdjustmentStep',
|
||||
)
|
||||
|
||||
EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
|
||||
|
@ -73,6 +69,20 @@ class AWSScalingPolicy(signal_responder.SignalResponder,
|
|||
_('Cooldown period, in seconds.'),
|
||||
update_allowed=True
|
||||
),
|
||||
MIN_ADJUSTMENT_STEP: properties.Schema(
|
||||
properties.Schema.INTEGER,
|
||||
_('Minimum number of resources that are added or removed '
|
||||
'when the AutoScaling group scales up or down. This can '
|
||||
'be used only when specifying PercentChangeInCapacity '
|
||||
'for the AdjustmentType property.'),
|
||||
constraints=[
|
||||
constraints.Range(
|
||||
min=0,
|
||||
),
|
||||
],
|
||||
update_allowed=True
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
attributes_schema = {
|
||||
|
@ -81,76 +91,9 @@ class AWSScalingPolicy(signal_responder.SignalResponder,
|
|||
),
|
||||
}
|
||||
|
||||
def handle_create(self):
|
||||
super(AWSScalingPolicy, self).handle_create()
|
||||
self.resource_id_set(self._get_user_id())
|
||||
|
||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||
"""
|
||||
If Properties has changed, update self.properties, so we get the new
|
||||
values during any subsequent adjustment.
|
||||
"""
|
||||
if prop_diff:
|
||||
self.properties = json_snippet.properties(self.properties_schema,
|
||||
self.context)
|
||||
|
||||
def _get_adjustement_type(self):
|
||||
return self.properties[self.ADJUSTMENT_TYPE]
|
||||
|
||||
def handle_signal(self, details=None):
|
||||
# ceilometer sends details like this:
|
||||
# {u'alarm_id': ID, u'previous': u'ok', u'current': u'alarm',
|
||||
# u'reason': u'...'})
|
||||
# in this policy we currently assume that this gets called
|
||||
# only when there is an alarm. But the template writer can
|
||||
# put the policy in all the alarm notifiers (nodata, and ok).
|
||||
#
|
||||
# our watchrule has upper case states so lower() them all.
|
||||
if details is None:
|
||||
alarm_state = 'alarm'
|
||||
else:
|
||||
alarm_state = details.get('current',
|
||||
details.get('state', 'alarm')).lower()
|
||||
|
||||
LOG.info(_LI('%(name)s Alarm, new state %(state)s'),
|
||||
{'name': self.name, 'state': alarm_state})
|
||||
|
||||
if alarm_state != 'alarm':
|
||||
return
|
||||
if self._cooldown_inprogress():
|
||||
LOG.info(_LI("%(name)s NOT performing scaling action, "
|
||||
"cooldown %(cooldown)s"),
|
||||
{'name': self.name,
|
||||
'cooldown': self.properties[self.COOLDOWN]})
|
||||
return
|
||||
|
||||
asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
|
||||
group = self.stack.resource_by_refid(asgn_id)
|
||||
if group is None:
|
||||
raise exception.NotFound(_('Alarm %(alarm)s could not find '
|
||||
'scaling group named "%(group)s"') % {
|
||||
'alarm': self.name,
|
||||
'group': asgn_id})
|
||||
|
||||
LOG.info(_LI('%(name)s Alarm, adjusting Group %(group)s with id '
|
||||
'%(asgn_id)s by %(filter)s'),
|
||||
{'name': self.name, 'group': group.name, 'asgn_id': asgn_id,
|
||||
'filter': self.properties[self.SCALING_ADJUSTMENT]})
|
||||
adjustment_type = self._get_adjustement_type()
|
||||
group.adjust(self.properties[self.SCALING_ADJUSTMENT], adjustment_type)
|
||||
|
||||
self._cooldown_timestamp("%s : %s" %
|
||||
(self.properties[self.ADJUSTMENT_TYPE],
|
||||
self.properties[self.SCALING_ADJUSTMENT]))
|
||||
|
||||
def _resolve_attribute(self, name):
|
||||
'''
|
||||
heat extension: "AlarmUrl" returns the url to post to the policy
|
||||
when there is an alarm.
|
||||
'''
|
||||
if name == self.ALARM_URL and self.resource_id is not None:
|
||||
return six.text_type(self._get_signed_url())
|
||||
|
||||
def FnGetRefId(self):
|
||||
if self.resource_id is not None:
|
||||
return six.text_type(self._get_signed_url())
|
||||
|
|
|
@ -37,10 +37,10 @@ class AutoScalingPolicy(signal_responder.SignalResponder,
|
|||
"""
|
||||
PROPERTIES = (
|
||||
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
|
||||
COOLDOWN,
|
||||
COOLDOWN, MIN_ADJUSTMENT_STEP
|
||||
) = (
|
||||
'auto_scaling_group_id', 'scaling_adjustment', 'adjustment_type',
|
||||
'cooldown',
|
||||
'cooldown', 'min_adjustment_step',
|
||||
)
|
||||
|
||||
EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
|
||||
|
@ -81,6 +81,20 @@ class AutoScalingPolicy(signal_responder.SignalResponder,
|
|||
_('Cooldown period, in seconds.'),
|
||||
update_allowed=True
|
||||
),
|
||||
MIN_ADJUSTMENT_STEP: properties.Schema(
|
||||
properties.Schema.INTEGER,
|
||||
_('Minimum number of resources that are added or removed '
|
||||
'when the AutoScaling group scales up or down. This can '
|
||||
'be used only when specifying percent_change_in_capacity '
|
||||
'for the adjustment_type property.'),
|
||||
constraints=[
|
||||
constraints.Range(
|
||||
min=0,
|
||||
),
|
||||
],
|
||||
update_allowed=True
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
attributes_schema = {
|
||||
|
@ -89,6 +103,20 @@ class AutoScalingPolicy(signal_responder.SignalResponder,
|
|||
),
|
||||
}
|
||||
|
||||
def validate(self):
|
||||
"""
|
||||
Add validation for min_adjustment_step
|
||||
"""
|
||||
super(AutoScalingPolicy, self).validate()
|
||||
adjustment_type = self.properties.get(self.ADJUSTMENT_TYPE)
|
||||
adjustment_step = self.properties.get(self.MIN_ADJUSTMENT_STEP)
|
||||
if (adjustment_type != self.PERCENT_CHANGE_IN_CAPACITY
|
||||
and adjustment_step is not None):
|
||||
raise exception.ResourcePropertyValueDependency(
|
||||
prop1=self.MIN_ADJUSTMENT_STEP,
|
||||
prop2=self.ADJUSTMENT_TYPE,
|
||||
value=self.PERCENT_CHANGE_IN_CAPACITY)
|
||||
|
||||
def handle_create(self):
|
||||
super(AutoScalingPolicy, self).handle_create()
|
||||
self.resource_id_set(self._get_user_id())
|
||||
|
@ -146,7 +174,8 @@ class AutoScalingPolicy(signal_responder.SignalResponder,
|
|||
{'name': self.name, 'group': group.name, 'asgn_id': asgn_id,
|
||||
'filter': self.properties[self.SCALING_ADJUSTMENT]})
|
||||
adjustment_type = self._get_adjustement_type()
|
||||
group.adjust(self.properties[self.SCALING_ADJUSTMENT], adjustment_type)
|
||||
group.adjust(self.properties[self.SCALING_ADJUSTMENT], adjustment_type,
|
||||
self.properties[self.MIN_ADJUSTMENT_STEP])
|
||||
|
||||
self._cooldown_timestamp("%s : %s" %
|
||||
(self.properties[self.ADJUSTMENT_TYPE],
|
||||
|
|
|
@ -164,6 +164,66 @@ class TestGroupAdjust(common.HeatTestCase):
|
|||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('ExactCapacity : 3')
|
||||
|
||||
def test_scale_up_min_adjustment(self):
|
||||
self.patchobject(grouputils, 'get_size', return_value=1)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.group.adjust(33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
expected_notifies = [
|
||||
mock.call(
|
||||
capacity=1, suffix='start',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'my-group',
|
||||
message=u'Start resizing the group my-group',
|
||||
adjustment=33,
|
||||
stack=self.group.stack),
|
||||
mock.call(
|
||||
capacity=3, suffix='end',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'my-group',
|
||||
message=u'End resizing the group my-group',
|
||||
adjustment=33,
|
||||
stack=self.group.stack)]
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : 33')
|
||||
|
||||
def test_scale_down_min_adjustment(self):
|
||||
self.patchobject(grouputils, 'get_size', return_value=3)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.group.adjust(-33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
expected_notifies = [
|
||||
mock.call(
|
||||
capacity=3, suffix='start',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'my-group',
|
||||
message=u'Start resizing the group my-group',
|
||||
adjustment=-33,
|
||||
stack=self.group.stack),
|
||||
mock.call(
|
||||
capacity=1, suffix='end',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'my-group',
|
||||
message=u'End resizing the group my-group',
|
||||
adjustment=-33,
|
||||
stack=self.group.stack)]
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(1)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : -33')
|
||||
|
||||
def test_scaling_policy_cooldown_ok(self):
|
||||
self.patchobject(grouputils, 'get_members', return_value=[])
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
|
|
|
@ -20,9 +20,11 @@ import six
|
|||
|
||||
from heat.common import exception
|
||||
from heat.common import template_format
|
||||
from heat.engine import resource
|
||||
from heat.engine import scheduler
|
||||
from heat.tests.autoscaling import inline_templates
|
||||
from heat.tests import common
|
||||
from heat.tests import generic_resource
|
||||
from heat.tests import utils
|
||||
|
||||
|
||||
|
@ -33,6 +35,8 @@ as_params = inline_templates.as_params
|
|||
class TestAutoScalingPolicy(common.HeatTestCase):
|
||||
def setUp(self):
|
||||
super(TestAutoScalingPolicy, self).setUp()
|
||||
resource._register_class('ResourceWithPropsAndAttrs',
|
||||
generic_resource.ResourceWithPropsAndAttrs)
|
||||
cfg.CONF.set_default('heat_waitcondition_server_url',
|
||||
'http://server.test:8000/v1/waitcondition')
|
||||
|
||||
|
@ -43,6 +47,32 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
|||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||
return rsrc
|
||||
|
||||
def test_validate_scaling_policy_ok(self):
|
||||
t = template_format.parse(as_template)
|
||||
t['resources']['my-policy']['properties'][
|
||||
'scaling_adjustment'] = 33
|
||||
t['resources']['my-policy']['properties'][
|
||||
'adjustment_type'] = 'percent_change_in_capacity'
|
||||
t['resources']['my-policy']['properties'][
|
||||
'min_adjustment_step'] = 2
|
||||
stack = utils.parse_stack(t)
|
||||
self.assertIsNone(stack.validate())
|
||||
|
||||
def test_validate_scaling_policy_error(self):
|
||||
t = template_format.parse(as_template)
|
||||
t['resources']['my-policy']['properties'][
|
||||
'scaling_adjustment'] = 1
|
||||
t['resources']['my-policy']['properties'][
|
||||
'adjustment_type'] = 'change_in_capacity'
|
||||
t['resources']['my-policy']['properties'][
|
||||
'min_adjustment_step'] = 2
|
||||
stack = utils.parse_stack(t)
|
||||
ex = self.assertRaises(exception.ResourcePropertyValueDependency,
|
||||
stack.validate)
|
||||
self.assertIn('min_adjustment_step property should only '
|
||||
'be specified for adjustment_type with '
|
||||
'value percent_change_in_capacity.', six.text_type(ex))
|
||||
|
||||
def test_scaling_policy_bad_group(self):
|
||||
t = template_format.parse(inline_templates.as_heat_template_bad_group)
|
||||
stack = utils.parse_stack(t)
|
||||
|
@ -92,7 +122,7 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
|||
return_value=False) as mock_cip:
|
||||
pol.handle_signal(details=test)
|
||||
mock_cip.assert_called_once_with()
|
||||
group.adjust.assert_called_once_with(1, 'ChangeInCapacity')
|
||||
group.adjust.assert_called_once_with(1, 'ChangeInCapacity', None)
|
||||
|
||||
|
||||
class TestCooldownMixin(common.HeatTestCase):
|
||||
|
|
|
@ -22,52 +22,86 @@ class TestCapacityChanges(common.HeatTestCase):
|
|||
# r rounded (+up, -down)
|
||||
# e EXACT_CAPACITY
|
||||
# p PERCENT_CHANGE_IN_CAPACITY
|
||||
# s MIN_ADJUSTMENT_STEP
|
||||
scenarios = [
|
||||
('+n', dict(current=2, adjustment=3,
|
||||
adjustment_type=asc.CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=10, expected=5)),
|
||||
('-n', dict(current=6, adjustment=-2,
|
||||
adjustment_type=asc.CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=5, expected=4)),
|
||||
('+nb', dict(current=2, adjustment=8,
|
||||
adjustment_type=asc.CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=5, expected=5)),
|
||||
('-nb', dict(current=2, adjustment=-10,
|
||||
adjustment_type=asc.CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=1, maximum=5, expected=1)),
|
||||
('e', dict(current=2, adjustment=4,
|
||||
adjustment_type=asc.EXACT_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=5, expected=4)),
|
||||
('+eb', dict(current=2, adjustment=11,
|
||||
adjustment_type=asc.EXACT_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=5, expected=5)),
|
||||
('-eb', dict(current=4, adjustment=1,
|
||||
adjustment_type=asc.EXACT_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=3, maximum=5, expected=3)),
|
||||
('+p', dict(current=4, adjustment=50,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=1, maximum=10, expected=6)),
|
||||
('-p', dict(current=4, adjustment=-25,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=1, maximum=10, expected=3)),
|
||||
('+pb', dict(current=4, adjustment=100,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=1, maximum=6, expected=6)),
|
||||
('-pb', dict(current=6, adjustment=-50,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=4, maximum=10, expected=4)),
|
||||
('-p+r', dict(current=2, adjustment=-33,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=10, expected=1)),
|
||||
('+p+r', dict(current=1, adjustment=33,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=10, expected=2)),
|
||||
('-p-r', dict(current=2, adjustment=-66,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=10, expected=1)),
|
||||
('+p-r', dict(current=1, adjustment=225,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None,
|
||||
minimum=0, maximum=10, expected=3)),
|
||||
('+ps', dict(current=1, adjustment=100,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=3,
|
||||
minimum=0, maximum=10, expected=4)),
|
||||
('+p+rs', dict(current=1, adjustment=33,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=2,
|
||||
minimum=0, maximum=10, expected=3)),
|
||||
('+p-rs', dict(current=1, adjustment=325,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=2,
|
||||
minimum=0, maximum=10, expected=4)),
|
||||
('-p-rs', dict(current=3, adjustment=-25,
|
||||
adjustment_type=asc.PERCENT_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=2,
|
||||
minimum=0, maximum=10, expected=1)),
|
||||
|
||||
|
||||
]
|
||||
|
||||
def test_calc(self):
|
||||
|
@ -75,4 +109,5 @@ class TestCapacityChanges(common.HeatTestCase):
|
|||
asc._calculate_new_capacity(
|
||||
self.current, self.adjustment,
|
||||
self.adjustment_type,
|
||||
self.min_adjustment_step,
|
||||
self.minimum, self.maximum))
|
||||
|
|
|
@ -345,6 +345,66 @@ class TestGroupAdjust(common.HeatTestCase):
|
|||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('ExactCapacity : 3')
|
||||
|
||||
def test_scale_up_min_adjustment(self):
|
||||
self.patchobject(grouputils, 'get_size', return_value=1)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.group.adjust(33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
expected_notifies = [
|
||||
mock.call(
|
||||
capacity=1, suffix='start',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'WebServerGroup',
|
||||
message=u'Start resizing the group WebServerGroup',
|
||||
adjustment=33,
|
||||
stack=self.group.stack),
|
||||
mock.call(
|
||||
capacity=3, suffix='end',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'WebServerGroup',
|
||||
message=u'End resizing the group WebServerGroup',
|
||||
adjustment=33,
|
||||
stack=self.group.stack)]
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : 33')
|
||||
|
||||
def test_scale_down_min_adjustment(self):
|
||||
self.patchobject(grouputils, 'get_size', return_value=5)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.group.adjust(-33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
expected_notifies = [
|
||||
mock.call(
|
||||
capacity=5, suffix='start',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'WebServerGroup',
|
||||
message=u'Start resizing the group WebServerGroup',
|
||||
adjustment=-33,
|
||||
stack=self.group.stack),
|
||||
mock.call(
|
||||
capacity=3, suffix='end',
|
||||
adjustment_type='PercentChangeInCapacity',
|
||||
groupname=u'WebServerGroup',
|
||||
message=u'End resizing the group WebServerGroup',
|
||||
adjustment=-33,
|
||||
stack=self.group.stack)]
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : -33')
|
||||
|
||||
def test_scaling_policy_cooldown_ok(self):
|
||||
self.patchobject(grouputils, 'get_members', return_value=[])
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
|
|
|
@ -43,6 +43,34 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
|||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||
return rsrc
|
||||
|
||||
def test_validate_scaling_policy_ok(self):
|
||||
t = template_format.parse(inline_templates.as_template)
|
||||
t['Resources']['WebServerScaleUpPolicy']['Properties'][
|
||||
'ScalingAdjustment'] = 33
|
||||
t['Resources']['WebServerScaleUpPolicy']['Properties'][
|
||||
'AdjustmentType'] = 'PercentChangeInCapacity'
|
||||
t['Resources']['WebServerScaleUpPolicy']['Properties'][
|
||||
'MinAdjustmentStep'] = 2
|
||||
stack = utils.parse_stack(t, params=as_params)
|
||||
self.policy = stack['WebServerScaleUpPolicy']
|
||||
self.assertIsNone(self.policy.validate())
|
||||
|
||||
def test_validate_scaling_policy_error(self):
|
||||
t = template_format.parse(inline_templates.as_template)
|
||||
t['Resources']['WebServerScaleUpPolicy']['Properties'][
|
||||
'ScalingAdjustment'] = 1
|
||||
t['Resources']['WebServerScaleUpPolicy']['Properties'][
|
||||
'AdjustmentType'] = 'ChangeInCapacity'
|
||||
t['Resources']['WebServerScaleUpPolicy']['Properties'][
|
||||
'MinAdjustmentStep'] = 2
|
||||
stack = utils.parse_stack(t, params=as_params)
|
||||
self.policy = stack['WebServerScaleUpPolicy']
|
||||
ex = self.assertRaises(exception.ResourcePropertyValueDependency,
|
||||
self.policy.validate)
|
||||
self.assertIn('MinAdjustmentStep property should only '
|
||||
'be specified for AdjustmentType with '
|
||||
'value PercentChangeInCapacity.', six.text_type(ex))
|
||||
|
||||
def test_scaling_policy_bad_group(self):
|
||||
t = template_format.parse(inline_templates.as_template_bad_group)
|
||||
stack = utils.parse_stack(t, params=as_params)
|
||||
|
@ -93,7 +121,7 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
|||
return_value=False) as mock_cip:
|
||||
pol.handle_signal(details=test)
|
||||
mock_cip.assert_called_once_with()
|
||||
group.adjust.assert_called_once_with(1, 'ChangeInCapacity')
|
||||
group.adjust.assert_called_once_with(1, 'ChangeInCapacity', None)
|
||||
|
||||
|
||||
class TestCooldownMixin(common.HeatTestCase):
|
||||
|
|
Loading…
Reference in New Issue