diff --git a/ceilometer/alarm/storage/impl_hbase.py b/ceilometer/alarm/storage/impl_hbase.py index 21c1431d8..352480273 100644 --- a/ceilometer/alarm/storage/impl_hbase.py +++ b/ceilometer/alarm/storage/impl_hbase.py @@ -12,6 +12,7 @@ # under the License. import datetime +import operator import ceilometer from ceilometer.alarm.storage import base @@ -133,9 +134,13 @@ class Connection(hbase_base.Connection, base.Connection): with self.conn_pool.connection() as conn: alarm_table = conn.table(self.ALARM_TABLE) gen = alarm_table.scan(filter=q) - for ignored, data in gen: - stored_alarm = hbase_utils.deserialize_entry(data)[0] - yield models.Alarm(**stored_alarm) + alarms = [hbase_utils.deserialize_entry(data)[0] + for ignored, data in gen] + for alarm in sorted( + alarms, + key=operator.itemgetter('timestamp'), + reverse=True): + yield models.Alarm(**alarm) def get_alarm_changes(self, alarm_id, on_behalf_of, user=None, project=None, type=None, diff --git a/ceilometer/alarm/storage/impl_sqlalchemy.py b/ceilometer/alarm/storage/impl_sqlalchemy.py index ddf856ae3..ebbebf836 100644 --- a/ceilometer/alarm/storage/impl_sqlalchemy.py +++ b/ceilometer/alarm/storage/impl_sqlalchemy.py @@ -172,6 +172,7 @@ class Connection(base.Connection): if state is not None: query = query.filter(models.Alarm.state == state) + query = query.order_by(desc(models.Alarm.timestamp)) alarms = self._retrieve_alarms(query) # TODO(cmart): improve this by using sqlalchemy.func factory diff --git a/ceilometer/alarm/storage/pymongo_base.py b/ceilometer/alarm/storage/pymongo_base.py index b012dd1e1..e7f0fd13f 100644 --- a/ceilometer/alarm/storage/pymongo_base.py +++ b/ceilometer/alarm/storage/pymongo_base.py @@ -111,7 +111,10 @@ class Connection(base.Connection): if meter is not None: q['rule.meter_name'] = meter - return self._retrieve_alarms(q, [], None) + return self._retrieve_alarms(q, + [("timestamp", + pymongo.DESCENDING)], + None) def get_alarm_changes(self, alarm_id, on_behalf_of, user=None, project=None, type=None, diff --git a/ceilometer/tests/api/v2/test_alarm_scenarios.py b/ceilometer/tests/api/v2/test_alarm_scenarios.py index 996fd6975..6b90d55eb 100644 --- a/ceilometer/tests/api/v2/test_alarm_scenarios.py +++ b/ceilometer/tests/api/v2/test_alarm_scenarios.py @@ -2086,20 +2086,24 @@ class TestAlarms(v2.FunctionalTest, def test_alarm_sends_notification(self): # Hit the AlarmController (with alarm_id supplied) ... data = self.get_json('/alarms') + del_alarm_name = "name1" + for d in data: + if d['name'] == del_alarm_name: + del_alarm_id = d['alarm_id'] + with mock.patch.object(messaging, 'get_notifier') as get_notifier: notifier = get_notifier.return_value - self.delete('/alarms/%s' % data[0]['alarm_id'], + self.delete('/alarms/%s' % del_alarm_id, headers=self.auth_headers, status=204) get_notifier.assert_called_once_with(mock.ANY, publisher_id='ceilometer.api') - calls = notifier.info.call_args_list self.assertEqual(1, len(calls)) args, _ = calls[0] context, event_type, payload = args self.assertEqual('alarm.deletion', event_type) - self.assertEqual('name1', payload['detail']['name']) + self.assertEqual(del_alarm_name, payload['detail']['name']) self.assertTrue(set(['alarm_id', 'detail', 'event_id', 'on_behalf_of', 'project_id', 'timestamp', 'type', 'user_id']).issubset(payload.keys())) diff --git a/ceilometer/tests/storage/test_storage_scenarios.py b/ceilometer/tests/storage/test_storage_scenarios.py index dbd1dd400..62cff43b7 100644 --- a/ceilometer/tests/storage/test_storage_scenarios.py +++ b/ceilometer/tests/storage/test_storage_scenarios.py @@ -2311,7 +2311,8 @@ class AlarmTestBase(DBTestBase): type='threshold', name='red-alert', description='my red-alert', - timestamp=constants.MIN_DATETIME, + timestamp=datetime.datetime(2015, 7, + 2, 10, 25), user_id='me', project_id='and-da-boys', state="insufficient data", @@ -2339,7 +2340,8 @@ class AlarmTestBase(DBTestBase): type='threshold', name='orange-alert', description='a orange', - timestamp=constants.MIN_DATETIME, + timestamp=datetime.datetime(2015, 7, + 2, 10, 40), user_id='me', project_id='and-da-boys', state="insufficient data", @@ -2365,7 +2367,8 @@ class AlarmTestBase(DBTestBase): type='threshold', name='yellow-alert', description='yellow', - timestamp=constants.MIN_DATETIME, + timestamp=datetime.datetime(2015, 7, + 2, 10, 10), user_id='me', project_id='and-da-boys', state="insufficient data", @@ -2408,6 +2411,16 @@ class AlarmTest(AlarmTestBase, alarms = list(self.alarm_conn.get_alarms()) self.assertEqual(len(alarms), 3) + def test_list_ordered_by_timestamp(self): + self.add_some_alarms() + alarms = list(self.alarm_conn.get_alarms()) + self.assertEqual(len(alarms), 3) + alarm_l = [a.timestamp for a in alarms] + alarm_l_ordered = [datetime.datetime(2015, 7, 2, 10, 40), + datetime.datetime(2015, 7, 2, 10, 25), + datetime.datetime(2015, 7, 2, 10, 10)] + self.assertEqual(alarm_l_ordered, alarm_l) + def test_list_enabled(self): self.add_some_alarms() alarms = list(self.alarm_conn.get_alarms(enabled=True)) @@ -2593,8 +2606,14 @@ class ComplexAlarmHistoryQueryTest(AlarmTestBase, def prepare_alarm_history(self): alarms = list(self.alarm_conn.get_alarms()) + name_index = { + 'red-alert': 0, + 'orange-alert': 1, + 'yellow-alert': 2 + } + for alarm in alarms: - i = alarms.index(alarm) + i = name_index[alarm.name] alarm_change = dict(event_id=( "16fd2706-8baf-433b-82eb-8c7fada847c%s" % i), alarm_id=alarm.alarm_id,