From 5d5f70e085ef9bb41040388469244f57f373a8fe Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Wed, 28 Aug 2013 17:01:53 +0200 Subject: [PATCH] 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 --- ceilometer/api/controllers/v2.py | 5 ++-- ceilometer/storage/base.py | 7 +++++ ceilometer/storage/impl_db2.py | 6 ++-- ceilometer/storage/impl_hbase.py | 5 ++++ ceilometer/storage/impl_log.py | 5 ++++ ceilometer/storage/impl_mongodb.py | 6 ++-- ceilometer/storage/impl_sqlalchemy.py | 39 +++++++++++++------------ ceilometer/storage/models.py | 3 +- tests/api/v2/test_alarm_scenarios.py | 3 ++ tests/storage/test_impl_mongodb.py | 2 +- tests/storage/test_storage_scenarios.py | 10 +++---- 11 files changed, 54 insertions(+), 37 deletions(-) diff --git a/ceilometer/api/controllers/v2.py b/ceilometer/api/controllers/v2.py index 584dad7c6..747daa0b7 100644 --- a/ceilometer/api/controllers/v2.py +++ b/ceilometer/api/controllers/v2.py @@ -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]) diff --git a/ceilometer/storage/base.py b/ceilometer/storage/base.py index 1bda217b1..e6f24c0c8 100644 --- a/ceilometer/storage/base.py +++ b/ceilometer/storage/base.py @@ -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 diff --git a/ceilometer/storage/impl_db2.py b/ceilometer/storage/impl_db2.py index e472d8619..d7462ada0 100644 --- a/ceilometer/storage/impl_db2.py +++ b/ceilometer/storage/impl_db2.py @@ -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 """ diff --git a/ceilometer/storage/impl_hbase.py b/ceilometer/storage/impl_hbase.py index d04fbd594..e69a1f128 100644 --- a/ceilometer/storage/impl_hbase.py +++ b/ceilometer/storage/impl_hbase.py @@ -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 """ diff --git a/ceilometer/storage/impl_log.py b/ceilometer/storage/impl_log.py index 6aa7aabc1..2ae0553b9 100644 --- a/ceilometer/storage/impl_log.py +++ b/ceilometer/storage/impl_log.py @@ -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 """ diff --git a/ceilometer/storage/impl_mongodb.py b/ceilometer/storage/impl_mongodb.py index 442f25fa3..53119dd51 100644 --- a/ceilometer/storage/impl_mongodb.py +++ b/ceilometer/storage/impl_mongodb.py @@ -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 """ diff --git a/ceilometer/storage/impl_sqlalchemy.py b/ceilometer/storage/impl_sqlalchemy.py index cb79a9b43..526f29e8d 100644 --- a/ceilometer/storage/impl_sqlalchemy.py +++ b/ceilometer/storage/impl_sqlalchemy.py @@ -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 diff --git a/ceilometer/storage/models.py b/ceilometer/storage/models.py index 8d6cebd4d..c1a19879b 100644 --- a/ceilometer/storage/models.py +++ b/ceilometer/storage/models.py @@ -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, diff --git a/tests/api/v2/test_alarm_scenarios.py b/tests/api/v2/test_alarm_scenarios.py index e62167534..1a6597658 100644 --- a/tests/api/v2/test_alarm_scenarios.py +++ b/tests/api/v2/test_alarm_scenarios.py @@ -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', diff --git a/tests/storage/test_impl_mongodb.py b/tests/storage/test_impl_mongodb.py index 2ba5a3420..b4e083c1a 100644 --- a/tests/storage/test_impl_mongodb.py +++ b/tests/storage/test_impl_mongodb.py @@ -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, diff --git a/tests/storage/test_storage_scenarios.py b/tests/storage/test_storage_scenarios.py index a3d13185a..a48be4ba3 100644 --- a/tests/storage/test_storage_scenarios.py +++ b/tests/storage/test_storage_scenarios.py @@ -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)