135 lines
5.9 KiB
Python
135 lines
5.9 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
#
|
|
# 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 resource
|
|
from heat.engine import watchrule
|
|
|
|
|
|
class CeilometerAlarm(resource.Resource):
|
|
|
|
properties_schema = {'comparison_operator': {'Type': 'String',
|
|
'Required': True,
|
|
'AllowedValues': ['ge',
|
|
'gt',
|
|
'eq',
|
|
'ne',
|
|
'lt',
|
|
'le']},
|
|
'evaluation_periods': {'Type': 'String',
|
|
'Required': True},
|
|
'counter_name': {'Type': 'String',
|
|
'Required': True},
|
|
'period': {'Type': 'String',
|
|
'Required': True},
|
|
'statistic': {'Type': 'String',
|
|
'Required': True,
|
|
'AllowedValues': ['count',
|
|
'avg',
|
|
'sum',
|
|
'min',
|
|
'max']},
|
|
'threshold': {'Type': 'String',
|
|
'Required': True},
|
|
'alarm_actions': {'Type': 'List'},
|
|
'ok_actions': {'Type': 'List'},
|
|
'insufficient_data_actions': {'Type': 'List'},
|
|
'description': {'Type': 'String'},
|
|
'source': {'Type': 'String'},
|
|
'enabled': {'Type': 'Boolean',
|
|
'Default': 'true'},
|
|
'matching_metadata': {'Type': 'Map'}}
|
|
|
|
update_allowed_keys = ('Properties',)
|
|
# allow the properties that affect the watch calculation.
|
|
# note: when using in-instance monitoring you can only change the
|
|
# metric name if you re-configure the instance too.
|
|
update_allowed_properties = ('comparison_operator', 'description',
|
|
'evaluation_periods', 'period', 'statistic',
|
|
'alarm_actions', 'ok_actions',
|
|
'insufficient_data_actions', 'threshold',
|
|
'enabled')
|
|
|
|
def _actions_to_urls(self, props):
|
|
kwargs = {}
|
|
for k, v in iter(props.items()):
|
|
if k.endswith('_actions') and v is not None:
|
|
kwargs[k] = []
|
|
for act in v:
|
|
# if the action is a resource name
|
|
# we ask the destination resource for an alarm url.
|
|
# the template writer should really do this in the
|
|
# template if possible with:
|
|
# {Fn::GetAtt: ['MyAction', 'AlarmUrl']}
|
|
if act in self.stack:
|
|
url = self.stack[act].FnGetAtt('AlarmUrl')
|
|
kwargs[k].append(url)
|
|
else:
|
|
kwargs[k].append(act)
|
|
else:
|
|
kwargs[k] = v
|
|
return kwargs
|
|
|
|
def handle_create(self):
|
|
props = self._actions_to_urls(self.parsed_template('Properties'))
|
|
props['name'] = self.physical_resource_name()
|
|
|
|
alarm = self.ceilometer().alarms.create(**props)
|
|
self.resource_id_set(alarm.alarm_id)
|
|
|
|
# the watchrule below is for backwards compatibility.
|
|
# 1) so we don't create watch tasks unneccessarly
|
|
# 2) to support CW stats post, we will redirect the request
|
|
# to ceilometer.
|
|
wr = watchrule.WatchRule(context=self.context,
|
|
watch_name=self.physical_resource_name(),
|
|
rule=self.parsed_template('Properties'),
|
|
stack_id=self.stack.id)
|
|
wr.state = wr.CEILOMETER_CONTROLLED
|
|
wr.store()
|
|
|
|
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
|
if prop_diff:
|
|
kwargs = {'alarm_id': self.resource_id}
|
|
kwargs.update(prop_diff)
|
|
self.ceilometer().alarms.update(**self._actions_to_urls(kwargs))
|
|
|
|
def handle_suspend(self):
|
|
if self.resource_id is not None:
|
|
self.ceilometer().alarms.update(alarm_id=self.resource_id,
|
|
enabled=False)
|
|
|
|
def handle_resume(self):
|
|
if self.resource_id is not None:
|
|
self.ceilometer().alarms.update(alarm_id=self.resource_id,
|
|
enabled=True)
|
|
|
|
def handle_delete(self):
|
|
try:
|
|
wr = watchrule.WatchRule.load(
|
|
self.context, watch_name=self.physical_resource_name())
|
|
wr.destroy()
|
|
except exception.WatchRuleNotFound:
|
|
pass
|
|
|
|
if self.resource_id is not None:
|
|
self.ceilometer().alarms.delete(self.resource_id)
|
|
|
|
|
|
def resource_mapping():
|
|
return {
|
|
'OS::Ceilometer::Alarm': CeilometerAlarm,
|
|
}
|