Merge "Avoid cooldown when group size does not change"
This commit is contained in:
commit
9202e87821
@ -226,7 +226,7 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
||||
"""Invoke the cooldown after creation succeeds."""
|
||||
done = super(AutoScalingGroup, self).check_create_complete(task)
|
||||
if done:
|
||||
self._cooldown_timestamp(
|
||||
self._finished_scaling(
|
||||
"%s : %s" % (sc_util.CFN_EXACT_CAPACITY,
|
||||
grouputils.get_size(self)))
|
||||
return done
|
||||
@ -262,7 +262,7 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
||||
adjustment_type=sc_util.CFN_CHANGE_IN_CAPACITY,
|
||||
min_adjustment_step=None, signal=False):
|
||||
"""Adjust the size of the scaling group if the cooldown permits."""
|
||||
if self._cooldown_inprogress():
|
||||
if not self._is_scaling_allowed():
|
||||
LOG.info(_LI("%(name)s NOT performing scaling adjustment, "
|
||||
"cooldown %(cooldown)s"),
|
||||
{'name': self.name,
|
||||
@ -281,6 +281,7 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
||||
min_adjustment_step,
|
||||
lower, upper)
|
||||
|
||||
changed_size = new_capacity != capacity
|
||||
# send a notification before, on-error and on-success.
|
||||
notif = {
|
||||
'stack': self.stack,
|
||||
@ -314,8 +315,9 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
||||
})
|
||||
notification.send(**notif)
|
||||
finally:
|
||||
self._cooldown_timestamp("%s : %s" % (adjustment_type,
|
||||
adjustment))
|
||||
self._finished_scaling("%s : %s" % (adjustment_type, adjustment),
|
||||
changed_size=changed_size)
|
||||
return changed_size
|
||||
|
||||
def _tags(self):
|
||||
"""Add Identifying Tags to all servers in the group.
|
||||
|
@ -161,7 +161,7 @@ class AutoScalingPolicy(signal_responder.SignalResponder,
|
||||
|
||||
if alarm_state != 'alarm':
|
||||
raise exception.NoActionRequired()
|
||||
if self._cooldown_inprogress():
|
||||
if not self._is_scaling_allowed():
|
||||
LOG.info(_LI("%(name)s NOT performing scaling action, "
|
||||
"cooldown %(cooldown)s"),
|
||||
{'name': self.name,
|
||||
@ -170,6 +170,7 @@ class AutoScalingPolicy(signal_responder.SignalResponder,
|
||||
|
||||
asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
|
||||
group = self.stack.resource_by_refid(asgn_id)
|
||||
changed_size = False
|
||||
try:
|
||||
if group is None:
|
||||
raise exception.NotFound(_('Alarm %(alarm)s could not find '
|
||||
@ -182,15 +183,16 @@ class AutoScalingPolicy(signal_responder.SignalResponder,
|
||||
{'name': self.name, 'group': group.name,
|
||||
'asgn_id': asgn_id,
|
||||
'filter': self.properties[self.SCALING_ADJUSTMENT]})
|
||||
group.adjust(self.properties[self.SCALING_ADJUSTMENT],
|
||||
self.properties[self.ADJUSTMENT_TYPE],
|
||||
self.properties[self.MIN_ADJUSTMENT_STEP],
|
||||
signal=True)
|
||||
|
||||
finally:
|
||||
self._cooldown_timestamp("%s : %s" % (
|
||||
changed_size = group.adjust(
|
||||
self.properties[self.SCALING_ADJUSTMENT],
|
||||
self.properties[self.ADJUSTMENT_TYPE],
|
||||
self.properties[self.SCALING_ADJUSTMENT]))
|
||||
self.properties[self.MIN_ADJUSTMENT_STEP],
|
||||
signal=True)
|
||||
finally:
|
||||
self._finished_scaling("%s : %s" % (
|
||||
self.properties[self.ADJUSTMENT_TYPE],
|
||||
self.properties[self.SCALING_ADJUSTMENT]),
|
||||
changed_size=changed_size)
|
||||
|
||||
def _resolve_attribute(self, name):
|
||||
if self.resource_id is None:
|
||||
|
@ -22,8 +22,10 @@ class CooldownMixin(object):
|
||||
This logic includes both cooldown timestamp comparing and scaling in
|
||||
progress checking.
|
||||
"""
|
||||
def _cooldown_inprogress(self):
|
||||
inprogress = False
|
||||
def _is_scaling_allowed(self):
|
||||
metadata = self.metadata_get()
|
||||
if metadata.get('scaling_in_progress'):
|
||||
return False
|
||||
try:
|
||||
# Negative values don't make sense, so they are clamped to zero
|
||||
cooldown = max(0, self.properties[self.COOLDOWN])
|
||||
@ -31,34 +33,30 @@ class CooldownMixin(object):
|
||||
# If not specified, it will be None, same as cooldown == 0
|
||||
cooldown = 0
|
||||
|
||||
metadata = self.metadata_get()
|
||||
if metadata.get('scaling_in_progress'):
|
||||
return True
|
||||
|
||||
if 'cooldown' not in metadata:
|
||||
# Note: this is for supporting old version cooldown checking
|
||||
if metadata and cooldown != 0:
|
||||
last_adjust = next(six.iterkeys(metadata))
|
||||
if not timeutils.is_older_than(last_adjust, cooldown):
|
||||
inprogress = True
|
||||
return False
|
||||
elif cooldown != 0:
|
||||
last_adjust = next(six.iterkeys(metadata['cooldown']))
|
||||
if not timeutils.is_older_than(last_adjust, cooldown):
|
||||
inprogress = True
|
||||
return False
|
||||
# Assumes _finished_scaling is called
|
||||
# after the scaling operation completes
|
||||
metadata['scaling_in_progress'] = True
|
||||
self.metadata_set(metadata)
|
||||
return True
|
||||
|
||||
if not inprogress:
|
||||
metadata['scaling_in_progress'] = True
|
||||
self.metadata_set(metadata)
|
||||
|
||||
return inprogress
|
||||
|
||||
def _cooldown_timestamp(self, reason):
|
||||
# Save cooldown timestamp into metadata and clean the
|
||||
# scaling_in_progress state.
|
||||
def _finished_scaling(self, cooldown_reason,
|
||||
changed_size=True):
|
||||
# If we wanted to implement the AutoScaling API like AWS does,
|
||||
# we could maintain event history here, but since we only need
|
||||
# the latest event for cooldown, just store that for now
|
||||
metadata = self.metadata_get()
|
||||
metadata['cooldown'] = {timeutils.utcnow().isoformat(): reason}
|
||||
if changed_size:
|
||||
now = timeutils.utcnow().isoformat()
|
||||
metadata['cooldown'] = {now: cooldown_reason}
|
||||
metadata['scaling_in_progress'] = False
|
||||
self.metadata_set(metadata)
|
||||
|
@ -113,17 +113,17 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
self.assertIsNone(self.group.validate())
|
||||
|
||||
def test_scaling_policy_cooldown_toosoon(self):
|
||||
"""If _cooldown_inprogress() returns True don't progress."""
|
||||
"""If _is_scaling_allowed() returns False don't progress."""
|
||||
|
||||
dont_call = self.patchobject(grouputils, 'get_size')
|
||||
with mock.patch.object(self.group, '_cooldown_inprogress',
|
||||
return_value=True):
|
||||
with mock.patch.object(self.group, '_is_scaling_allowed',
|
||||
return_value=False):
|
||||
self.group.adjust(1)
|
||||
self.assertEqual([], dont_call.call_args_list)
|
||||
|
||||
def test_scaling_policy_cooldown_toosoon_with_signal(self):
|
||||
with mock.patch.object(self.group, '_cooldown_inprogress',
|
||||
return_value=True):
|
||||
with mock.patch.object(self.group, '_is_scaling_allowed',
|
||||
return_value=False):
|
||||
self.assertRaises(exception.NoActionRequired, self.group.adjust, 1,
|
||||
signal=True)
|
||||
|
||||
@ -131,10 +131,10 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
"""Alway resize even if the capacity is the same."""
|
||||
self.patchobject(grouputils, 'get_size', return_value=3)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(3, adjustment_type='ExactCapacity')
|
||||
|
||||
expected_notifies = [
|
||||
@ -155,15 +155,16 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('ExactCapacity : 3')
|
||||
finished_scaling.assert_called_once_with('ExactCapacity : 3',
|
||||
changed_size=False)
|
||||
|
||||
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')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
@ -185,15 +186,16 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : 33')
|
||||
finished_scaling.assert_called_once_with(
|
||||
'PercentChangeInCapacity : 33', changed_size=True)
|
||||
|
||||
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')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(-33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
@ -215,15 +217,16 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(1)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : -33')
|
||||
finished_scaling.assert_called_once_with(
|
||||
'PercentChangeInCapacity : -33', changed_size=True)
|
||||
|
||||
def test_scaling_policy_cooldown_ok(self):
|
||||
self.patchobject(grouputils, 'get_size', return_value=0)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(1)
|
||||
|
||||
expected_notifies = [
|
||||
@ -243,7 +246,8 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(1)
|
||||
cd_stamp.assert_called_once_with('ChangeInCapacity : 1')
|
||||
finished_scaling.assert_called_once_with('ChangeInCapacity : 1',
|
||||
changed_size=True)
|
||||
grouputils.get_size.assert_called_once_with(self.group)
|
||||
|
||||
def test_scaling_policy_resize_fail(self):
|
||||
@ -251,9 +255,9 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
self.patchobject(self.group, 'resize',
|
||||
side_effect=ValueError('test error'))
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_cooldown_timestamp')
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.patchobject(self.group, '_finished_scaling')
|
||||
self.assertRaises(ValueError, self.group.adjust, 1)
|
||||
|
||||
expected_notifies = [
|
||||
@ -281,9 +285,9 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
self.patchobject(self.group, 'resize',
|
||||
side_effect=ValueError('test error'))
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_cooldown_timestamp')
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.patchobject(self.group, '_finished_scaling')
|
||||
|
||||
self.assertRaises(ValueError, self.group.adjust,
|
||||
5, adjustment_type='ExactCapacity')
|
||||
|
@ -81,14 +81,14 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
||||
pol = self.create_scaling_policy(t, stack, 'my-policy')
|
||||
|
||||
test = {'current': 'not_an_alarm'}
|
||||
with mock.patch.object(pol, '_cooldown_inprogress',
|
||||
with mock.patch.object(pol, '_is_scaling_allowed',
|
||||
side_effect=AssertionError()) as dont_call:
|
||||
self.assertRaises(exception.NoActionRequired,
|
||||
pol.handle_signal, details=test)
|
||||
self.assertEqual([], dont_call.call_args_list)
|
||||
|
||||
def test_scaling_policy_cooldown_toosoon(self):
|
||||
"""If _cooldown_inprogress() returns True don't progress."""
|
||||
"""If _is_scaling_allowed() returns False don't progress."""
|
||||
t = template_format.parse(as_template)
|
||||
stack = utils.parse_stack(t, params=as_params)
|
||||
pol = self.create_scaling_policy(t, stack, 'my-policy')
|
||||
@ -96,8 +96,8 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
||||
|
||||
with mock.patch.object(pol.stack, 'resource_by_refid',
|
||||
side_effect=AssertionError) as dont_call:
|
||||
with mock.patch.object(pol, '_cooldown_inprogress',
|
||||
return_value=True) as mock_cip:
|
||||
with mock.patch.object(pol, '_is_scaling_allowed',
|
||||
return_value=False) as mock_cip:
|
||||
self.assertRaises(exception.NoActionRequired,
|
||||
pol.handle_signal, details=test)
|
||||
mock_cip.assert_called_once_with()
|
||||
@ -111,10 +111,10 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
||||
|
||||
group = self.patchobject(pol.stack, 'resource_by_refid').return_value
|
||||
group.name = 'fluffy'
|
||||
with mock.patch.object(pol, '_cooldown_inprogress',
|
||||
return_value=False) as mock_cip:
|
||||
with mock.patch.object(pol, '_is_scaling_allowed',
|
||||
return_value=True) as mock_isa:
|
||||
pol.handle_signal(details=test)
|
||||
mock_cip.assert_called_once_with()
|
||||
mock_isa.assert_called_once_with()
|
||||
group.adjust.assert_called_once_with(1, 'change_in_capacity', None,
|
||||
signal=True)
|
||||
|
||||
@ -159,7 +159,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
previous_meta = {'cooldown': {
|
||||
now.isoformat(): 'change_in_capacity : 1'}}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertTrue(pol._cooldown_inprogress())
|
||||
self.assertFalse(pol._is_scaling_allowed())
|
||||
|
||||
def test_cooldown_is_in_progress_scaling_unfinished(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -168,7 +168,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
|
||||
previous_meta = {'scaling_in_progress': True}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertTrue(pol._cooldown_inprogress())
|
||||
self.assertFalse(pol._is_scaling_allowed())
|
||||
|
||||
def test_cooldown_not_in_progress(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -183,7 +183,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
'scaling_in_progress': False
|
||||
}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertFalse(pol._cooldown_inprogress())
|
||||
self.assertTrue(pol._is_scaling_allowed())
|
||||
|
||||
def test_scaling_policy_cooldown_zero(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -199,7 +199,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
previous_meta = {'cooldown': {
|
||||
now.isoformat(): 'change_in_capacity : 1'}}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertFalse(pol._cooldown_inprogress())
|
||||
self.assertTrue(pol._is_scaling_allowed())
|
||||
|
||||
def test_scaling_policy_cooldown_none(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -216,7 +216,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
previous_meta = {'cooldown': {
|
||||
now.isoformat(): 'change_in_capacity : 1'}}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertFalse(pol._cooldown_inprogress())
|
||||
self.assertTrue(pol._is_scaling_allowed())
|
||||
|
||||
def test_metadata_is_written(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -227,7 +227,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
reason = 'cool as'
|
||||
meta_set = self.patchobject(pol, 'metadata_set')
|
||||
self.patchobject(timeutils, 'utcnow', return_value=nowish)
|
||||
pol._cooldown_timestamp(reason)
|
||||
pol._finished_scaling(reason)
|
||||
meta_set.assert_called_once_with(
|
||||
{'cooldown': {nowish.isoformat(): reason},
|
||||
'scaling_in_progress': False})
|
||||
|
@ -300,17 +300,17 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
self.assertIsNone(self.group.validate())
|
||||
|
||||
def test_scaling_policy_cooldown_toosoon(self):
|
||||
"""If _cooldown_inprogress() returns True don't progress."""
|
||||
"""If _is_scaling_allowed() returns False don't progress."""
|
||||
|
||||
dont_call = self.patchobject(grouputils, 'get_size')
|
||||
with mock.patch.object(self.group, '_cooldown_inprogress',
|
||||
return_value=True):
|
||||
with mock.patch.object(self.group, '_is_scaling_allowed',
|
||||
return_value=False):
|
||||
self.group.adjust(1)
|
||||
self.assertEqual([], dont_call.call_args_list)
|
||||
|
||||
def test_scaling_policy_cooldown_toosoon_with_signal(self):
|
||||
with mock.patch.object(self.group, '_cooldown_inprogress',
|
||||
return_value=True):
|
||||
with mock.patch.object(self.group, '_is_scaling_allowed',
|
||||
return_value=False):
|
||||
self.assertRaises(exception.NoActionRequired, self.group.adjust, 1,
|
||||
signal=True)
|
||||
|
||||
@ -318,10 +318,10 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
"""Alway resize even if the capacity is the same."""
|
||||
self.patchobject(grouputils, 'get_size', return_value=3)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(3, adjustment_type='ExactCapacity')
|
||||
|
||||
expected_notifies = [
|
||||
@ -342,15 +342,16 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('ExactCapacity : 3')
|
||||
finished_scaling.assert_called_once_with('ExactCapacity : 3',
|
||||
changed_size=False)
|
||||
|
||||
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')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
@ -372,15 +373,16 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : 33')
|
||||
finished_scaling.assert_called_once_with(
|
||||
'PercentChangeInCapacity : 33', changed_size=True)
|
||||
|
||||
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')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(-33, adjustment_type='PercentChangeInCapacity',
|
||||
min_adjustment_step=2)
|
||||
|
||||
@ -402,15 +404,16 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(3)
|
||||
cd_stamp.assert_called_once_with('PercentChangeInCapacity : -33')
|
||||
finished_scaling.assert_called_once_with(
|
||||
'PercentChangeInCapacity : -33', changed_size=True)
|
||||
|
||||
def test_scaling_policy_cooldown_ok(self):
|
||||
self.patchobject(grouputils, 'get_size', return_value=0)
|
||||
resize = self.patchobject(self.group, 'resize')
|
||||
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
|
||||
finished_scaling = self.patchobject(self.group, '_finished_scaling')
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.group.adjust(1)
|
||||
|
||||
expected_notifies = [
|
||||
@ -430,7 +433,8 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
|
||||
self.assertEqual(expected_notifies, notify.call_args_list)
|
||||
resize.assert_called_once_with(1)
|
||||
cd_stamp.assert_called_once_with('ChangeInCapacity : 1')
|
||||
finished_scaling.assert_called_once_with('ChangeInCapacity : 1',
|
||||
changed_size=True)
|
||||
grouputils.get_size.assert_called_once_with(self.group)
|
||||
|
||||
def test_scaling_policy_resize_fail(self):
|
||||
@ -438,9 +442,9 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
self.patchobject(self.group, 'resize',
|
||||
side_effect=ValueError('test error'))
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_cooldown_timestamp')
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.patchobject(self.group, '_finished_scaling')
|
||||
self.assertRaises(ValueError, self.group.adjust, 1)
|
||||
|
||||
expected_notifies = [
|
||||
@ -468,9 +472,9 @@ class TestGroupAdjust(common.HeatTestCase):
|
||||
self.patchobject(self.group, 'resize',
|
||||
side_effect=ValueError('test error'))
|
||||
notify = self.patch('heat.engine.notification.autoscaling.send')
|
||||
self.patchobject(self.group, '_cooldown_inprogress',
|
||||
return_value=False)
|
||||
self.patchobject(self.group, '_cooldown_timestamp')
|
||||
self.patchobject(self.group, '_is_scaling_allowed',
|
||||
return_value=True)
|
||||
self.patchobject(self.group, '_finished_scaling')
|
||||
|
||||
self.assertRaises(ValueError, self.group.adjust,
|
||||
5, adjustment_type='ExactCapacity')
|
||||
|
@ -87,14 +87,14 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
||||
pol = self.create_scaling_policy(t, stack, 'WebServerScaleUpPolicy')
|
||||
|
||||
test = {'current': 'not_an_alarm'}
|
||||
with mock.patch.object(pol, '_cooldown_inprogress',
|
||||
with mock.patch.object(pol, '_is_scaling_allowed',
|
||||
side_effect=AssertionError()) as dont_call:
|
||||
self.assertRaises(exception.NoActionRequired,
|
||||
pol.handle_signal, details=test)
|
||||
self.assertEqual([], dont_call.call_args_list)
|
||||
|
||||
def test_scaling_policy_cooldown_toosoon(self):
|
||||
"""If _cooldown_inprogress() returns True don't progress."""
|
||||
"""If _is_scaling_allowed() returns False don't progress."""
|
||||
t = template_format.parse(as_template)
|
||||
stack = utils.parse_stack(t, params=as_params)
|
||||
pol = self.create_scaling_policy(t, stack, 'WebServerScaleUpPolicy')
|
||||
@ -102,11 +102,11 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
||||
|
||||
with mock.patch.object(pol.stack, 'resource_by_refid',
|
||||
side_effect=AssertionError) as dont_call:
|
||||
with mock.patch.object(pol, '_cooldown_inprogress',
|
||||
return_value=True) as mock_cip:
|
||||
with mock.patch.object(pol, '_is_scaling_allowed',
|
||||
return_value=False) as mock_isa:
|
||||
self.assertRaises(exception.NoActionRequired,
|
||||
pol.handle_signal, details=test)
|
||||
mock_cip.assert_called_once_with()
|
||||
mock_isa.assert_called_once_with()
|
||||
self.assertEqual([], dont_call.call_args_list)
|
||||
|
||||
def test_scaling_policy_cooldown_ok(self):
|
||||
@ -117,10 +117,10 @@ class TestAutoScalingPolicy(common.HeatTestCase):
|
||||
|
||||
group = self.patchobject(pol.stack, 'resource_by_refid').return_value
|
||||
group.name = 'fluffy'
|
||||
with mock.patch.object(pol, '_cooldown_inprogress',
|
||||
return_value=False) as mock_cip:
|
||||
with mock.patch.object(pol, '_is_scaling_allowed',
|
||||
return_value=True) as mock_isa:
|
||||
pol.handle_signal(details=test)
|
||||
mock_cip.assert_called_once_with()
|
||||
mock_isa.assert_called_once_with()
|
||||
group.adjust.assert_called_once_with(1, 'ChangeInCapacity', None,
|
||||
signal=True)
|
||||
|
||||
@ -173,7 +173,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
previous_meta = {'cooldown': {
|
||||
now.isoformat(): 'ChangeInCapacity : 1'}}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertTrue(pol._cooldown_inprogress())
|
||||
self.assertFalse(pol._is_scaling_allowed())
|
||||
|
||||
def test_cooldown_is_in_progress_scaling_unfinished(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -182,7 +182,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
|
||||
previous_meta = {'scaling_in_progress': True}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertTrue(pol._cooldown_inprogress())
|
||||
self.assertFalse(pol._is_scaling_allowed())
|
||||
|
||||
def test_cooldown_not_in_progress(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -197,7 +197,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
'scaling_in_progress': False
|
||||
}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertFalse(pol._cooldown_inprogress())
|
||||
self.assertTrue(pol._is_scaling_allowed())
|
||||
|
||||
def test_scaling_policy_cooldown_zero(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -212,7 +212,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
now = timeutils.utcnow()
|
||||
previous_meta = {now.isoformat(): 'ChangeInCapacity : 1'}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertFalse(pol._cooldown_inprogress())
|
||||
self.assertTrue(pol._is_scaling_allowed())
|
||||
|
||||
def test_scaling_policy_cooldown_none(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -228,7 +228,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
now = timeutils.utcnow()
|
||||
previous_meta = {now.isoformat(): 'ChangeInCapacity : 1'}
|
||||
self.patchobject(pol, 'metadata_get', return_value=previous_meta)
|
||||
self.assertFalse(pol._cooldown_inprogress())
|
||||
self.assertTrue(pol._is_scaling_allowed())
|
||||
|
||||
def test_metadata_is_written(self):
|
||||
t = template_format.parse(as_template)
|
||||
@ -239,7 +239,7 @@ class TestCooldownMixin(common.HeatTestCase):
|
||||
reason = 'cool as'
|
||||
meta_set = self.patchobject(pol, 'metadata_set')
|
||||
self.patchobject(timeutils, 'utcnow', return_value=nowish)
|
||||
pol._cooldown_timestamp(reason)
|
||||
pol._finished_scaling(reason)
|
||||
meta_set.assert_called_once_with(
|
||||
{'cooldown': {nowish.isoformat(): reason},
|
||||
'scaling_in_progress': False})
|
||||
|
Loading…
x
Reference in New Issue
Block a user