From a41442e8737b19b02f5c18cf004bd95e9bbde006 Mon Sep 17 00:00:00 2001 From: Zhang Yang Date: Mon, 14 Apr 2014 00:25:46 -0700 Subject: [PATCH] Allow DesiredCapacity to be zero When updating or validating a AutoScaleGroup, 'DesiredCapacity' is ignored if the value is 0. - Add validation for 'DesiredCapacity' if the value is 0, - Don't ignore zero when updating. Change-Id: I830aaf97ebed6b2c77c72b18dc8d222ce23f9a28 Partial-Bug: #1304423 --- heat/engine/resources/autoscaling.py | 4 +- heat/tests/test_autoscaling.py | 59 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/heat/engine/resources/autoscaling.py b/heat/engine/resources/autoscaling.py index 84ccf363c6..3ecc7aff9c 100644 --- a/heat/engine/resources/autoscaling.py +++ b/heat/engine/resources/autoscaling.py @@ -607,7 +607,7 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin): if capacity > self.properties[self.MAX_SIZE]: new_capacity = self.properties[self.MAX_SIZE] if self.DESIRED_CAPACITY in prop_diff: - if self.properties[self.DESIRED_CAPACITY]: + if self.properties[self.DESIRED_CAPACITY] is not None: new_capacity = self.properties[self.DESIRED_CAPACITY] if new_capacity is not None: @@ -724,7 +724,7 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin): msg = _("The size of AutoScalingGroup can not be less than zero") raise exception.StackValidationFailed(message=msg) - if self.properties[self.DESIRED_CAPACITY]: + if self.properties[self.DESIRED_CAPACITY] is not None: desired_capacity = self.properties[self.DESIRED_CAPACITY] if desired_capacity < min_size or desired_capacity > max_size: msg = _("DesiredCapacity must be between MinSize and MaxSize") diff --git a/heat/tests/test_autoscaling.py b/heat/tests/test_autoscaling.py index 700358d188..cde35e824e 100644 --- a/heat/tests/test_autoscaling.py +++ b/heat/tests/test_autoscaling.py @@ -172,6 +172,17 @@ class AutoScalingTest(HeatTestCase): instance.Instance.check_create_complete( cookie).MultipleTimes().AndReturn(True) + def _stub_delete(self, num): + self._stub_validate() + self.m.StubOutWithMock(instance.Instance, 'handle_delete') + self.m.StubOutWithMock(instance.Instance, 'check_delete_complete') + task = object() + for x in range(num): + instance.Instance.handle_delete().AndReturn(task) + instance.Instance.check_delete_complete(task).AndReturn(False) + instance.Instance.check_delete_complete( + task).MultipleTimes().AndReturn(True) + def _stub_lb_reload(self, num, unset=True, nochange=False): expected_list = [self.dummy_instance_id] * num if unset: @@ -246,6 +257,7 @@ class AutoScalingTest(HeatTestCase): properties = t['Resources']['WebServerGroup']['Properties'] properties['MinSize'] = '0' properties['MaxSize'] = '0' + properties['DesiredCapacity'] = '0' stack = utils.parse_stack(t, params=self.params) self._stub_lb_reload(0) self.m.ReplayAll() @@ -642,6 +654,37 @@ class AutoScalingTest(HeatTestCase): rsrc.delete() self.m.VerifyAll() + def test_scaling_group_update_ok_desired_zero(self): + t = template_format.parse(as_template) + properties = t['Resources']['WebServerGroup']['Properties'] + properties['MinSize'] = '1' + properties['MaxSize'] = '3' + stack = utils.parse_stack(t, params=self.params) + + self._stub_lb_reload(1) + now = timeutils.utcnow() + self._stub_meta_expected(now, 'ExactCapacity : 1') + self._stub_create(1) + self.m.ReplayAll() + rsrc = self.create_scaling_group(t, stack, 'WebServerGroup') + self.assertEqual(1, len(rsrc.get_instance_names())) + + # Increase min size to 2 via DesiredCapacity, should adjust + self._stub_lb_reload(0) + self._stub_meta_expected(now, 'ExactCapacity : 0') + self._stub_delete(1) + self.m.ReplayAll() + + update_snippet = copy.deepcopy(rsrc.parsed_template()) + update_snippet['Properties']['MinSize'] = '0' + update_snippet['Properties']['DesiredCapacity'] = '0' + scheduler.TaskRunner(rsrc.update, update_snippet)() + self.assertEqual(0, len(rsrc.get_instance_names())) + self.assertEqual(0, rsrc.properties['DesiredCapacity']) + + rsrc.delete() + self.m.VerifyAll() + def test_scaling_group_update_ok_desired_remove(self): t = template_format.parse(as_template) properties = t['Resources']['WebServerGroup']['Properties'] @@ -1634,6 +1677,22 @@ class AutoScalingTest(HeatTestCase): expected_msg = "DesiredCapacity must be between MinSize and MaxSize" self.assertEqual(expected_msg, str(e)) + def test_invalid_desiredcapacity_zero(self): + t = template_format.parse(as_template) + properties = t['Resources']['WebServerGroup']['Properties'] + properties['MinSize'] = '1' + properties['MaxSize'] = '3' + properties['DesiredCapacity'] = '0' + + stack = utils.parse_stack(t, params=self.params) + + e = self.assertRaises(exception.StackValidationFailed, + self.create_scaling_group, t, + stack, 'WebServerGroup') + + expected_msg = "DesiredCapacity must be between MinSize and MaxSize" + self.assertEqual(expected_msg, str(e)) + class TestInstanceGroup(HeatTestCase): params = {'KeyName': 'test', 'ImageId': 'foo'}