Merge "Add Alarm DB API and models"

This commit is contained in:
Jenkins 2013-05-06 10:28:24 +00:00 committed by Gerrit Code Review
commit 1667ded277
7 changed files with 218 additions and 0 deletions

View File

@ -137,6 +137,22 @@ class Connection(object):
The filter must have a meter value set.
"""
@abc.abstractmethod
def get_alarms(self, name=None, user=None,
project=None, enabled=True, alarm_id=None):
"""Yields a lists of alarms that match filters
"""
@abc.abstractmethod
def update_alarm(self, alarm):
"""update alarm
"""
@abc.abstractmethod
def delete_alarm(self, alarm_id):
"""Delete a alarm
"""
@abc.abstractmethod
def clear(self):
"""Clear database."""

View File

@ -494,6 +494,23 @@ class Connection(base.Connection):
self._update_meter_stats(results[-1], meter)
return results
def get_alarms(self, name=None, user=None,
project=None, enabled=True, alarm_id=None):
"""Yields a lists of alarms that match filters
raise NotImplementedError('metaquery not implemented')
"""
raise NotImplementedError('Alarms not implemented')
def update_alarm(self, alarm):
"""update alarm
"""
raise NotImplementedError('Alarms not implemented')
def delete_alarm(self, alarm_id):
"""Delete a alarm
"""
raise NotImplementedError('Alarms not implemented')
###############
# This is a very crude version of "in-memory HBase", which implements just

View File

@ -145,3 +145,18 @@ class Connection(base.Connection):
"""
return []
def get_alarms(self, name=None, user=None,
project=None, enabled=True, alarm_id=None):
"""Yields a lists of alarms that match filters
"""
return []
def update_alarm(self, alarm):
"""update alarm
"""
return alarm
def delete_alarm(self, alarm_id):
"""Delete a alarm
"""

View File

