~ubuntu-branches/ubuntu/wily/heat/wily-proposed

« back to all changes in this revision

Viewing changes to heat/engine/resources/openstack/heat/scaling_policy.py

  • Committer: Package Import Robot
  • Author(s): James Page, Corey Bryant, James Page
  • Date: 2015-03-30 11:11:18 UTC
  • mfrom: (1.1.23)
  • Revision ID: package-import@ubuntu.com-20150330111118-2qpycylx6swu4yhj
Tags: 2015.1~b3-0ubuntu1
[ Corey Bryant ]
* New upstream milestone release for OpenStack kilo:
  - d/control: Align with upstream dependencies.
  - d/p/sudoers_patch.patch: Rebased.
  - d/p/fix-requirements.patch: Rebased.

[ James Page ]
* d/p/fixup-assert-regex.patch: Tweak test to use assertRegexpMatches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
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
 
5
#
 
6
#         http://www.apache.org/licenses/LICENSE-2.0
 
7
#
 
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
 
12
#    under the License.
 
13
 
 
14
from oslo_log import log as logging
 
15
import six
 
16
 
 
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
 
26
 
 
27
LOG = logging.getLogger(__name__)
 
28
 
 
29
 
 
30
class AutoScalingPolicy(signal_responder.SignalResponder,
 
31
                        cooldown.CooldownMixin):
 
32
    """A resource to manage scaling of `OS::Heat::AutoScalingGroup`.
 
33
 
 
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.
 
37
    """
 
38
    PROPERTIES = (
 
39
        AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
 
40
        COOLDOWN,
 
41
    ) = (
 
42
        'auto_scaling_group_id', 'scaling_adjustment', 'adjustment_type',
 
43
        'cooldown',
 
44
    )
 
45
 
 
46
    EXACT_CAPACITY, CHANGE_IN_CAPACITY, PERCENT_CHANGE_IN_CAPACITY = (
 
47
        'exact_capacity', 'change_in_capacity', 'percent_change_in_capacity')
 
48
 
 
49
    ATTRIBUTES = (
 
50
        ALARM_URL,
 
51
    ) = (
 
52
        'alarm_url',
 
53
    )
 
54
 
 
55
    properties_schema = {
 
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.'),
 
60
            required=True
 
61
        ),
 
62
        SCALING_ADJUSTMENT: properties.Schema(
 
63
            properties.Schema.NUMBER,
 
64
            _('Size of adjustment.'),
 
65
            required=True,
 
66
            update_allowed=True
 
67
        ),
 
68
        ADJUSTMENT_TYPE: properties.Schema(
 
69
            properties.Schema.STRING,
 
70
            _('Type of adjustment (absolute or percentage).'),
 
71
            required=True,
 
72
            constraints=[
 
73
                constraints.AllowedValues([CHANGE_IN_CAPACITY,
 
74
                                           EXACT_CAPACITY,
 
75
                                           PERCENT_CHANGE_IN_CAPACITY]),
 
76
            ],
 
77
            update_allowed=True
 
78
        ),
 
79
        COOLDOWN: properties.Schema(
 
80
            properties.Schema.NUMBER,
 
81
            _('Cooldown period, in seconds.'),
 
82
            update_allowed=True
 
83
        ),
 
84
    }
 
85
 
 
86
    attributes_schema = {
 
87
        ALARM_URL: attributes.Schema(
 
88
            _("A signed url to handle the alarm.")
 
89
        ),
 
90
    }
 
91
 
 
92
    def handle_create(self):
 
93
        super(AutoScalingPolicy, self).handle_create()
 
94
        self.resource_id_set(self._get_user_id())
 
95
 
 
96
    def handle_update(self, json_snippet, tmpl_diff, prop_diff):
 
97
        """
 
98
        If Properties has changed, update self.properties, so we get the new
 
99
        values during any subsequent adjustment.
 
100
        """
 
101
        if prop_diff:
 
102
            self.properties = json_snippet.properties(self.properties_schema,
 
103
                                                      self.context)
 
104
 
 
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('_')])
 
108
 
 
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
 
112
            raise Exception(msg)
 
113
 
 
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).
 
120
        #
 
121
        # our watchrule has upper case states so lower() them all.
 
122
        if details is None:
 
123
            alarm_state = 'alarm'
 
124
        else:
 
125
            alarm_state = details.get('current',
 
126
                                      details.get('state', 'alarm')).lower()
 
127
 
 
128
        LOG.info(_LI('Alarm %(name)s, new state %(state)s'),
 
129
                 {'name': self.name, 'state': alarm_state})
 
130
 
 
131
        if alarm_state != 'alarm':
 
132
            return
 
133
        if self._cooldown_inprogress():
 
134
            LOG.info(_LI("%(name)s NOT performing scaling action, "
 
135
                         "cooldown %(cooldown)s"),
 
136
                     {'name': self.name,
 
137
                      'cooldown': self.properties[self.COOLDOWN]})
 
138
            return
 
139
 
 
140
        asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
 
141
        group = self.stack.resource_by_refid(asgn_id)
 
142
        if group is None:
 
143
            raise exception.NotFound(_('Alarm %(alarm)s could not find '
 
144
                                       'scaling group named "%(group)s"') % {
 
145
                                           'alarm': self.name,
 
146
                                           'group': asgn_id})
 
147
 
 
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)
 
154
 
 
155
        self._cooldown_timestamp("%s : %s" %
 
156
                                 (self.properties[self.ADJUSTMENT_TYPE],
 
157
                                  self.properties[self.SCALING_ADJUSTMENT]))
 
158
 
 
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())
 
162
 
 
163
    def FnGetRefId(self):
 
164
        return resource.Resource.FnGetRefId(self)
 
165
 
 
166
 
 
167
def resource_mapping():
 
168
    return {
 
169
        'OS::Heat::ScalingPolicy': AutoScalingPolicy,
 
170
    }