Split scaling policy into separate files

A further step to split the AWS and the OS version of auto-scaling group
related classes.  This patch splits the scaling policy and launch
configuration into separate files.

This patch is not breaking any existing test cases. But more test cases
will be needed for the OS version scaling policy.

Implements: partial-blueprint reorg-asg-code
Change-Id: I0f888496d92b0efb5d63b567864488ff8a45e4ac
This commit is contained in:
tengqm 2014-08-27 11:40:22 +08:00
parent 78a6757d88
commit 91300e4069
7 changed files with 447 additions and 300 deletions

View File

@ -24,10 +24,8 @@ from heat.engine import environment
from heat.engine import function from heat.engine import function
from heat.engine.notification import autoscaling as notification from heat.engine.notification import autoscaling as notification
from heat.engine import properties from heat.engine import properties
from heat.engine import resource
from heat.engine import rsrc_defn from heat.engine import rsrc_defn
from heat.engine import scheduler from heat.engine import scheduler
from heat.engine import signal_responder
from heat.engine import stack_resource from heat.engine import stack_resource
from heat.openstack.common import excutils from heat.openstack.common import excutils
from heat.openstack.common import log as logging from heat.openstack.common import log as logging
@ -717,93 +715,6 @@ class AutoScalingGroup(InstanceGroup, cooldown.CooldownMixin):
return self._create_template(num_instances) return self._create_template(num_instances)
class LaunchConfiguration(resource.Resource):
PROPERTIES = (
IMAGE_ID, INSTANCE_TYPE, KEY_NAME, USER_DATA, SECURITY_GROUPS,
KERNEL_ID, RAM_DISK_ID, BLOCK_DEVICE_MAPPINGS, NOVA_SCHEDULER_HINTS,
) = (
'ImageId', 'InstanceType', 'KeyName', 'UserData', 'SecurityGroups',
'KernelId', 'RamDiskId', 'BlockDeviceMappings', 'NovaSchedulerHints',
)
_NOVA_SCHEDULER_HINT_KEYS = (
NOVA_SCHEDULER_HINT_KEY, NOVA_SCHEDULER_HINT_VALUE,
) = (
'Key', 'Value',
)
properties_schema = {
IMAGE_ID: properties.Schema(
properties.Schema.STRING,
_('Glance image ID or name.'),
required=True,
constraints=[
constraints.CustomConstraint('glance.image')
]
),
INSTANCE_TYPE: properties.Schema(
properties.Schema.STRING,
_('Nova instance type (flavor).'),
required=True
),
KEY_NAME: properties.Schema(
properties.Schema.STRING,
_('Optional Nova keypair name.'),
constraints=[
constraints.CustomConstraint("nova.keypair")
]
),
USER_DATA: properties.Schema(
properties.Schema.STRING,
_('User data to pass to instance.')
),
SECURITY_GROUPS: properties.Schema(
properties.Schema.LIST,
_('Security group names to assign.')
),
KERNEL_ID: properties.Schema(
properties.Schema.STRING,
_('Not Implemented.'),
implemented=False
),
RAM_DISK_ID: properties.Schema(
properties.Schema.STRING,
_('Not Implemented.'),
implemented=False
),
BLOCK_DEVICE_MAPPINGS: properties.Schema(
properties.Schema.STRING,
_('Not Implemented.'),
implemented=False
),
NOVA_SCHEDULER_HINTS: properties.Schema(
properties.Schema.LIST,
_('Scheduler hints to pass to Nova (Heat extension).'),
schema=properties.Schema(
properties.Schema.MAP,
schema={
NOVA_SCHEDULER_HINT_KEY: properties.Schema(
properties.Schema.STRING,
required=True
),
NOVA_SCHEDULER_HINT_VALUE: properties.Schema(
properties.Schema.STRING,
required=True
),
},
)
),
}
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
if 'Metadata' in tmpl_diff:
raise resource.UpdateReplace(self.name)
def FnGetRefId(self):
return self.physical_resource_name_or_FnGetRefId()
class AutoScalingResourceGroup(AutoScalingGroup): class AutoScalingResourceGroup(AutoScalingGroup):
"""An autoscaling group that can scale arbitrary resources.""" """An autoscaling group that can scale arbitrary resources."""
@ -940,219 +851,9 @@ class AutoScalingResourceGroup(AutoScalingGroup):
key=key) key=key)
class ScalingPolicy(signal_responder.SignalResponder, cooldown.CooldownMixin):
PROPERTIES = (
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
COOLDOWN,
) = (
'AutoScalingGroupName', 'ScalingAdjustment', 'AdjustmentType',
'Cooldown',
)
EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
'ExactCapacity', 'ChangeInCapacity', 'PercentChangeInCapacity')
ATTRIBUTES = (
ALARM_URL,
) = (
'AlarmUrl',
)
properties_schema = {
AUTO_SCALING_GROUP_NAME: properties.Schema(
properties.Schema.STRING,
_('AutoScaling group name to apply policy to.'),
required=True
),
SCALING_ADJUSTMENT: properties.Schema(
properties.Schema.NUMBER,
_('Size of adjustment.'),
required=True,
update_allowed=True
),
ADJUSTMENT_TYPE: properties.Schema(
properties.Schema.STRING,
_('Type of adjustment (absolute or percentage).'),
required=True,
constraints=[
constraints.AllowedValues([CHANGE_IN_CAPACITY,
EXACT_CAPACITY,
PERCENT_CHANGE_IN_CAPACITY]),
],
update_allowed=True
),
COOLDOWN: properties.Schema(
properties.Schema.NUMBER,
_('Cooldown period, in seconds.'),
update_allowed=True
),
}
attributes_schema = {
ALARM_URL: attributes.Schema(
_("A signed url to handle the alarm. (Heat extension).")
),
}
def handle_create(self):
super(ScalingPolicy, self).handle_create()
self.resource_id_set(self._get_user_id())
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
"""
If Properties has changed, update self.properties, so we get the new
values during any subsequent adjustment.
"""
if prop_diff:
self.properties = json_snippet.properties(self.properties_schema,
self.context)
def _get_adjustement_type(self):
return self.properties[self.ADJUSTMENT_TYPE]
def handle_signal(self, details=None):
if self.action in (self.SUSPEND, self.DELETE):
msg = _('Cannot signal resource during %s') % self.action
raise Exception(msg)
# ceilometer sends details like this:
# {u'alarm_id': ID, u'previous': u'ok', u'current': u'alarm',
# u'reason': u'...'})
# in this policy we currently assume that this gets called
# only when there is an alarm. But the template writer can
# put the policy in all the alarm notifiers (nodata, and ok).
#
# our watchrule has upper case states so lower() them all.
if details is None:
alarm_state = 'alarm'
else:
alarm_state = details.get('current',
details.get('state', 'alarm')).lower()
LOG.info(_('%(name)s Alarm, new state %(state)s')
% {'name': self.name, 'state': alarm_state})
if alarm_state != 'alarm':
return
if self._cooldown_inprogress():
LOG.info(_("%(name)s NOT performing scaling action, "
"cooldown %(cooldown)s")
% {'name': self.name,
'cooldown': self.properties[self.COOLDOWN]})
return
asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
group = self.stack.resource_by_refid(asgn_id)
if group is None:
raise exception.NotFound(_('Alarm %(alarm)s could not find '
'scaling group named "%(group)s"') % {
'alarm': self.name,
'group': asgn_id})
LOG.info(_('%(name)s Alarm, adjusting Group %(group)s with id '
'%(asgn_id)s by %(filter)s')
% {'name': self.name, 'group': group.name, 'asgn_id': asgn_id,
'filter': self.properties[self.SCALING_ADJUSTMENT]})
adjustment_type = self._get_adjustement_type()
group.adjust(self.properties[self.SCALING_ADJUSTMENT], adjustment_type)
self._cooldown_timestamp("%s : %s" %
(self.properties[self.ADJUSTMENT_TYPE],
self.properties[self.SCALING_ADJUSTMENT]))
def _resolve_attribute(self, name):
'''
heat extension: "AlarmUrl" returns the url to post to the policy
when there is an alarm.
'''
if name == self.ALARM_URL and self.resource_id is not None:
return unicode(self._get_signed_url())
def FnGetRefId(self):
if self.resource_id is not None:
return unicode(self._get_signed_url())
else:
return unicode(self.name)
class AutoScalingPolicy(ScalingPolicy):
"""A resource to manage scaling of `OS::Heat::AutoScalingGroup`.
**Note** while it may incidentally support
`AWS::AutoScaling::AutoScalingGroup` for now, please don't use it for that
purpose and use `AWS::AutoScaling::ScalingPolicy` instead.
"""
PROPERTIES = (
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
COOLDOWN,
) = (
'auto_scaling_group_id', 'scaling_adjustment', 'adjustment_type',
'cooldown',
)
EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
'exact_capacity', 'change_in_capacity', 'percent_change_in_capacity')
ATTRIBUTES = (
ALARM_URL,
) = (
'alarm_url',
)
properties_schema = {
AUTO_SCALING_GROUP_NAME: properties.Schema(
properties.Schema.STRING,
_('AutoScaling group ID to apply policy to.'),
required=True
),
SCALING_ADJUSTMENT: properties.Schema(
properties.Schema.NUMBER,
_('Size of adjustment.'),
required=True,
update_allowed=True
),
ADJUSTMENT_TYPE: properties.Schema(
properties.Schema.STRING,
_('Type of adjustment (absolute or percentage).'),
required=True,
constraints=[
constraints.AllowedValues([CHANGE_IN_CAPACITY,
EXACT_CAPACITY,
PERCENT_CHANGE_IN_CAPACITY]),
],
update_allowed=True
),
COOLDOWN: properties.Schema(
properties.Schema.NUMBER,
_('Cooldown period, in seconds.'),
update_allowed=True
),
}
attributes_schema = {
ALARM_URL: attributes.Schema(
_("A signed url to handle the alarm.")
),
}
def _get_adjustement_type(self):
adjustment_type = self.properties[self.ADJUSTMENT_TYPE]
return ''.join([t.capitalize() for t in adjustment_type.split('_')])
def _resolve_attribute(self, name):
if name == self.ALARM_URL and self.resource_id is not None:
return unicode(self._get_signed_url())
def FnGetRefId(self):
return resource.Resource.FnGetRefId(self)
def resource_mapping(): def resource_mapping():
return { return {
'AWS::AutoScaling::LaunchConfiguration': LaunchConfiguration,
'AWS::AutoScaling::AutoScalingGroup': AutoScalingGroup, 'AWS::AutoScaling::AutoScalingGroup': AutoScalingGroup,
'AWS::AutoScaling::ScalingPolicy': ScalingPolicy,
'OS::Heat::InstanceGroup': InstanceGroup, 'OS::Heat::InstanceGroup': InstanceGroup,
'OS::Heat::AutoScalingGroup': AutoScalingResourceGroup, 'OS::Heat::AutoScalingGroup': AutoScalingResourceGroup,
'OS::Heat::ScalingPolicy': AutoScalingPolicy,
} }

