alarm: generate alarm_id in API

This isn't a detail of the storage, this is something we handle and
expose in the API, so the responsability for handling should be in the
API.
Also, they shouldn't exist any alarm without an id, so the model makes
it mandatory now.

Change-Id: I726ca74489007ee1d387bcb06b23af2f060ceb5f
This commit is contained in:
Julien Danjou 2013-08-28 17:01:53 +02:00
parent bd9b26e757
commit 5d5f70e085
11 changed files with 54 additions and 37 deletions

View File

@ -34,6 +34,7 @@
import ast import ast
import datetime import datetime
import inspect import inspect
import uuid
import pecan import pecan
from pecan import rest from pecan import rest
@ -1016,9 +1017,9 @@ class AlarmsController(rest.RestController):
"""Create a new alarm.""" """Create a new alarm."""
conn = pecan.request.storage_conn conn = pecan.request.storage_conn
data.alarm_id = str(uuid.uuid4())
data.user_id = pecan.request.headers.get('X-User-Id') data.user_id = pecan.request.headers.get('X-User-Id')
data.project_id = pecan.request.headers.get('X-Project-Id') data.project_id = pecan.request.headers.get('X-Project-Id')
data.alarm_id = wsme.Unset
data.state_timestamp = wsme.Unset data.state_timestamp = wsme.Unset
data.timestamp = timeutils.utcnow() data.timestamp = timeutils.utcnow()
@ -1039,7 +1040,7 @@ class AlarmsController(rest.RestController):
pecan.response.translatable_error = error pecan.response.translatable_error = error
raise wsme.exc.ClientSideError(error) raise wsme.exc.ClientSideError(error)
alarm = conn.update_alarm(alarm_in) alarm = conn.create_alarm(alarm_in)
return Alarm.from_db_model(alarm) return Alarm.from_db_model(alarm)
@wsme_pecan.wsexpose([Alarm], [Query]) @wsme_pecan.wsexpose([Alarm], [Query])

View File

@ -188,6 +188,13 @@ class Connection(object):
"""Yields a lists of alarms that match filters """Yields a lists of alarms that match filters
""" """
@abc.abstractmethod
def create_alarm(self, alarm):
"""Create an alarm. Returns the alarm as created.
:param alarm: The alarm to create.
"""
@abc.abstractmethod @abc.abstractmethod
def update_alarm(self, alarm): def update_alarm(self, alarm):
"""update alarm """update alarm

View File

@ -22,7 +22,6 @@
""" """
import copy import copy
import uuid
import weakref import weakref
import bson.code import bson.code
@ -595,9 +594,6 @@ class Connection(base.Connection):
def update_alarm(self, alarm): def update_alarm(self, alarm):
"""update alarm """update alarm
""" """
if alarm.alarm_id is None:
# This is an insert, generate an id
alarm.alarm_id = str(uuid.uuid1())
data = alarm.as_dict() data = alarm.as_dict()
data['matching_metadata'] = \ data['matching_metadata'] = \
self._encode_matching_metadata(data['matching_metadata']) self._encode_matching_metadata(data['matching_metadata'])
@ -613,6 +609,8 @@ class Connection(base.Connection):
self._decode_matching_metadata(stored_alarm['matching_metadata']) self._decode_matching_metadata(stored_alarm['matching_metadata'])
return models.Alarm(**stored_alarm) return models.Alarm(**stored_alarm)
create_alarm = update_alarm
def delete_alarm(self, alarm_id): def delete_alarm(self, alarm_id):
"""Delete an alarm """Delete an alarm
""" """

View File

@ -599,6 +599,11 @@ class Connection(base.Connection):
""" """
raise NotImplementedError('Alarms not implemented') raise NotImplementedError('Alarms not implemented')
def create_alarm(self, alarm):
"""update alarm
"""
raise NotImplementedError('Alarms not implemented')
def update_alarm(self, alarm): def update_alarm(self, alarm):
"""update alarm """update alarm
""" """

View File

@ -161,6 +161,11 @@ class Connection(base.Connection):
""" """
return [] return []
def create_alarm(self, alarm):
"""Create alarm.
"""
return alarm
def update_alarm(self, alarm): def update_alarm(self, alarm):
"""update alarm """update alarm
""" """

View File

