heat/heat/engine/resources/alarm_base.py

212 lines
7.6 KiB
Python

#
# 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.i18n import _
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
from heat.engine import support
COMMON_PROPERTIES = (
ALARM_ACTIONS, OK_ACTIONS, REPEAT_ACTIONS,
INSUFFICIENT_DATA_ACTIONS, DESCRIPTION, ENABLED, TIME_CONSTRAINTS,
SEVERITY,
) = (
'alarm_actions', 'ok_actions', 'repeat_actions',
'insufficient_data_actions', 'description', 'enabled', 'time_constraints',
'severity',
)
_TIME_CONSTRAINT_KEYS = (
NAME, START, DURATION, TIMEZONE, TIME_CONSTRAINT_DESCRIPTION,
) = (
'name', 'start', 'duration', 'timezone', 'description',
)
common_properties_schema = {
DESCRIPTION: properties.Schema(
properties.Schema.STRING,
_('Description for the alarm.'),
update_allowed=True
),
ENABLED: properties.Schema(
properties.Schema.BOOLEAN,
_('True if alarm evaluation/actioning is enabled.'),
default='true',
update_allowed=True
),
ALARM_ACTIONS: properties.Schema(
properties.Schema.LIST,
_('A list of URLs (webhooks) to invoke when state transitions to '
'alarm.'),
update_allowed=True
),
OK_ACTIONS: properties.Schema(
properties.Schema.LIST,
_('A list of URLs (webhooks) to invoke when state transitions to '
'ok.'),
update_allowed=True
),
INSUFFICIENT_DATA_ACTIONS: properties.Schema(
properties.Schema.LIST,
_('A list of URLs (webhooks) to invoke when state transitions to '
'insufficient-data.'),
update_allowed=True
),
REPEAT_ACTIONS: properties.Schema(
properties.Schema.BOOLEAN,
_("False to trigger actions when the threshold is reached AND "
"the alarm's state has changed. By default, actions are called "
"each time the threshold is reached."),
default='true',
update_allowed=True
),
SEVERITY: properties.Schema(
properties.Schema.STRING,
_('Severity of the alarm.'),
default='low',
constraints=[
constraints.AllowedValues(['low', 'moderate', 'critical'])
],
update_allowed=True,
support_status=support.SupportStatus(version='5.0.0'),
),
TIME_CONSTRAINTS: properties.Schema(
properties.Schema.LIST,
_('Describe time constraints for the alarm. '
'Only evaluate the alarm if the time at evaluation '
'is within this time constraint. Start point(s) of '
'the constraint are specified with a cron expression, '
'whereas its duration is given in seconds.'
),
schema=properties.Schema(
properties.Schema.MAP,
schema={
NAME: properties.Schema(
properties.Schema.STRING,
_("Name for the time constraint."),
required=True
),
START: properties.Schema(
properties.Schema.STRING,
_("Start time for the time constraint. "
"A CRON expression property."),
constraints=[
constraints.CustomConstraint(
'cron_expression')
],
required=True
),
TIME_CONSTRAINT_DESCRIPTION: properties.Schema(
properties.Schema.STRING,
_("Description for the time constraint."),
),
DURATION: properties.Schema(
properties.Schema.INTEGER,
_("Duration for the time constraint."),
constraints=[
constraints.Range(min=0)
],
required=True
),
TIMEZONE: properties.Schema(
properties.Schema.STRING,
_("Timezone for the time constraint "
"(eg. 'Taiwan/Taipei', 'Europe/Amsterdam')."),
constraints=[
constraints.CustomConstraint('timezone')
],
)
}
),
support_status=support.SupportStatus(version='5.0.0'),
default=[],
)
}
NOVA_METERS = ['instance', 'memory', 'memory.usage',
'cpu', 'cpu_util', 'vcpus',
'disk.read.requests', 'disk.read.requests.rate',
'disk.write.requests', 'disk.write.requests.rate',
'disk.read.bytes', 'disk.read.bytes.rate',
'disk.write.bytes', 'disk.write.bytes.rate',
'disk.device.read.requests', 'disk.device.read.requests.rate',
'disk.device.write.requests', 'disk.device.write.requests.rate',
'disk.device.read.bytes', 'disk.device.read.bytes.rate',
'disk.device.write.bytes', 'disk.device.write.bytes.rate',
'disk.root.size', 'disk.ephemeral.size',
'network.incoming.bytes', 'network.incoming.bytes.rate',
'network.outgoing.bytes', 'network.outgoing.bytes.rate',
'network.incoming.packets', 'network.incoming.packets.rate',
'network.outgoing.packets', 'network.outgoing.packets.rate']
class BaseAlarm(resource.Resource):
"""Base Alarm Manager."""
default_client_name = 'aodh'
entity = 'alarm'
alarm_type = 'threshold'
def actions_to_urls(self, props):
kwargs = {}
for k, v in iter(props.items()):
if k in [ALARM_ACTIONS, OK_ACTIONS,
INSUFFICIENT_DATA_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:
if act:
kwargs[k].append(act)
else:
kwargs[k] = v
return kwargs
def _reformat_properties(self, props):
rule = {}
for name in self.PROPERTIES:
value = props.pop(name, None)
if value:
rule[name] = value
if rule:
props['%s_rule' % self.alarm_type] = rule
return props
def handle_suspend(self):
if self.resource_id is not None:
alarm_update = {'enabled': False}
self.client().alarm.update(self.resource_id,
alarm_update)
def handle_resume(self):
if self.resource_id is not None:
alarm_update = {'enabled': True}
self.client().alarm.update(self.resource_id,
alarm_update)
def handle_check(self):
self.client().alarm.get(self.resource_id)