Ceilometer/blueprints/alarm-api

AlarmController
class AlarmController(rest.RestController): """Manages operations on a single alarm.   """

@wsme_pecan.wsexpose(Alarm, wtypes.text) def get(self): """Return this alarm."""

@wsme.validate(Alarm) @wsme_pecan.wsexpose(Alarm, wtypes.text, body=Alarm) def put(self, data): """Modify this alarm."""

@wsme_pecan.wsexpose(None, wtypes.text, status_code=204) def delete(self): """Delete this alarm."""

# TODO(eglynn): add pagination marker to signature once overall #              API support for pagination is finalized @wsme_pecan.wsexpose([AlarmChange], [Query]) def history(self, q=[]): """Assembles the alarm history requested.

"""

AlarmsController
class AlarmsController(rest.RestController): """Manages operations on the alarms collection.   """

@wsme.validate(Alarm) @wsme_pecan.wsexpose(Alarm, body=Alarm, status_code=201) def post(self, data): """Create a new alarm."""

@wsme_pecan.wsexpose([Alarm], [Query]) def get_all(self, q=[]): """Return all alarms, based on the query provided.

"""

Alarm class
class Alarm(_Base): """Representation of an alarm.   """

alarm_id = wtypes.text "The UUID of the alarm"

name = wtypes.text "The name for the alarm"

description = wtypes.text "The description of the alarm"

meter_name = wtypes.text "The name of meter"

project_id = wtypes.text "The ID of the project or tenant that owns the alarm"

user_id = wtypes.text "The ID of the user who created the alarm"

comparison_operator = wtypes.Enum(str, 'lt', 'le', 'eq', 'ne', 'ge', 'gt') "The comparison against the alarm threshold"

threshold = float "The threshold of the alarm"

statistic = wtypes.Enum(str, 'max', 'min', 'avg', 'sum', 'count') "The statistic to compare to the threshold"

enabled = bool "This alarm is enabled?"

evaluation_periods = int "The number of periods to evaluate the threshold"

period = int "The time range in seconds over which to evaluate the threshold"

timestamp = datetime.datetime "The date of the last alarm definition update"

state = wtypes.Enum(str, 'ok', 'alarm', 'insufficient data') "The state offset the alarm"

state_timestamp = datetime.datetime "The date of the last alarm state changed"

ok_actions = [wtypes.text] "The actions to do when alarm state change to ok"

alarm_actions = [wtypes.text] "The actions to do when alarm state change to alarm"

insufficient_data_actions = [wtypes.text] "The actions to do when alarm state change to insufficient data"

repeat_actions = bool "The actions should be re-triggered on each evaluation cycle"

matching_metadata = {wtypes.text: wtypes.text} "The matching_metadata of the alarm"

Alarm State Enum
This enum is reused in a couple of places.

AlarmState = wtypes.Enum(wtypes.text, 'ok', 'alarm', 'insufficient_data')

AlarmThresholdRule
Collect the arguments for defining a rule based on a statistics value reaching a threshold.

class AlarmThresholdRule(_Base):

query = [Query] "The query to find the data for computing statistics, including meter_name. Ownership settings are automatically included based on the Alarm owner."

period = int "The time range in seconds over which query"

comparison_operator = wtypes.Enum(str, 'lt', 'le', 'eq', 'ne', 'ge', 'gt') "The comparison against the alarm threshold"

threshold = float "The threshold of the alarm"

statistic = wtypes.Enum(str, 'max', 'min', 'avg', 'sum', 'count') "The statistic to compare to the threshold"

evaluation_periods = int "The number of historical periods to evaluate the threshold"

AlarmCombinationRule
Collect the settings related to combining multiple alarms.

class AlarmCombinationRule(_Base):

operator = wtypes.Enum(str, 'or', 'and') "How to combine the sub-alarms"

alarm_ids = [wtypes.text] "List of alarm identifiers to combine"

Alarm
The parent data structure.

class Alarm(_Base): """Representation of an alarm.   """

alarm_id = wtypes.text "The UUID of the alarm"

name = wtypes.text "The name for the alarm"

description = wtypes.text "The description of the alarm"

enabled = bool "This alarm is enabled?"

ok_actions = [wtypes.text] "The actions to do when alarm state change to ok"

alarm_actions = [wtypes.text] "The actions to do when alarm state change to alarm"

insufficient_data_actions = [wtypes.text] "The actions to do when alarm state change to insufficient data"

repeat_actions = bool "The actions should be re-triggered on each evaluation cycle"

type = Enum(str, 'threshold', 'combination') "Explicit type specifier to select which rule to follow below."

threshold_rule = AlarmThresholdRule "Describe when to trigger the alarm based on computed statistics"

combination_rule = AlarmCombinationRule "Describe when to trigger the alarm based on combining the settings of other alarms"

# These settings are ignored in the the PUT or POST operations, but are filled in for GET

project_id = wtypes.text "The ID of the project or tenant that owns the alarm"

user_id = wtypes.text "The ID of the user who created the alarm"

timestamp = datetime.datetime "The date of the last alarm definition update"

# FIXME: Add an explicit "set_state" operation instead of    # forcing the caller to PUT the entire definition of the alarm to test it. state = alarm_states "The current state of the alarm"

state_timestamp = datetime.datetime "The date of the last alarm state changed"

Rejected Alternatives
These options were considered but rejected.

Unified Rule Spec
Unfortunately, there is not much in common between the two rule types. An alternative format for the rule specification is to encode the settings as a list of arguments, but that does not offer the caller any help about which arguments are needed when.

class Rule(_Base):

type = wtypes.Enum(str, 'threshold', 'combination')

operator = wtypes.Enum(str, 'lt', 'le', 'eq', 'ne', 'ge', 'gt', 'in')

arguments = [wtypes.text]

DSL
If we want to get much more complicated, we should consider creating a domain-specific-language and having the alarm rules described as a block of text containing that DSL. We could document the DSL, and it wouldn't need to have a complex syntax. For example, it could be line oriented, use whitespace to separate expressions, etc.

query field1 >= blah field2 == value threshold min > 0 or max < 100

combination alarm1 and alarm2

AlarmAction class
Unify all of the actions into a single class with a state and a URL, instead of keeping 3 separate lists.

class AlarmAction(_Base): """Action to take when alarm changes state.  """

state = AlarmState "The state for which the action applies."

url = wtypes.text "The URL to visit when the alarm state is reached"