@ -23,7 +23,6 @@
import calendar import calendar
import copy import copy
import operator import operator
import uuid
import weakref import weakref
import bson.code import bson.code
@ -844,9 +843,6 @@ class Connection(base.Connection):
def update_alarm(self, alarm): def update_alarm(self, alarm):
"""update alarm """update alarm
""" """
if alarm.alarm_id is None:
# This is an insert, generate an id
alarm.alarm_id = str(uuid.uuid1())
data = alarm.as_dict() data = alarm.as_dict()
data['matching_metadata'] = \ data['matching_metadata'] = \
self._encode_matching_metadata(data['matching_metadata']) self._encode_matching_metadata(data['matching_metadata'])
@ -862,6 +858,8 @@ class Connection(base.Connection):
self._decode_matching_metadata(stored_alarm['matching_metadata']) self._decode_matching_metadata(stored_alarm['matching_metadata'])
return models.Alarm(**stored_alarm) return models.Alarm(**stored_alarm)
create_alarm = update_alarm
def delete_alarm(self, alarm_id): def delete_alarm(self, alarm_id):
"""Delete a alarm """Delete a alarm
""" """

View File

@ -22,7 +22,6 @@ from __future__ import absolute_import
import datetime import datetime
import operator import operator
import os import os
import uuid
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy import desc from sqlalchemy import desc
from sqlalchemy.orm import aliased from sqlalchemy.orm import aliased
@ -571,13 +570,6 @@ class Connection(base.Connection):
matching_metadata=row.matching_metadata, matching_metadata=row.matching_metadata,
repeat_actions=row.repeat_actions) repeat_actions=row.repeat_actions)
@staticmethod
def _alarm_model_to_row(alarm, row=None):
if row is None:
row = Alarm(id=str(uuid.uuid1()))
row.update(alarm.as_dict())
return row
def get_alarms(self, name=None, user=None, def get_alarms(self, name=None, user=None,
project=None, enabled=True, alarm_id=None, project=None, enabled=True, alarm_id=None,
limit=None, marker_pairs=None, limit=None, marker_pairs=None,
@ -614,24 +606,33 @@ class Connection(base.Connection):
return (self._row_to_alarm_model(x) for x in query.all()) return (self._row_to_alarm_model(x) for x in query.all())
def create_alarm(self, alarm):
"""Create an alarm.
:param alarm: The alarm to create.
"""
session = sqlalchemy_session.get_session()
with session.begin():
session.merge(User(id=alarm.user_id))
session.merge(Project(id=alarm.project_id))
alarm_row = Alarm(id=alarm.alarm_id)
alarm_row.update(alarm.as_dict())
session.add(alarm_row)
session.flush()
return self._row_to_alarm_model(alarm_row)
def update_alarm(self, alarm): def update_alarm(self, alarm):
"""update alarm """Update an alarm.
:param alarm: the new Alarm to update :param alarm: the new Alarm to update
""" """
session = sqlalchemy_session.get_session() session = sqlalchemy_session.get_session()
with session.begin(): with session.begin():
if alarm.alarm_id: alarm_row = session.merge(Alarm(id=alarm.alarm_id))
alarm_row = session.merge(Alarm(id=alarm.alarm_id)) alarm_row.update(alarm.as_dict())
self._alarm_model_to_row(alarm, alarm_row)
else:
session.merge(User(id=alarm.user_id))
session.merge(Project(id=alarm.project_id))
alarm_row = self._alarm_model_to_row(alarm)
session.add(alarm_row)
session.flush() session.flush()
return self._row_to_alarm_model(alarm_row) return self._row_to_alarm_model(alarm_row)
@staticmethod @staticmethod

View File

@ -277,12 +277,11 @@ class Alarm(Model):
:param repeat_actions: Is the actions should be triggered on each :param repeat_actions: Is the actions should be triggered on each
alarm evaluation. alarm evaluation.
""" """
def __init__(self, name, counter_name, def __init__(self, alarm_id, name, counter_name,
comparison_operator, threshold, statistic, comparison_operator, threshold, statistic,
user_id, project_id, user_id, project_id,
evaluation_periods=1, evaluation_periods=1,
period=60, period=60,
alarm_id=None,
enabled=True, enabled=True,
description='', description='',
timestamp=None, timestamp=None,

View File

@ -50,6 +50,7 @@ class TestAlarms(FunctionalTest,
self.auth_headers = {'X-User-Id': str(uuid.uuid1()), self.auth_headers = {'X-User-Id': str(uuid.uuid1()),
'X-Project-Id': str(uuid.uuid1())} 'X-Project-Id': str(uuid.uuid1())}
for alarm in [Alarm(name='name1', for alarm in [Alarm(name='name1',
alarm_id='a',
counter_name='meter.test', counter_name='meter.test',
comparison_operator='gt', threshold=2.0, comparison_operator='gt', threshold=2.0,
statistic='avg', statistic='avg',
@ -57,12 +58,14 @@ class TestAlarms(FunctionalTest,
user_id=self.auth_headers['X-User-Id'], user_id=self.auth_headers['X-User-Id'],
project_id=self.auth_headers['X-Project-Id']), project_id=self.auth_headers['X-Project-Id']),
Alarm(name='name2', Alarm(name='name2',
alarm_id='b',
counter_name='meter.mine', counter_name='meter.mine',
comparison_operator='gt', threshold=2.0, comparison_operator='gt', threshold=2.0,
statistic='avg', statistic='avg',
user_id=self.auth_headers['X-User-Id'], user_id=self.auth_headers['X-User-Id'],
project_id=self.auth_headers['X-Project-Id']), project_id=self.auth_headers['X-Project-Id']),
Alarm(name='name3', Alarm(name='name3',
alarm_id='c',
counter_name='meter.test', counter_name='meter.test',
comparison_operator='gt', threshold=2.0, comparison_operator='gt', threshold=2.0,
statistic='avg', statistic='avg',

View File

@ -194,7 +194,7 @@ class CompatibilityTest(test_storage_scenarios.DBTestBase,
# Create the old format alarm with a dict instead of a # Create the old format alarm with a dict instead of a
# array for matching_metadata # array for matching_metadata
alarm = models.Alarm('old-alert', alarm = models.Alarm('0ld-4l3rt', 'old-alert',
'test.one', 'eq', 36, 'count', 'test.one', 'eq', 36, 'count',
'me', 'and-da-boys', 'me', 'and-da-boys',
evaluation_periods=1, evaluation_periods=1,

View File

@ -1495,20 +1495,20 @@ class CounterDataTypeTest(DBTestBase,
class AlarmTestBase(DBTestBase): class AlarmTestBase(DBTestBase):
def add_some_alarms(self): def add_some_alarms(self):
alarms = [models.Alarm('red-alert', alarms = [models.Alarm('r3d', 'red-alert',
'test.one', 'eq', 36, 'count', 'test.one', 'eq', 36, 'count',
'me', 'and-da-boys', 'me', 'and-da-boys',
evaluation_periods=1, evaluation_periods=1,
period=60, period=60,
alarm_actions=['http://nowhere/alarms'], alarm_actions=['http://nowhere/alarms'],
matching_metadata={'key': 'value'}), matching_metadata={'key': 'value'}),
models.Alarm('orange-alert', models.Alarm('0r4ng3', 'orange-alert',
'test.fourty', 'gt', 75, 'avg', 'test.fourty', 'gt', 75, 'avg',
'me', 'and-da-boys', 'me', 'and-da-boys',
period=60, period=60,
alarm_actions=['http://nowhere/alarms'], alarm_actions=['http://nowhere/alarms'],
matching_metadata={'key2': 'value2'}), matching_metadata={'key2': 'value2'}),
models.Alarm('yellow-alert', models.Alarm('y3ll0w', 'yellow-alert',
'test.five', 'lt', 10, 'min', 'test.five', 'lt', 10, 'min',
'me', 'and-da-boys', 'me', 'and-da-boys',
alarm_actions=['http://nowhere/alarms'], alarm_actions=['http://nowhere/alarms'],
@ -1516,7 +1516,7 @@ class AlarmTestBase(DBTestBase):
{'key2': 'value2', {'key2': 'value2',
'user_metadata.key3': 'value3'})] 'user_metadata.key3': 'value3'})]
for a in alarms: for a in alarms:
self.conn.update_alarm(a) self.conn.create_alarm(a)
class AlarmTest(AlarmTestBase, class AlarmTest(AlarmTestBase,
@ -1561,7 +1561,7 @@ class AlarmTest(AlarmTestBase,
{'new': 'value', 'user_metadata.new2': 'value4'}) {'new': 'value', 'user_metadata.new2': 'value4'})
def test_update_llu(self): def test_update_llu(self):
llu = models.Alarm('llu', llu = models.Alarm('llu', 'llu',
'counter_name', 'lt', 34, 'max', 'counter_name', 'lt', 34, 'max',
'bla', 'ffo') 'bla', 'ffo')
updated = self.conn.update_alarm(llu) updated = self.conn.update_alarm(llu)