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

View File

@ -188,6 +188,13 @@ class Connection(object):
"""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
def update_alarm(self, alarm):
"""update alarm

View File

@ -22,7 +22,6 @@
"""
import copy
import uuid
import weakref
import bson.code
@ -595,9 +594,6 @@ class Connection(base.Connection):
def update_alarm(self, 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['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'])
return models.Alarm(**stored_alarm)
create_alarm = update_alarm
def delete_alarm(self, alarm_id):
"""Delete an alarm
"""

View File

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

View File

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

View File

@ -23,7 +23,6 @@
import calendar
import copy
import operator
import uuid
import weakref
import bson.code
@ -844,9 +843,6 @@ class Connection(base.Connection):
def update_alarm(self, 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['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'])
return models.Alarm(**stored_alarm)
create_alarm = update_alarm
def delete_alarm(self, alarm_id):
"""Delete a alarm
"""

View File

@ -22,7 +22,6 @@ from __future__ import absolute_import
import datetime
import operator
import os
import uuid
from sqlalchemy import func
from sqlalchemy import desc
from sqlalchemy.orm import aliased
@ -571,13 +570,6 @@ class Connection(base.Connection):
matching_metadata=row.matching_metadata,
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,
project=None, enabled=True, alarm_id=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())
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):
"""update alarm
"""Update an alarm.
:param alarm: the new Alarm to update
"""
session = sqlalchemy_session.get_session()
with session.begin():
if alarm.alarm_id:
alarm_row = session.merge(Alarm(id=alarm.alarm_id))
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)
alarm_row = session.merge(Alarm(id=alarm.alarm_id))
alarm_row.update(alarm.as_dict())
session.flush()
return self._row_to_alarm_model(alarm_row)
@staticmethod

View File

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

View File

@ -50,6 +50,7 @@ class TestAlarms(FunctionalTest,
self.auth_headers = {'X-User-Id': str(uuid.uuid1()),
'X-Project-Id': str(uuid.uuid1())}
for alarm in [Alarm(name='name1',
alarm_id='a',
counter_name='meter.test',
comparison_operator='gt', threshold=2.0,
statistic='avg',
@ -57,12 +58,14 @@ class TestAlarms(FunctionalTest,
user_id=self.auth_headers['X-User-Id'],
project_id=self.auth_headers['X-Project-Id']),
Alarm(name='name2',
alarm_id='b',
counter_name='meter.mine',
comparison_operator='gt', threshold=2.0,
statistic='avg',
user_id=self.auth_headers['X-User-Id'],
project_id=self.auth_headers['X-Project-Id']),
Alarm(name='name3',
alarm_id='c',
counter_name='meter.test',
comparison_operator='gt', threshold=2.0,
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
# array for matching_metadata
alarm = models.Alarm('old-alert',
alarm = models.Alarm('0ld-4l3rt', 'old-alert',
'test.one', 'eq', 36, 'count',
'me', 'and-da-boys',
evaluation_periods=1,

View File

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