View File

View File

@ -0,0 +1,114 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
from heat.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class LaunchConfiguration(resource.Resource):
PROPERTIES = (
IMAGE_ID, INSTANCE_TYPE, KEY_NAME, USER_DATA, SECURITY_GROUPS,
KERNEL_ID, RAM_DISK_ID, BLOCK_DEVICE_MAPPINGS, NOVA_SCHEDULER_HINTS,
) = (
'ImageId', 'InstanceType', 'KeyName', 'UserData', 'SecurityGroups',
'KernelId', 'RamDiskId', 'BlockDeviceMappings', 'NovaSchedulerHints',
)
_NOVA_SCHEDULER_HINT_KEYS = (
NOVA_SCHEDULER_HINT_KEY, NOVA_SCHEDULER_HINT_VALUE,
) = (
'Key', 'Value',
)
properties_schema = {
IMAGE_ID: properties.Schema(
properties.Schema.STRING,
_('Glance image ID or name.'),
required=True,
constraints=[
constraints.CustomConstraint('glance.image')
]
),
INSTANCE_TYPE: properties.Schema(
properties.Schema.STRING,
_('Nova instance type (flavor).'),
required=True
),
KEY_NAME: properties.Schema(
properties.Schema.STRING,
_('Optional Nova keypair name.'),
constraints=[
constraints.CustomConstraint("nova.keypair")
]
),
USER_DATA: properties.Schema(
properties.Schema.STRING,
_('User data to pass to instance.')
),
SECURITY_GROUPS: properties.Schema(
properties.Schema.LIST,
_('Security group names to assign.')
),
KERNEL_ID: properties.Schema(
properties.Schema.STRING,
_('Not Implemented.'),
implemented=False
),
RAM_DISK_ID: properties.Schema(
properties.Schema.STRING,
_('Not Implemented.'),
implemented=False
),
BLOCK_DEVICE_MAPPINGS: properties.Schema(
properties.Schema.STRING,
_('Not Implemented.'),
implemented=False
),
NOVA_SCHEDULER_HINTS: properties.Schema(
properties.Schema.LIST,
_('Scheduler hints to pass to Nova (Heat extension).'),
schema=properties.Schema(
properties.Schema.MAP,
schema={
NOVA_SCHEDULER_HINT_KEY: properties.Schema(
properties.Schema.STRING,
required=True
),
NOVA_SCHEDULER_HINT_VALUE: properties.Schema(
properties.Schema.STRING,
required=True
),
},
)
),
}
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
if 'Metadata' in tmpl_diff:
raise resource.UpdateReplace(self.name)
def FnGetRefId(self):
return self.physical_resource_name_or_FnGetRefId()
def resource_mapping():
return {
'AWS::AutoScaling::LaunchConfiguration': LaunchConfiguration,
}

