diff --git a/heat/engine/resources/autoscaling.py b/heat/engine/resources/autoscaling.py index 26618b416..d634b69e5 100644 --- a/heat/engine/resources/autoscaling.py +++ b/heat/engine/resources/autoscaling.py @@ -15,6 +15,7 @@ from heat.common import exception from heat.engine import resource +from heat.engine import signal_responder from heat.engine import scheduler from heat.openstack.common import log as logging @@ -434,7 +435,7 @@ class LaunchConfiguration(resource.Resource): } -class ScalingPolicy(resource.Resource, CooldownMixin): +class ScalingPolicy(signal_responder.SignalResponder, CooldownMixin): properties_schema = { 'AutoScalingGroupName': {'Type': 'String', 'Required': True}, @@ -451,6 +452,10 @@ class ScalingPolicy(resource.Resource, CooldownMixin): update_allowed_keys = ('Properties',) update_allowed_properties = ('ScalingAdjustment', 'AdjustmentType', 'Cooldown',) + attributes_schema = { + "AlarmUrl": ("A signed url to handle the alarm. " + "(Heat extension)") + } def handle_update(self, json_snippet, tmpl_diff, prop_diff): # If Properties has changed, update self.properties, so we @@ -467,7 +472,7 @@ class ScalingPolicy(resource.Resource, CooldownMixin): (self.name, self.properties['Cooldown'])) return - group = self.stack.resources[self.properties['AutoScalingGroupName']] + group = self.stack[self.properties['AutoScalingGroupName']] logger.info('%s Alarm, adjusting Group %s by %s' % (self.name, group.name, @@ -479,6 +484,17 @@ class ScalingPolicy(resource.Resource, CooldownMixin): (self.properties['AdjustmentType'], self.properties['ScalingAdjustment'])) + def _resolve_attribute(self, name): + ''' + heat extension: "AlarmUrl" returns the url to post to the policy + when there is an alarm. + ''' + if name == 'AlarmUrl' and self.resource_id is not None: + return unicode(self._get_signed_url()) + + def FnGetRefId(self): + return unicode(self.name) + def resource_mapping(): return { diff --git a/heat/engine/resources/instance.py b/heat/engine/resources/instance.py index db56d0a84..2bc4bc0e2 100644 --- a/heat/engine/resources/instance.py +++ b/heat/engine/resources/instance.py @@ -22,6 +22,7 @@ from urlparse import urlparse from oslo.config import cfg +from heat.engine import signal_responder from heat.engine import clients from heat.engine import resource from heat.engine import scheduler @@ -37,9 +38,13 @@ from heat.openstack.common import uuidutils logger = logging.getLogger(__name__) -class Restarter(resource.Resource): +class Restarter(signal_responder.SignalResponder): properties_schema = {'InstanceId': {'Type': 'String', 'Required': True}} + attributes_schema = { + "AlarmUrl": ("A signed url to handle the alarm. " + "(Heat extension)") + } def _find_resource(self, resource_id): ''' @@ -63,6 +68,14 @@ class Restarter(resource.Resource): (self.name, victim.name)) self.stack.restart_resource(victim.name) + def _resolve_attribute(self, name): + ''' + heat extension: "AlarmUrl" returns the url to post to the policy + when there is an alarm. + ''' + if name == 'AlarmUrl' and self.resource_id is not None: + return unicode(self._get_signed_url()) + class Instance(resource.Resource): # AWS does not require InstanceType but Heat does because the nova diff --git a/heat/tests/test_autoscaling.py b/heat/tests/test_autoscaling.py index 5b7bc201b..73caffa93 100644 --- a/heat/tests/test_autoscaling.py +++ b/heat/tests/test_autoscaling.py @@ -17,6 +17,8 @@ import copy import mox +from oslo.config import cfg + from heat.common import template_format from heat.common import exception from heat.engine.resources import autoscaling as asc @@ -28,6 +30,7 @@ from heat.engine import scheduler from heat.engine.resource import Metadata from heat.openstack.common import timeutils from heat.tests.common import HeatTestCase +from heat.tests import fakes from heat.tests.utils import setup_dummy_db from heat.tests.utils import parse_stack @@ -99,6 +102,9 @@ class AutoScalingTest(HeatTestCase): def setUp(self): super(AutoScalingTest, self).setUp() setup_dummy_db() + cfg.CONF.set_default('heat_waitcondition_server_url', + 'http://127.0.0.1:8000/v1/waitcondition') + self.fc = fakes.FakeKeystoneClient() def create_scaling_group(self, t, stack, resource_name): rsrc = asc.AutoScalingGroup(resource_name, @@ -113,7 +119,6 @@ class AutoScalingTest(HeatTestCase): rsrc = asc.ScalingPolicy(resource_name, t['Resources'][resource_name], stack) - self.assertEqual(None, rsrc.validate()) scheduler.TaskRunner(rsrc.create)() self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) @@ -930,6 +935,7 @@ class AutoScalingTest(HeatTestCase): 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') stack.resources['WebServerGroup'] = rsrc @@ -939,9 +945,17 @@ class AutoScalingTest(HeatTestCase): self._stub_lb_reload(2) self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2) self._stub_create(1) + + self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone') + asc.ScalingPolicy.keystone().MultipleTimes().AndReturn( + self.fc) + self.m.ReplayAll() up_policy = self.create_scaling_policy(t, stack, 'WebServerScaleUpPolicy') + + alarm_url = up_policy.FnGetAtt('AlarmUrl') + self.assertNotEqual(None, alarm_url) up_policy.signal() self.assertEqual('WebServerGroup-0,WebServerGroup-1', rsrc.resource_id) @@ -969,6 +983,11 @@ class AutoScalingTest(HeatTestCase): # Scale down one self._stub_lb_reload(1) self._stub_meta_expected(now, 'ChangeInCapacity : -1', 2) + + self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone') + asc.ScalingPolicy.keystone().MultipleTimes().AndReturn( + self.fc) + self.m.ReplayAll() down_policy = self.create_scaling_policy(t, stack, 'WebServerScaleDownPolicy') @@ -996,6 +1015,11 @@ class AutoScalingTest(HeatTestCase): self._stub_lb_reload(2) self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2) self._stub_create(1) + + self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone') + asc.ScalingPolicy.keystone().MultipleTimes().AndReturn( + self.fc) + self.m.ReplayAll() up_policy = self.create_scaling_policy(t, stack, 'WebServerScaleUpPolicy') @@ -1047,6 +1071,11 @@ class AutoScalingTest(HeatTestCase): self._stub_lb_reload(2) self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2) self._stub_create(1) + + self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone') + asc.ScalingPolicy.keystone().MultipleTimes().AndReturn( + self.fc) + self.m.ReplayAll() up_policy = self.create_scaling_policy(t, stack, 'WebServerScaleUpPolicy') @@ -1099,6 +1128,11 @@ class AutoScalingTest(HeatTestCase): self._stub_lb_reload(2) self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2) self._stub_create(1) + + self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone') + asc.ScalingPolicy.keystone().MultipleTimes().AndReturn( + self.fc) + self.m.ReplayAll() up_policy = self.create_scaling_policy(t, stack, 'WebServerScaleUpPolicy') @@ -1151,6 +1185,11 @@ class AutoScalingTest(HeatTestCase): now = timeutils.utcnow() self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2) self._stub_create(1) + + self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone') + asc.ScalingPolicy.keystone().MultipleTimes().AndReturn( + self.fc) + self.m.ReplayAll() up_policy = self.create_scaling_policy(t, stack, 'WebServerScaleUpPolicy') @@ -1190,6 +1229,11 @@ class AutoScalingTest(HeatTestCase): now = timeutils.utcnow() self._stub_meta_expected(now, 'ExactCapacity : 1') self._stub_create(1) + + self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone') + asc.ScalingPolicy.keystone().MultipleTimes().AndReturn( + self.fc) + self.m.ReplayAll() rsrc = self.create_scaling_group(t, stack, 'WebServerGroup') stack.resources['WebServerGroup'] = rsrc