2
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3
# not use this file except in compliance with the License. You may obtain
4
# a copy of the License at
6
# http://www.apache.org/licenses/LICENSE-2.0
8
# Unless required by applicable law or agreed to in writing, software
9
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
# License for the specific language governing permissions and limitations
14
from oslo_log import log as logging
17
from heat.common import exception
18
from heat.common.i18n import _
19
from heat.common.i18n import _LI
20
from heat.engine import attributes
21
from heat.engine import constraints
22
from heat.engine import properties
23
from heat.engine import resource
24
from heat.engine.resources import signal_responder
25
from heat.scaling import cooldown
27
LOG = logging.getLogger(__name__)
30
class AutoScalingPolicy(signal_responder.SignalResponder,
31
cooldown.CooldownMixin):
32
"""A resource to manage scaling of `OS::Heat::AutoScalingGroup`.
34
**Note** while it may incidentally support
35
`AWS::AutoScaling::AutoScalingGroup` for now, please don't use it for that
36
purpose and use `AWS::AutoScaling::ScalingPolicy` instead.
39
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
42
'auto_scaling_group_id', 'scaling_adjustment', 'adjustment_type',
46
EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
47
'exact_capacity', 'change_in_capacity', 'percent_change_in_capacity')
56
# TODO(Qiming): property name should be AUTO_SCALING_GROUP_ID
57
AUTO_SCALING_GROUP_NAME: properties.Schema(
58
properties.Schema.STRING,
59
_('AutoScaling group ID to apply policy to.'),
62
SCALING_ADJUSTMENT: properties.Schema(
63
properties.Schema.NUMBER,
64
_('Size of adjustment.'),
68
ADJUSTMENT_TYPE: properties.Schema(
69
properties.Schema.STRING,
70
_('Type of adjustment (absolute or percentage).'),
73
constraints.AllowedValues([CHANGE_IN_CAPACITY,
75
PERCENT_CHANGE_IN_CAPACITY]),
79
COOLDOWN: properties.Schema(
80
properties.Schema.NUMBER,
81
_('Cooldown period, in seconds.'),
87
ALARM_URL: attributes.Schema(
88
_("A signed url to handle the alarm.")
92
def handle_create(self):
93
super(AutoScalingPolicy, self).handle_create()
94
self.resource_id_set(self._get_user_id())
96
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
98
If Properties has changed, update self.properties, so we get the new
99
values during any subsequent adjustment.
102
self.properties = json_snippet.properties(self.properties_schema,
105
def _get_adjustement_type(self):
106
adjustment_type = self.properties[self.ADJUSTMENT_TYPE]
107
return ''.join([t.capitalize() for t in adjustment_type.split('_')])
109
def handle_signal(self, details=None):
110
if self.action in (self.SUSPEND, self.DELETE):
111
msg = _('Cannot signal resource during %s') % self.action
114
# ceilometer sends details like this:
115
# {u'alarm_id': ID, u'previous': u'ok', u'current': u'alarm',
116
# u'reason': u'...'})
117
# in this policy we currently assume that this gets called
118
# only when there is an alarm. But the template writer can
119
# put the policy in all the alarm notifiers (nodata, and ok).
121
# our watchrule has upper case states so lower() them all.
123
alarm_state = 'alarm'
125
alarm_state = details.get('current',
126
details.get('state', 'alarm')).lower()
128
LOG.info(_LI('Alarm %(name)s, new state %(state)s'),
129
{'name': self.name, 'state': alarm_state})
131
if alarm_state != 'alarm':
133
if self._cooldown_inprogress():
134
LOG.info(_LI("%(name)s NOT performing scaling action, "
135
"cooldown %(cooldown)s"),
137
'cooldown': self.properties[self.COOLDOWN]})
140
asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
141
group = self.stack.resource_by_refid(asgn_id)
143
raise exception.NotFound(_('Alarm %(alarm)s could not find '
144
'scaling group named "%(group)s"') % {
148
LOG.info(_LI('%(name)s Alarm, adjusting Group %(group)s with id '
149
'%(asgn_id)s by %(filter)s'),
150
{'name': self.name, 'group': group.name, 'asgn_id': asgn_id,
151
'filter': self.properties[self.SCALING_ADJUSTMENT]})
152
adjustment_type = self._get_adjustement_type()
153
group.adjust(self.properties[self.SCALING_ADJUSTMENT], adjustment_type)
155
self._cooldown_timestamp("%s : %s" %
156
(self.properties[self.ADJUSTMENT_TYPE],
157
self.properties[self.SCALING_ADJUSTMENT]))
159
def _resolve_attribute(self, name):
160
if name == self.ALARM_URL and self.resource_id is not None:
161
return six.text_type(self._get_signed_url())
163
def FnGetRefId(self):
164
return resource.Resource.FnGetRefId(self)
167
def resource_mapping():
169
'OS::Heat::ScalingPolicy': AutoScalingPolicy,