@ -506,6 +506,22 @@ class Connection(base.Connection):
a_max.valueOf() // 1000)
return (a_min, a_max)
def get_alarms(self, name=None, user=None,
project=None, enabled=True, alarm_id=None):
"""Yields a lists of alarms that match filters
"""
raise NotImplementedError('Alarms not implemented')
def update_alarm(self, alarm):
"""update alarm
"""
raise NotImplementedError('Alarms not implemented')
def delete_alarm(self, alarm_id):
"""Delete a alarm
"""
raise NotImplementedError('Alarms not implemented')
def require_map_reduce(conn):
"""Raises SkipTest if the connection is using mim.

View File

@ -411,3 +411,19 @@ class Connection(base.Connection):
period_start=period_start,
period_end=period_end,
)
def get_alarms(self, name=None, user=None,
project=None, enabled=True, alarm_id=None):
"""Yields a lists of alarms that match filters
"""
raise NotImplementedError('Alarms not implemented')
def update_alarm(self, alarm):
"""update alarm
"""
raise NotImplementedError('Alarms not implemented')
def delete_alarm(self, alarm_id):
"""Delete a alarm
"""
raise NotImplementedError('Alarms not implemented')

View File

@ -174,3 +174,78 @@ class Statistics(Model):
period_end=period_end, duration=duration,
duration_start=duration_start,
duration_end=duration_end)
class Alarm(Model):
ALARM_INSUFFICIENT_DATA = 'insufficient data'
ALARM_OK = 'ok'
ALARM_ALARM = 'alarm'
"""
An alarm to monitor.
:param alarm_id: UUID of the alarm
:param name: The Alarm name
:param description: User friendly description of the alarm
:param enabled: Is the alarm enabled
:param state: Alarm state (alarm/nodata/ok)
:param counter_name: The counter that the alarm is based on
:param comparison_operator: How to compare the samples and the threshold
:param threshold: the value to compare to the samples
:param statistic: the function from Statistic (min/max/avg/count)
:param user_id: the owner/creator of the alarm
:param project_id: the project_id of the creator
:param evaluation_periods: the number of periods
:param period: the time period in seconds
:param timestamp: the timestamp when the alarm was last updated
:param state_timestamp: the timestamp of the last state change
:param ok_actions: the list of webhooks to call when entering the ok state
:param alarm_actions: the list of webhooks to call when entering the
alarm state
:param insufficient_data_actions: the list of webhooks to call when
entering the insufficient data state
:param matching_metadata: the key/values of metadata to match on.
"""
def __init__(self, name, counter_name,
comparison_operator, threshold, statistic,
user_id, project_id,
evaluation_periods=1,
period=60,
alarm_id=None,
enabled=True,
description='',
timestamp=None,
state=ALARM_INSUFFICIENT_DATA,
state_timestamp=None,
ok_actions=[],
alarm_actions=[],
insufficient_data_actions=[],
matching_metadata={}
):
if not description:
# make a nice user friendly description by default
description = 'Alarm when %s is %s a %s of %s over %s seconds' % (
counter_name, comparison_operator,
statistic, threshold, period)
Model.__init__(
self,
alarm_id=alarm_id,
enabled=enabled,
name=name,
description=description,
timestamp=timestamp,
counter_name=counter_name,
user_id=user_id,
project_id=project_id,
comparison_operator=comparison_operator,
threshold=threshold,
statistic=statistic,
evaluation_periods=evaluation_periods,
period=period,
state=state,
state_timestamp=state_timestamp,
ok_actions=ok_actions,
alarm_actions=alarm_actions,
insufficient_data_actions=
insufficient_data_actions,
matching_metadata=matching_metadata)

View File

@ -583,3 +583,66 @@ class CounterDataTypeTest(DBTestBase):
)
results = list(self.conn.get_samples(f))
self.assertEqual(results[0].counter_volume, 1938495037.53697)
class AlarmTest(DBTestBase):
def test_empty(self):
alarms = list(self.conn.get_alarms())
self.assertEquals([], alarms)
def add_some_alarms(self):
alarms = [models.Alarm('red-alert',
'test.one', 'eq', 36, 'count',
'me', 'and-da-boys',
evaluation_periods=1,
period=60,
alarm_actions=['http://nowhere/alarms']),
models.Alarm('orange-alert',
'test.fourty', 'gt', 75, 'avg',
'me', 'and-da-boys',
period=60,
alarm_actions=['http://nowhere/alarms']),
models.Alarm('yellow-alert',
'test.five', 'lt', 10, 'min',
'me', 'and-da-boys',
alarm_actions=['http://nowhere/alarms'])]
for a in alarms:
self.conn.update_alarm(a)
def test_add(self):
self.add_some_alarms()
alarms = list(self.conn.get_alarms())
self.assertEquals(len(alarms), 3)
def test_defaults(self):
self.add_some_alarms()
yellow = list(self.conn.get_alarms(name='yellow-alert'))[0]
self.assertEquals(yellow.evaluation_periods, 1)
self.assertEquals(yellow.period, 60)
self.assertEquals(yellow.enabled, True)
self.assertEquals(yellow.description,
'Alarm when test.five is lt %s' %
'a min of 10 over 60 seconds')
self.assertEquals(yellow.state, models.Alarm.ALARM_INSUFFICIENT_DATA)
self.assertEquals(yellow.ok_actions, [])
self.assertEquals(yellow.insufficient_data_actions, [])
def test_update(self):
self.add_some_alarms()
orange = list(self.conn.get_alarms(name='orange-alert'))[0]
orange.enabled = False
orange.state = models.Alarm.ALARM_INSUFFICIENT_DATA
updated = self.conn.update_alarm(orange)
self.assertEquals(updated.enabled, False)
self.assertEquals(updated.state, models.Alarm.ALARM_INSUFFICIENT_DATA)
def test_delete(self):
self.add_some_alarms()
victim = list(self.conn.get_alarms(name='orange-alert'))[0]
self.conn.delete_alarm(victim.alarm_id)
survivors = list(self.conn.get_alarms())
self.assertEquals(len(survivors), 2)
for s in survivors:
self.assertNotEquals(victim.name, s.name)