diff options
author | Eoghan Glynn <eglynn@redhat.com> | 2013-11-13 17:47:09 +0000 |
---|---|---|
committer | Eoghan Glynn <eglynn@redhat.com> | 2013-11-14 10:46:01 +0000 |
commit | f33297d7f13eedc8e8aa5e5db294d3a725679974 (patch) | |
tree | 118bb147095976c5fc9b409f486b55bdee1d8f13 | |
parent | e6979b0f81c2cbc87cb353cfa29790b68d70a193 (diff) | |
download | heat-f33297d7f13eedc8e8aa5e5db294d3a725679974.tar.gz |
Ensure autoscaling actions occur for percentage adjustment
Fixes bug 1251007
Previously if the AdjustmentType was set to PercentChangeInCapacity,
then depending on the choice of the instance group MinSize and the
scale-up policy ScalingAdjustment, no autoscaling actions may occur
even when the under-scaled alarm fires.
This situation occurred if:
(MinSize * ScalingAdjustment / 100.0) < 1.0
in which case the group never get gets scaled up even if the under-
scaled alarm stays in the alarm state forever.
Now we follow the rounding rules used by AWS Autoscaling:
http://docs.aws.amazon.com/AutoScaling/latest/DeveloperGuide/as-scale-based-on-demand.html
Change-Id: I79e5e743de1944ace5ef2c4dbcb76c9cab7262bb
(cherry picked from commit 5720e6d647ce3a273d638fd7dacc9c2d6eb2bc22)
-rw-r--r-- | heat/engine/resources/autoscaling.py | 10 | ||||
-rw-r--r-- | heat/tests/test_autoscaling.py | 48 |
2 files changed, 40 insertions, 18 deletions
diff --git a/heat/engine/resources/autoscaling.py b/heat/engine/resources/autoscaling.py index dbdbcd072..ee7cfbe96 100644 --- a/heat/engine/resources/autoscaling.py +++ b/heat/engine/resources/autoscaling.py @@ -14,6 +14,7 @@ # under the License. import copy +import math from heat.engine import resource from heat.engine import signal_responder @@ -410,7 +411,14 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin): new_capacity = adjustment else: # PercentChangeInCapacity - new_capacity = capacity + (capacity * adjustment / 100) + delta = capacity * adjustment / 100.0 + if math.fabs(delta) < 1.0: + rounded = int(math.ceil(delta) if delta > 0.0 + else math.floor(delta)) + else: + rounded = int(math.floor(delta) if delta > 0.0 + else math.ceil(delta)) + new_capacity = capacity + rounded if new_capacity > int(self.properties['MaxSize']): logger.warn('can not exceed %s' % self.properties['MaxSize']) diff --git a/heat/tests/test_autoscaling.py b/heat/tests/test_autoscaling.py index 122b0e425..119ce747e 100644 --- a/heat/tests/test_autoscaling.py +++ b/heat/tests/test_autoscaling.py @@ -835,10 +835,17 @@ class AutoScalingTest(HeatTestCase): rsrc.delete() self.m.VerifyAll() - def test_scaling_group_percent(self): + def _do_test_scaling_group_percent(self, decrease, lowest, + increase, create, highest): t = template_format.parse(as_template) stack = utils.parse_stack(t, params=self.params) + def _verify_instance_names(bound): + instance_names = rsrc.get_instance_names() + self.assertEqual(len(instance_names), bound) + for i in xrange(bound): + self.assertEqual('WebServerGroup-%d' % i, instance_names[i]) + # Create initial group, 2 instances properties = t['Resources']['WebServerGroup']['Properties'] properties['DesiredCapacity'] = '2' @@ -849,30 +856,37 @@ class AutoScalingTest(HeatTestCase): self.m.ReplayAll() rsrc = self.create_scaling_group(t, stack, 'WebServerGroup') stack.resources['WebServerGroup'] = rsrc - self.assertEqual(['WebServerGroup-0', 'WebServerGroup-1'], - rsrc.get_instance_names()) + _verify_instance_names(2) - # reduce by 50% - self._stub_lb_reload(1) - self._stub_meta_expected(now, 'PercentChangeInCapacity : -50') + # reduce by decrease % + self._stub_lb_reload(lowest) + adjust = 'PercentChangeInCapacity : %d' % decrease + self._stub_meta_expected(now, adjust) self._stub_validate() self.m.ReplayAll() - rsrc.adjust(-50, 'PercentChangeInCapacity') - self.assertEqual(['WebServerGroup-0'], - rsrc.get_instance_names()) + rsrc.adjust(decrease, 'PercentChangeInCapacity') + _verify_instance_names(lowest) - # raise by 200% - self._stub_lb_reload(3) - self._stub_meta_expected(now, 'PercentChangeInCapacity : 200') - self._stub_create(2) + # raise by increase % + self._stub_lb_reload(highest) + adjust = 'PercentChangeInCapacity : %d' % increase + self._stub_meta_expected(now, adjust) + self._stub_create(create) self.m.ReplayAll() - rsrc.adjust(200, 'PercentChangeInCapacity') - self.assertEqual(['WebServerGroup-0', 'WebServerGroup-1', - 'WebServerGroup-2'], - rsrc.get_instance_names()) + rsrc.adjust(increase, 'PercentChangeInCapacity') + _verify_instance_names(highest) rsrc.delete() + def test_scaling_group_percent(self): + self._do_test_scaling_group_percent(-50, 1, 200, 2, 3) + + def test_scaling_group_percent_round_up(self): + self._do_test_scaling_group_percent(-33, 1, 33, 1, 2) + + def test_scaling_group_percent_round_down(self): + self._do_test_scaling_group_percent(-66, 1, 225, 2, 3) + def test_scaling_group_cooldown_toosoon(self): t = template_format.parse(as_template) stack = utils.parse_stack(t, params=self.params) |