summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEoghan Glynn <eglynn@redhat.com>2013-11-13 17:47:09 +0000
committerEoghan Glynn <eglynn@redhat.com>2013-11-14 10:46:01 +0000
commitf33297d7f13eedc8e8aa5e5db294d3a725679974 (patch)
tree118bb147095976c5fc9b409f486b55bdee1d8f13
parente6979b0f81c2cbc87cb353cfa29790b68d70a193 (diff)
downloadheat-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.py10
-rw-r--r--heat/tests/test_autoscaling.py48
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)