View File

@ -0,0 +1,165 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from heat.common import exception
from heat.engine import attributes
from heat.engine import constraints
from heat.engine import properties
from heat.engine import signal_responder
from heat.openstack.common import log as logging
from heat.scaling import cooldown
LOG = logging.getLogger(__name__)
class AWSScalingPolicy(signal_responder.SignalResponder,
cooldown.CooldownMixin):
PROPERTIES = (
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
COOLDOWN,
) = (
'AutoScalingGroupName', 'ScalingAdjustment', 'AdjustmentType',
'Cooldown',
)
EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
'ExactCapacity', 'ChangeInCapacity', 'PercentChangeInCapacity')
ATTRIBUTES = (
ALARM_URL,
) = (
'AlarmUrl',
)
properties_schema = {
AUTO_SCALING_GROUP_NAME: properties.Schema(
properties.Schema.STRING,
_('AutoScaling group name to apply policy to.'),
required=True
),
SCALING_ADJUSTMENT: properties.Schema(
properties.Schema.NUMBER,
_('Size of adjustment.'),
required=True,
update_allowed=True
),
ADJUSTMENT_TYPE: properties.Schema(
properties.Schema.STRING,
_('Type of adjustment (absolute or percentage).'),
required=True,
constraints=[
constraints.AllowedValues([CHANGE_IN_CAPACITY,
EXACT_CAPACITY,
PERCENT_CHANGE_IN_CAPACITY]),
],
update_allowed=True
),
COOLDOWN: properties.Schema(
properties.Schema.NUMBER,
_('Cooldown period, in seconds.'),
update_allowed=True
),
}
attributes_schema = {
ALARM_URL: attributes.Schema(
_("A signed url to handle the alarm. (Heat extension).")
),
}
def handle_create(self):
super(AWSScalingPolicy, self).handle_create()
self.resource_id_set(self._get_user_id())
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
"""
If Properties has changed, update self.properties, so we get the new
values during any subsequent adjustment.
"""
if prop_diff:
self.properties = json_snippet.properties(self.properties_schema,
self.context)
def _get_adjustement_type(self):
return self.properties[self.ADJUSTMENT_TYPE]
def handle_signal(self, details=None):
if self.action in (self.SUSPEND, self.DELETE):
msg = _('Cannot signal resource during %s') % self.action
raise Exception(msg)
# ceilometer sends details like this:
# {u'alarm_id': ID, u'previous': u'ok', u'current': u'alarm',
# u'reason': u'...'})
# in this policy we currently assume that this gets called
# only when there is an alarm. But the template writer can
# put the policy in all the alarm notifiers (nodata, and ok).
#
# our watchrule has upper case states so lower() them all.
if details is None:
alarm_state = 'alarm'
else:
alarm_state = details.get('current',
details.get('state', 'alarm')).lower()
LOG.info(_('%(name)s Alarm, new state %(state)s')
% {'name': self.name, 'state': alarm_state})
if alarm_state != 'alarm':
return
if self._cooldown_inprogress():
LOG.info(_("%(name)s NOT performing scaling action, "
"cooldown %(cooldown)s")
% {'name': self.name,
'cooldown': self.properties[self.COOLDOWN]})
return
asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
group = self.stack.resource_by_refid(asgn_id)
if group is None:
raise exception.NotFound(_('Alarm %(alarm)s could not find '
'scaling group named "%(group)s"') % {
'alarm': self.name,
'group': asgn_id})
LOG.info(_('%(name)s Alarm, adjusting Group %(group)s with id '
'%(asgn_id)s by %(filter)s')
% {'name': self.name, 'group': group.name, 'asgn_id': asgn_id,
'filter': self.properties[self.SCALING_ADJUSTMENT]})
adjustment_type = self._get_adjustement_type()
group.adjust(self.properties[self.SCALING_ADJUSTMENT], adjustment_type)
self._cooldown_timestamp("%s : %s" %
(self.properties[self.ADJUSTMENT_TYPE],
self.properties[self.SCALING_ADJUSTMENT]))
def _resolve_attribute(self, name):
'''
heat extension: "AlarmUrl" returns the url to post to the policy
when there is an alarm.
'''
if name == self.ALARM_URL and self.resource_id is not None:
return unicode(self._get_signed_url())
def FnGetRefId(self):
if self.resource_id is not None:
return unicode(self._get_signed_url())
else:
return unicode(self.name)
def resource_mapping():
return {
'AWS::AutoScaling::ScalingPolicy': AWSScalingPolicy,
}

