From a9176042e549c522de9166d593c8c6e5529b963d Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Fri, 28 Jun 2013 16:53:44 +0100 Subject: [PATCH] Add resume support to InstanceGroup Change-Id: I491bfd3475e12c2e5b8675d92d93f855b590423b blueprint: stack-suspend-resume --- heat/engine/resources/autoscaling.py | 14 ++++ heat/tests/test_autoscaling.py | 105 +++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/heat/engine/resources/autoscaling.py b/heat/engine/resources/autoscaling.py index a4f3518e..4b87b2ca 100644 --- a/heat/engine/resources/autoscaling.py +++ b/heat/engine/resources/autoscaling.py @@ -162,6 +162,20 @@ class InstanceGroup(resource.Resource): return False return True + def handle_resume(self): + cookie_list = [] + for inst in self._instances(): + logger.debug('handle_resume %s' % inst.name) + inst_cookie = inst.handle_resume() + cookie_list.append((inst, inst_cookie)) + return cookie_list + + def check_resume_complete(self, cookie_list): + for inst, inst_cookie in cookie_list: + if not inst.check_resume_complete(inst_cookie): + return False + return True + @scheduler.wrappertask def _scale(self, instance_task, indices): group = scheduler.PollingTaskGroup.from_task_with_args(instance_task, diff --git a/heat/tests/test_autoscaling.py b/heat/tests/test_autoscaling.py index 06ab59d6..2953cd33 100644 --- a/heat/tests/test_autoscaling.py +++ b/heat/tests/test_autoscaling.py @@ -253,6 +253,41 @@ class AutoScalingTest(HeatTestCase): rsrc.delete() self.m.VerifyAll() + def test_scaling_group_resume(self): + t = template_format.parse(as_template) + stack = parse_stack(t) + + self._stub_lb_reload(['WebServerGroup-0']) + 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('WebServerGroup', rsrc.FnGetRefId()) + self.assertEqual('WebServerGroup-0', rsrc.resource_id) + self.assertEqual(rsrc.state, (rsrc.CREATE, rsrc.COMPLETE)) + + self.m.VerifyAll() + self.m.UnsetStubs() + + self.m.StubOutWithMock(scheduler.TaskRunner, '_sleep') + self.m.StubOutWithMock(instance.Instance, 'handle_resume') + self.m.StubOutWithMock(instance.Instance, 'check_resume_complete') + inst_cookie = (object(), object(), object()) + instance.Instance.handle_resume().AndReturn(inst_cookie) + instance.Instance.check_resume_complete(inst_cookie).AndReturn(False) + instance.Instance.check_resume_complete(inst_cookie).AndReturn(True) + scheduler.TaskRunner._sleep(mox.IsA(int)).AndReturn(None) + self.m.ReplayAll() + + rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE) + + scheduler.TaskRunner(rsrc.resume)() + self.assertEqual(rsrc.state, (rsrc.RESUME, rsrc.COMPLETE)) + + rsrc.delete() + self.m.VerifyAll() + def test_scaling_group_suspend_multiple(self): t = template_format.parse(as_template) properties = t['Resources']['WebServerGroup']['Properties'] @@ -288,6 +323,43 @@ class AutoScalingTest(HeatTestCase): rsrc.delete() self.m.VerifyAll() + def test_scaling_group_resume_multiple(self): + t = template_format.parse(as_template) + properties = t['Resources']['WebServerGroup']['Properties'] + properties['DesiredCapacity'] = '2' + stack = parse_stack(t) + + self._stub_lb_reload(['WebServerGroup-0', 'WebServerGroup-1']) + now = timeutils.utcnow() + self._stub_meta_expected(now, 'ExactCapacity : 2') + self._stub_create(2) + self.m.ReplayAll() + rsrc = self.create_scaling_group(t, stack, 'WebServerGroup') + self.assertEqual('WebServerGroup', rsrc.FnGetRefId()) + self.assertEqual('WebServerGroup-0,WebServerGroup-1', rsrc.resource_id) + self.assertEqual(rsrc.state, (rsrc.CREATE, rsrc.COMPLETE)) + + self.m.VerifyAll() + self.m.UnsetStubs() + + self.m.StubOutWithMock(instance.Instance, 'handle_resume') + self.m.StubOutWithMock(instance.Instance, 'check_resume_complete') + inst_cookie1 = ('foo1', 'foo2', 'foo3') + inst_cookie2 = ('bar1', 'bar2', 'bar3') + instance.Instance.handle_resume().AndReturn(inst_cookie1) + instance.Instance.handle_resume().AndReturn(inst_cookie2) + instance.Instance.check_resume_complete(inst_cookie1).AndReturn(True) + instance.Instance.check_resume_complete(inst_cookie2).AndReturn(True) + self.m.ReplayAll() + + rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE) + + scheduler.TaskRunner(rsrc.resume)() + self.assertEqual(rsrc.state, (rsrc.RESUME, rsrc.COMPLETE)) + + rsrc.delete() + self.m.VerifyAll() + def test_scaling_group_suspend_fail(self): t = template_format.parse(as_template) stack = parse_stack(t) @@ -319,6 +391,39 @@ class AutoScalingTest(HeatTestCase): rsrc.delete() self.m.VerifyAll() + def test_scaling_group_resume_fail(self): + t = template_format.parse(as_template) + stack = parse_stack(t) + + self._stub_lb_reload(['WebServerGroup-0']) + 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('WebServerGroup', rsrc.FnGetRefId()) + self.assertEqual('WebServerGroup-0', rsrc.resource_id) + self.assertEqual(rsrc.state, (rsrc.CREATE, rsrc.COMPLETE)) + + self.m.VerifyAll() + self.m.UnsetStubs() + + self.m.StubOutWithMock(instance.Instance, 'handle_resume') + self.m.StubOutWithMock(instance.Instance, 'check_resume_complete') + inst_cookie = (object(), object(), object()) + instance.Instance.handle_resume().AndRaise(Exception('oops')) + self.m.ReplayAll() + + rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE) + + sus_task = scheduler.TaskRunner(rsrc.resume) + self.assertRaises(exception.ResourceFailure, sus_task, ()) + self.assertEqual(rsrc.state, (rsrc.RESUME, rsrc.FAILED)) + self.assertEqual(rsrc.status_reason, 'Exception: oops') + + rsrc.delete() + self.m.VerifyAll() + def test_scaling_group_create_error(self): t = template_format.parse(as_template) stack = parse_stack(t) -- 2.45.2