From 3cfac4c51a29dcce17d139321d49f0682385dab8 Mon Sep 17 00:00:00 2001 From: Mehdi Abaakouk Date: Thu, 26 Sep 2013 11:53:01 +0200 Subject: [PATCH] Allow to get a disabled alarm This change allow to get a disabled alarm. To do this, it: * add the ability to query the alarm-list API with the 'enabled' fields. * change the default visibility of alarm-list API from enabled only to all. Fixes bug #1231328 Change-Id: I80cd691696f7630d2ac9e9b2a69b5b0ae5ee7968 --- ceilometer/api/controllers/v2.py | 21 ++++++++++--------- ceilometer/storage/base.py | 2 +- ceilometer/storage/impl_db2.py | 2 +- ceilometer/storage/impl_hbase.py | 2 +- ceilometer/storage/impl_log.py | 2 +- ceilometer/storage/impl_mongodb.py | 2 +- ceilometer/storage/impl_sqlalchemy.py | 2 +- tests/api/v2/test_alarm_scenarios.py | 27 +++++++++++++++++++++++++ tests/storage/test_storage_scenarios.py | 17 +++++++++++++++- 9 files changed, 61 insertions(+), 16 deletions(-) diff --git a/ceilometer/api/controllers/v2.py b/ceilometer/api/controllers/v2.py index 54c8e747..e8b464a5 100644 --- a/ceilometer/api/controllers/v2.py +++ b/ceilometer/api/controllers/v2.py @@ -209,7 +209,7 @@ class Query(_Base): def as_dict(self): return self.as_dict_from_keys(['field', 'op', 'type', 'value']) - def _get_value_as_type(self): + def _get_value_as_type(self, forced_type=None): """Convert metadata value to the specified data type. This method is called during metadata query to help convert the @@ -225,9 +225,10 @@ class Query(_Base): :returns: metadata value converted with the specified data type. """ + type = forced_type or self.type try: converted_value = self.value - if not self.type: + if not type: try: converted_value = ast.literal_eval(self.value) except (ValueError, SyntaxError): @@ -235,13 +236,13 @@ class Query(_Base): ' automatically') % (self.value) LOG.debug(msg) else: - if self.type == 'integer': + if type == 'integer': converted_value = int(self.value) - elif self.type == 'float': + elif type == 'float': converted_value = float(self.value) - elif self.type == 'boolean': + elif type == 'boolean': converted_value = strutils.bool_from_string(self.value) - elif self.type == 'string': + elif type == 'string': converted_value = self.value else: # For now, this method only support integer, float, @@ -251,17 +252,17 @@ class Query(_Base): except ValueError: msg = _('Failed to convert the metadata value %(value)s' ' to the expected data type %(type)s.') % \ - {'value': self.value, 'type': self.type} + {'value': self.value, 'type': type} raise wsme.exc.ClientSideError(unicode(msg)) except TypeError: msg = _('The data type %s is not supported. The supported' ' data type list is: integer, float, boolean and' - ' string.') % (self.type) + ' string.') % (type) raise wsme.exc.ClientSideError(unicode(msg)) except Exception: msg = _('Unexpected exception converting %(value)s to' ' the expected data type %(type)s.') % \ - {'value': self.value, 'type': self.type} + {'value': self.value, 'type': type} raise wsme.exc.ClientSideError(unicode(msg)) return converted_value @@ -323,6 +324,8 @@ def _query_to_kwargs(query, db_func, internal_keys=[], headers=None): if i.op == 'eq': if i.field == 'search_offset': stamp['search_offset'] = i.value + elif i.field == 'enabled': + kwargs[i.field] = i._get_value_as_type('boolean') elif i.field.startswith('metadata.'): metaquery[i.field] = i._get_value_as_type() elif i.field.startswith('resource_metadata.'): diff --git a/ceilometer/storage/base.py b/ceilometer/storage/base.py index e077c17e..7b59da80 100644 --- a/ceilometer/storage/base.py +++ b/ceilometer/storage/base.py @@ -209,7 +209,7 @@ class Connection(object): @abc.abstractmethod def get_alarms(self, name=None, user=None, - project=None, enabled=True, alarm_id=None, pagination=None): + project=None, enabled=None, alarm_id=None, pagination=None): """Yields a lists of alarms that match filters """ diff --git a/ceilometer/storage/impl_db2.py b/ceilometer/storage/impl_db2.py index bbc331ee..f74e774d 100644 --- a/ceilometer/storage/impl_db2.py +++ b/ceilometer/storage/impl_db2.py @@ -666,7 +666,7 @@ class Connection(base.Connection): alarm['rule']['query'] = query def get_alarms(self, name=None, user=None, - project=None, enabled=True, alarm_id=None, pagination=None): + project=None, enabled=None, alarm_id=None, pagination=None): """Yields a lists of alarms that match filters :param user: Optional ID for user that owns the resource. :param project: Optional ID for project that owns the resource. diff --git a/ceilometer/storage/impl_hbase.py b/ceilometer/storage/impl_hbase.py index 0447606f..67f41ba0 100644 --- a/ceilometer/storage/impl_hbase.py +++ b/ceilometer/storage/impl_hbase.py @@ -591,7 +591,7 @@ class Connection(base.Connection): return results def get_alarms(self, name=None, user=None, - project=None, enabled=True, alarm_id=None, pagination=None): + project=None, enabled=None, alarm_id=None, pagination=None): """Yields a lists of alarms that match filters raise NotImplementedError('metaquery not implemented') """ diff --git a/ceilometer/storage/impl_log.py b/ceilometer/storage/impl_log.py index 2f952fb1..56bf2cc6 100644 --- a/ceilometer/storage/impl_log.py +++ b/ceilometer/storage/impl_log.py @@ -158,7 +158,7 @@ class Connection(base.Connection): return [] def get_alarms(self, name=None, user=None, - project=None, enabled=True, alarm_id=None, pagination=None): + project=None, enabled=None, alarm_id=None, pagination=None): """Yields a lists of alarms that match filters """ return [] diff --git a/ceilometer/storage/impl_mongodb.py b/ceilometer/storage/impl_mongodb.py index dd2a9711..9ca881c6 100644 --- a/ceilometer/storage/impl_mongodb.py +++ b/ceilometer/storage/impl_mongodb.py @@ -850,7 +850,7 @@ class Connection(base.Connection): alarm['rule']['query'] = query def get_alarms(self, name=None, user=None, - project=None, enabled=True, alarm_id=None, pagination=None): + project=None, enabled=None, alarm_id=None, pagination=None): """Yields a lists of alarms that match filters :param name: The Alarm name. :param user: Optional ID for user that owns the resource. diff --git a/ceilometer/storage/impl_sqlalchemy.py b/ceilometer/storage/impl_sqlalchemy.py index 93139aa3..20da8091 100644 --- a/ceilometer/storage/impl_sqlalchemy.py +++ b/ceilometer/storage/impl_sqlalchemy.py @@ -597,7 +597,7 @@ class Connection(base.Connection): repeat_actions=row.repeat_actions) def get_alarms(self, name=None, user=None, - project=None, enabled=True, alarm_id=None, pagination=None): + project=None, enabled=None, alarm_id=None, pagination=None): """Yields a lists of alarms that match filters :param user: Optional ID for user that owns the resource. :param project: Optional ID for project that owns the resource. diff --git a/tests/api/v2/test_alarm_scenarios.py b/tests/api/v2/test_alarm_scenarios.py index 7e51a263..de84adbe 100644 --- a/tests/api/v2/test_alarm_scenarios.py +++ b/tests/api/v2/test_alarm_scenarios.py @@ -183,6 +183,33 @@ class TestAlarms(FunctionalTest, self.assertEqual(one['alarm_id'], alarms[0]['alarm_id']) self.assertEqual(one['repeat_actions'], alarms[0]['repeat_actions']) + def test_get_alarm_disabled(self): + alarm = Alarm(name='disabled', + type='combination', + enabled=False, + alarm_id='d', + description='d', + state='insufficient data', + state_timestamp=None, + timestamp=None, + ok_actions=[], + insufficient_data_actions=[], + alarm_actions=[], + repeat_actions=False, + user_id=self.auth_headers['X-User-Id'], + project_id=self.auth_headers['X-Project-Id'], + rule=dict(alarm_ids=['a', 'b'], operator='or')) + self.conn.update_alarm(alarm) + + alarms = self.get_json('/alarms', + q=[{'field': 'enabled', + 'value': 'False'}]) + self.assertEqual(len(alarms), 1) + self.assertEqual(alarms[0]['name'], 'disabled') + + one = self.get_json('/alarms/%s' % alarms[0]['alarm_id']) + self.assertEqual(one['name'], 'disabled') + def test_get_alarm_combination(self): alarms = self.get_json('/alarms', q=[{'field': 'name', diff --git a/tests/storage/test_storage_scenarios.py b/tests/storage/test_storage_scenarios.py index adf45365..880a947c 100644 --- a/tests/storage/test_storage_scenarios.py +++ b/tests/storage/test_storage_scenarios.py @@ -1903,7 +1903,7 @@ class AlarmTestBase(DBTestBase): 'type': 'string'}]), ), models.Alarm(alarm_id='y3ll0w', - enabled=True, + enabled=False, type='threshold', name='yellow-alert', description='yellow', @@ -1944,6 +1944,21 @@ class AlarmTest(AlarmTestBase, alarms = list(self.conn.get_alarms()) self.assertEqual([], alarms) + def test_list(self): + self.add_some_alarms() + alarms = list(self.conn.get_alarms()) + self.assertEqual(len(alarms), 3) + + def test_list_enabled(self): + self.add_some_alarms() + alarms = list(self.conn.get_alarms(enabled=True)) + self.assertEqual(len(alarms), 2) + + def test_list_disabled(self): + self.add_some_alarms() + alarms = list(self.conn.get_alarms(enabled=False)) + self.assertEqual(len(alarms), 1) + def test_add(self): self.add_some_alarms() alarms = list(self.conn.get_alarms())