View File

@ -0,0 +1,167 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from heat.common import exception
from heat.engine import attributes
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
from heat.engine import signal_responder
from heat.scaling import cooldown
from heat.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class AutoScalingPolicy(signal_responder.SignalResponder,
cooldown.CooldownMixin):
"""A resource to manage scaling of `OS::Heat::AutoScalingGroup`.
**Note** while it may incidentally support
`AWS::AutoScaling::AutoScalingGroup` for now, please don't use it for that
purpose and use `AWS::AutoScaling::ScalingPolicy` instead.
"""
PROPERTIES = (
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
COOLDOWN,
) = (
'auto_scaling_group_id', 'scaling_adjustment', 'adjustment_type',
'cooldown',
)
EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
'exact_capacity', 'change_in_capacity', 'percent_change_in_capacity')
ATTRIBUTES = (
ALARM_URL,
) = (
'alarm_url',
)
properties_schema = {
# TODO(Qiming): property name should be AUTO_SCALING_GROUP_ID
AUTO_SCALING_GROUP_NAME: properties.Schema(
properties.Schema.STRING,
_('AutoScaling group ID to apply policy to.'),
required=True
),
SCALING_ADJUSTMENT: properties.Schema(
properties.Schema.NUMBER,
_('Size of adjustment.'),
required=True,
update_allowed=True
),
ADJUSTMENT_TYPE: properties.Schema(
properties.Schema.STRING,
_('Type of adjustment (absolute or percentage).'),
required=True,
constraints=[
constraints.AllowedValues([CHANGE_IN_CAPACITY,
EXACT_CAPACITY,
PERCENT_CHANGE_IN_CAPACITY]),
],
update_allowed=True
),
COOLDOWN: properties.Schema(
properties.Schema.NUMBER,
_('Cooldown period, in seconds.'),
update_allowed=True
),
}
attributes_schema = {
ALARM_URL: attributes.Schema(
_("A signed url to handle the alarm.")
),
}
def handle_create(self):
super(AutoScalingPolicy, self).handle_create()
self.resource_id_set(self._get_user_id())
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
"""
If Properties has changed, update self.properties, so we get the new
values during any subsequent adjustment.
"""
if prop_diff:
self.properties = json_snippet.properties(self.properties_schema,
self.context)
def _get_adjustement_type(self):
adjustment_type = self.properties[self.ADJUSTMENT_TYPE]
return ''.join([t.capitalize() for t in adjustment_type.split('_')])
def handle_signal(self, details=None):
if self.action in (self.SUSPEND, self.DELETE):
msg = _('Cannot signal resource during %s') % self.action
raise Exception(msg)
# ceilometer sends details like this:
# {u'alarm_id': ID, u'previous': u'ok', u'current': u'alarm',
# u'reason': u'...'})
# in this policy we currently assume that this gets called
# only when there is an alarm. But the template writer can
# put the policy in all the alarm notifiers (nodata, and ok).
#
# our watchrule has upper case states so lower() them all.
if details is None:
alarm_state = 'alarm'
else:
alarm_state = details.get('current',
details.get('state', 'alarm')).lower()
LOG.info(_('Alarm %(name)s, new state %(state)s')
% {'name': self.name, 'state': alarm_state})
if alarm_state != 'alarm':
return
if self._cooldown_inprogress():
LOG.info(_("%(name)s NOT performing scaling action, "
"cooldown %(cooldown)s")
% {'name': self.name,
'cooldown': self.properties[self.COOLDOWN]})
return
asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
group = self.stack.resource_by_refid(asgn_id)
if group is None:
raise exception.NotFound(_('Alarm %(alarm)s could not find '
'scaling group named "%(group)s"') % {
'alarm': self.name,
'group': asgn_id})
LOG.info(_('%(name)s Alarm, adjusting Group %(group)s with id '
'%(asgn_id)s by %(filter)s')
% {'name': self.name, 'group': group.name, 'asgn_id': asgn_id,
'filter': self.properties[self.SCALING_ADJUSTMENT]})
adjustment_type = self._get_adjustement_type()
group.adjust(self.properties[self.SCALING_ADJUSTMENT], adjustment_type)
self._cooldown_timestamp("%s : %s" %
(self.properties[self.ADJUSTMENT_TYPE],
self.properties[self.SCALING_ADJUSTMENT]))
def _resolve_attribute(self, name):
if name == self.ALARM_URL and self.resource_id is not None:
return unicode(self._get_signed_url())
def FnGetRefId(self):
return resource.Resource.FnGetRefId(self)
def resource_mapping():
return {
'OS::Heat::ScalingPolicy': AutoScalingPolicy,
}

View File

@ -323,7 +323,7 @@ class HeatScalingGroupWithCFNScalingPolicyTest(HeatTestCase):
class ScalingPolicyTest(HeatTestCase): class ScalingPolicyTest(HeatTestCase):
# TODO(Qiming): Add more tests to the scaling policy
as_template = ''' as_template = '''
heat_template_version: 2013-05-23 heat_template_version: 2013-05-23
resources: resources: