diff --git a/releasenotes/notes/aodh_extended_alarm_support-327bb589311da440.yaml b/releasenotes/notes/aodh_extended_alarm_support-327bb589311da440.yaml new file mode 100644 index 000000000..4f1fffe19 --- /dev/null +++ b/releasenotes/notes/aodh_extended_alarm_support-327bb589311da440.yaml @@ -0,0 +1,5 @@ +--- +features: + - Add support for more aodh alarm types - composite, + gnocchi_aggregation_by_metrics_threshold and + gnocchi_aggregation_by_resources_threshold. diff --git a/vitrage/datasources/alarm_driver_base.py b/vitrage/datasources/alarm_driver_base.py index 98dbd449b..5e9cf214a 100644 --- a/vitrage/datasources/alarm_driver_base.py +++ b/vitrage/datasources/alarm_driver_base.py @@ -103,8 +103,7 @@ class AlarmDriverBase(DriverBase): for alarm in alarms: alarm_key = self._alarm_key(alarm) old_alarm = self.cache.get(alarm_key, (None, None))[0] - if self._filter_and_cache_alarm( - alarm, old_alarm, filter_, now): + if self._filter_and_cache_alarm(alarm, old_alarm, filter_, now): alarms_to_update.append(alarm) # add alarms that were deleted diff --git a/vitrage/datasources/aodh/driver.py b/vitrage/datasources/aodh/driver.py index c1141f096..9eafe6bae 100644 --- a/vitrage/datasources/aodh/driver.py +++ b/vitrage/datasources/aodh/driver.py @@ -11,6 +11,8 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +import json +import six from oslo_log import log @@ -57,7 +59,14 @@ class AodhDriver(AlarmDriverBase): AodhExtendedAlarmType.THRESHOLD: self._convert_threshold_alarm_rule, AodhExtendedAlarmType.GNOCCHI_RESOURCES_THRESHOLD: - self._convert_gnocchi_resources_threshold_alarm_rule + self._convert_gnocchi_resources_threshold_alarm_rule, + AodhExtendedAlarmType.GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD: + self._convert_gnocchi_aggregation_by_metrics_threshold_rule, + AodhExtendedAlarmType.GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD: + self._convert_gnocchi_aggregation_by_resources_threshold_rule, + AodhExtendedAlarmType.COMPOSITE: + self._convert_composite_alarm_rule + } def _init_alarm_type_to_rule(self): @@ -66,7 +75,12 @@ class AodhDriver(AlarmDriverBase): AodhExtendedAlarmType.EVENT: AodhProps.EVENT_RULE, AodhExtendedAlarmType.THRESHOLD: AodhProps.THRESHOLD_RULE, AodhExtendedAlarmType.GNOCCHI_RESOURCES_THRESHOLD: - AodhProps.GNOCCHI_RESOURCES_THRESHOLD_RULE + AodhProps.GNOCCHI_RESOURCES_THRESHOLD_RULE, + AodhExtendedAlarmType.COMPOSITE: AodhProps.COMPOSITE_RULE, + AodhExtendedAlarmType.GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD: + AodhProps.GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD_RULE, + AodhExtendedAlarmType.GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD: + AodhProps.GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD_RULE } @property @@ -109,7 +123,12 @@ class AodhDriver(AlarmDriverBase): Aodh_type = [AodhExtendedAlarmType.EVENT, AodhExtendedAlarmType.THRESHOLD, - AodhExtendedAlarmType.GNOCCHI_RESOURCES_THRESHOLD] + AodhExtendedAlarmType.GNOCCHI_RESOURCES_THRESHOLD, + AodhExtendedAlarmType. + GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD, + AodhExtendedAlarmType. + GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD, + AodhExtendedAlarmType.COMPOSITE] alarm_type = alarm[AodhProps.TYPE] if alarm_type == AodhProps.EVENT and \ @@ -171,12 +190,26 @@ class AodhDriver(AlarmDriverBase): @classmethod def _convert_threshold_alarm_rule(cls, rule): - return { - AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID) - } + return cls._alarm_rule_common(rule) @classmethod def _convert_gnocchi_resources_threshold_alarm_rule(cls, rule): + return cls._alarm_rule_common(rule) + + @classmethod + def _convert_gnocchi_aggregation_by_metrics_threshold_rule(cls, rule): + return cls._alarm_rule_common(rule) + + @classmethod + def _convert_gnocchi_aggregation_by_resources_threshold_rule(cls, rule): + return cls._alarm_rule_common(rule) + + @classmethod + def _convert_composite_alarm_rule(cls, rule): + return cls._alarm_rule_common(rule) + + @classmethod + def _alarm_rule_common(cls, rule): return { AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID) } @@ -268,7 +301,6 @@ class AodhDriver(AlarmDriverBase): """ old_alarm = self._old_alarm(event) entity = old_alarm.copy() - changed_rule = event[AodhProps.DETAIL] for (changed_type, changed_info) in changed_rule.items(): # handle changed rule which may effect the neighbor @@ -303,12 +335,41 @@ class AodhDriver(AlarmDriverBase): def _parse_query(data, key): + """Find the relevant key in a given alarm detail query. + + :param data: A query is either a list of this form: + [ + { + field: resource_id, + value: 54132 + } + ] + or a string-represented dict of this form: + '{ + =: { resource_id : 1235423 } + }' + """ + query_fields = data.get(AodhProps.QUERY, {}) - for query in query_fields: - field = query['field'] - if field == key: - return query['value'] - return None + try: + if isinstance(query_fields, six.text_type): + query_fields = json.loads(query_fields) + if not isinstance(query_fields, list): + query_fields = [query_fields] + for query in query_fields: + field = query.get('field') + if field and field == key: + return query['value'] + elif not field: + field = query.get('=', {}) + for k in field: + if k == key: + return field[key] + return None + + except Exception: + LOG.exception("Failed to parse AODH alarm query") + return None def _is_vitrage_alarm(rule): diff --git a/vitrage/datasources/aodh/properties.py b/vitrage/datasources/aodh/properties.py index a9d109041..284ce38a6 100644 --- a/vitrage/datasources/aodh/properties.py +++ b/vitrage/datasources/aodh/properties.py @@ -38,8 +38,14 @@ class AodhProperties(object): DETAIL = 'detail' RULE = 'rule' GNOCCHI_RESOURCES_THRESHOLD_RULE = 'gnocchi_resources_threshold_rule' + COMPOSITE_RULE = 'composite_rule' + GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD_RULE = \ + 'gnocchi_aggregation_by_resources_threshold_rule' + GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD_RULE = \ + 'gnocchi_aggregation_by_metrics_threshold_rule' USER_ID = 'user_id' STATE_REASON = 'state_reason' + METRICS = 'metrics' class AodhState(object): @@ -60,3 +66,8 @@ class AodhExtendedAlarmType(object): VITRAGE = 'vitrage' THRESHOLD = 'threshold' GNOCCHI_RESOURCES_THRESHOLD = 'gnocchi_resources_threshold' + COMPOSITE = 'composite' + GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD = \ + 'gnocchi_aggregation_by_metrics_threshold' + GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD = \ + 'gnocchi_aggregation_by_resources_threshold' diff --git a/vitrage/tests/unit/datasources/aodh/test_aodh_driver.py b/vitrage/tests/unit/datasources/aodh/test_aodh_driver.py index c0e434887..bb460a635 100644 --- a/vitrage/tests/unit/datasources/aodh/test_aodh_driver.py +++ b/vitrage/tests/unit/datasources/aodh/test_aodh_driver.py @@ -19,6 +19,7 @@ from vitrage.common.constants import DatasourceProperties as DSProps from vitrage.common.constants import UpdateMethod from vitrage.datasources.aodh import AODH_DATASOURCE from vitrage.datasources.aodh.properties import AodhEventType +from vitrage.datasources.aodh.properties import AodhExtendedAlarmType as AType from vitrage.datasources.aodh.properties import AodhProperties as AodhProps from vitrage.tests import base from vitrage.tests.mocks import mock_driver @@ -312,6 +313,500 @@ class AodhDriverTest(base.BaseTest): # Test assertions self.assertIsNone(entity) + def test_gnocchi_aggregation_by_metrics_alarm_notifications(self): + aodh_driver = MockAodhDriver(self.conf) + + # 1. alarm creation with 'ok' state + # prepare data + detail_data = { + "type": AType.GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD, + AodhProps.DETAIL: self._create_alarm_data_metrics() + } + generators = \ + mock_driver.simple_aodh_alarm_notification_generators( + alarm_num=1, + update_events=1, + update_vals=detail_data) + alarm = mock_driver.generate_sequential_events_list(generators)[0] + alarm_info = alarm.copy() + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.CREATION) + + # Test assertions + # alarm with status OK should not be handled + self.assertIsNone(entity) + + # 2.alarm state transition from 'ok' to 'alarm' + detail_data = {"type": "state transition", + AodhProps.DETAIL: {AodhProps.STATE: "alarm"}} + alarm.update(detail_data) + entity = aodh_driver.enrich_event(alarm, + AodhEventType.STATE_TRANSITION) + + # Test assertions + # alarm state change: ok->alarm, need to be added + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.STATE], + alarm[AodhProps.DETAIL][AodhProps.STATE]) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.SEVERITY]) + + # 3. delete alarm which is 'alarm' state + # prepare data + detail_data = {"type": "deletion"} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.DELETION) + + # Test assertions + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.DELETION) + + # 4. alarm creation with 'alarm' state + # prepare data + detail_data = { + "type": AType.GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD, + AodhProps.DETAIL: self._create_alarm_data_metrics(state="alarm") + } + generators = \ + mock_driver.simple_aodh_alarm_notification_generators( + alarm_num=1, + update_events=1, + update_vals=detail_data) + alarm = mock_driver.generate_sequential_events_list(generators)[0] + alarm_info = alarm.copy() + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.CREATION) + + # Test assertions + # alarm with status 'alarm' need to be added + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.STATE], + alarm[AodhProps.DETAIL][AodhProps.STATE]) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.SEVERITY]) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.CREATION) + + # 5. alarm rule change + # prepare data + detail_data = {"type": "rule change", + AodhProps.DETAIL: { + "severity": "critical", + AodhProps.RULE: + {"granularity": "300", + "threshold": "0.0123", + "comparison_operator": "eq"}}} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, + AodhEventType.RULE_CHANGE) + + # Test assertions + # alarm rule change: need to be update + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.DETAIL][AodhProps.SEVERITY]) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.RULE_CHANGE) + + # 6. alarm state change from 'alarm' to 'ok' + # prepare data + detail_data = {"type": "state transition", + AodhProps.DETAIL: {AodhProps.STATE: "ok"}} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, + AodhEventType.STATE_TRANSITION) + + # Test assertions + # alarm state change: alarm->OK, need to be deleted + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.STATE_TRANSITION) + + # 7. delete alarm which is 'ok' state + # prepare data + detail_data = {"type": "deletion"} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.DELETION) + + # Test assertions + self.assertIsNone(entity) + + def test_gnocchi_aggregation_by_resource_alarm_notifications(self): + aodh_driver = MockAodhDriver(self.conf) + + # 1. alarm creation with 'ok' state + # prepare data + detail_data = { + "type": AType.GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD, + AodhProps.DETAIL: self._create_alarm_data_resource() + } + generators = \ + mock_driver.simple_aodh_alarm_notification_generators( + alarm_num=1, + update_events=1, + update_vals=detail_data) + alarm = mock_driver.generate_sequential_events_list(generators)[0] + alarm_info = alarm.copy() + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.CREATION) + + # Test assertions + # alarm with status OK should not be handled + self.assertIsNone(entity) + + # 2.alarm state transition from 'ok' to 'alarm' + detail_data = {"type": "state transition", + AodhProps.DETAIL: {AodhProps.STATE: "alarm"}} + alarm.update(detail_data) + entity = aodh_driver.enrich_event(alarm, + AodhEventType.STATE_TRANSITION) + + # Test assertions + # alarm state change: ok->alarm, need to be added + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.STATE], + alarm[AodhProps.DETAIL][AodhProps.STATE]) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.SEVERITY]) + + # 3. delete alarm which is 'alarm' state + # prepare data + detail_data = {"type": "deletion"} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.DELETION) + + # Test assertions + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.DELETION) + + # 4. alarm creation with 'alarm' state + # prepare data + detail_data = { + "type": AType.GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD, + AodhProps.DETAIL: + self._create_alarm_data_gnocchi(state="alarm") + } + generators = \ + mock_driver.simple_aodh_alarm_notification_generators( + alarm_num=1, + update_events=1, + update_vals=detail_data) + alarm = mock_driver.generate_sequential_events_list(generators)[0] + alarm_info = alarm.copy() + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.CREATION) + + # Test assertions + # alarm with status 'alarm' need to be added + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.STATE], + alarm[AodhProps.DETAIL][AodhProps.STATE]) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.SEVERITY]) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.CREATION) + + # 5. alarm rule change + # prepare data + detail_data = {"type": "rule change", + AodhProps.DETAIL: { + "severity": "critical", + AodhProps.RULE: + {"granularity": "300", + "threshold": "0.0123", + "comparison_operator": "eq"}}} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, + AodhEventType.RULE_CHANGE) + + # Test assertions + # alarm rule change: need to be update + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.DETAIL][AodhProps.SEVERITY]) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.RULE_CHANGE) + + # 6. alarm state change from 'alarm' to 'ok' + # prepare data + detail_data = {"type": "state transition", + AodhProps.DETAIL: {AodhProps.STATE: "ok"}} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, + AodhEventType.STATE_TRANSITION) + + # Test assertions + # alarm state change: alarm->OK, need to be deleted + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.STATE_TRANSITION) + + # 7. delete alarm which is 'ok' state + # prepare data + detail_data = {"type": "deletion"} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.DELETION) + + # Test assertions + self.assertIsNone(entity) + + def test_composite_alarm_notifications(self): + aodh_driver = MockAodhDriver(self.conf) + + # 1. alarm creation with 'ok' state + # prepare data + detail_data = {"type": "composite", + AodhProps.DETAIL: self._create_alarm_data_composite()} + generators = \ + mock_driver.simple_aodh_alarm_notification_generators( + alarm_num=1, + update_events=1, + update_vals=detail_data) + alarm = mock_driver.generate_sequential_events_list(generators)[0] + alarm_info = alarm.copy() + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.CREATION) + + # Test assertions + # alarm with status OK should not be handled + self.assertIsNone(entity) + + # 2.alarm state transition from 'ok' to 'alarm' + detail_data = {"type": "state transition", + AodhProps.DETAIL: {AodhProps.STATE: "alarm"}} + alarm.update(detail_data) + entity = aodh_driver.enrich_event(alarm, + AodhEventType.STATE_TRANSITION) + + # Test assertions + # alarm state change: ok->alarm, need to be added + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.STATE], + alarm[AodhProps.DETAIL][AodhProps.STATE]) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.SEVERITY]) + + # 3. delete alarm which is 'alarm' state + # prepare data + detail_data = {"type": "deletion"} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.DELETION) + + # Test assertions + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.DELETION) + + # 4. alarm creation with 'alarm' state + # prepare data + detail_data = {"type": "composite", + AodhProps.DETAIL: + self._create_alarm_data_composite(state="alarm")} + generators = \ + mock_driver.simple_aodh_alarm_notification_generators( + alarm_num=1, + update_events=1, + update_vals=detail_data) + alarm = mock_driver.generate_sequential_events_list(generators)[0] + alarm_info = alarm.copy() + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.CREATION) + + # Test assertions + # alarm with status 'alarm' need to be added + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.STATE], + alarm[AodhProps.DETAIL][AodhProps.STATE]) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.SEVERITY]) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.CREATION) + + # 5. alarm rule change + # prepare data + detail_data = {"type": "rule change", + AodhProps.DETAIL: { + "severity": "critical", + AodhProps.RULE: + {"granularity": "300", + "threshold": "0.0123", + "comparison_operator": "eq"}}} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, + AodhEventType.RULE_CHANGE) + + # Test assertions + # alarm rule change: need to be update + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[AodhProps.SEVERITY], + alarm[AodhProps.DETAIL][AodhProps.SEVERITY]) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.RULE_CHANGE) + + # 6. alarm state change from 'alarm' to 'ok' + # prepare data + detail_data = {"type": "state transition", + AodhProps.DETAIL: {AodhProps.STATE: "ok"}} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, + AodhEventType.STATE_TRANSITION) + + # Test assertions + # alarm state change: alarm->OK, need to be deleted + self.assertIsNotNone(entity) + self._validate_aodh_entity_comm_props(entity, alarm_info) + self.assertEqual(entity[DSProps.EVENT_TYPE], + AodhEventType.STATE_TRANSITION) + + # 7. delete alarm which is 'ok' state + # prepare data + detail_data = {"type": "deletion"} + alarm.update(detail_data) + + # action + entity = aodh_driver.enrich_event(alarm, AodhEventType.DELETION) + + # Test assertions + self.assertIsNone(entity) + + def _create_alarm_data_composite(self, + state='ok', + type='composite', + rule=None): + if rule is None: + rule = {"or": + [{"evaluation_periods": 1, + "metrics": ["6ade05e5-f98b-4b7d-a0b3-9d330c4c3c41"], + "aggregation_method": "mean", + "granularity": 60, + "threshold": 100.0, + "type": "gnocchi_aggregation_by_metrics_threshold", + "comparison_operator": "lt"}, + {"evaluation_periods": 3, + "metrics": ["89vde0e5-k3rb-4b7d-a0b3-9d330c4c3c41"], + "aggregation_method": "mean", + "granularity": 2, + "threshold": 80.0, + "type": "gnocchi_aggregation_by_metrics_threshold", + "comparison_operator": "ge"} + ]} + return {AodhProps.DESCRIPTION: "test", + AodhProps.TIMESTAMP: "2016-11-09T01:39:13.839584", + AodhProps.ENABLED: True, + AodhProps.STATE_TIMESTAMP: "2016-11-09T01:39:13.839584", + AodhProps.ALARM_ID: "7e5c3754-e2eb-4782-ae00-7da5ded8568b", + AodhProps.REPEAT_ACTIONS: False, + AodhProps.PROJECT_ID: "c365d18fcc03493187016ae743f0cc4d", + AodhProps.NAME: "test", + AodhProps.SEVERITY: "low", + AodhProps.RESOURCE_ID: "88cd2d1d-8af4-4d00-9b5e-f82f8c8b0f8d", + AodhProps.TYPE: type, + AodhProps.STATE: state, + AodhProps.RULE: rule} + + def _create_alarm_data_metrics( + self, + state='ok', + type=AType.GNOCCHI_AGGREGATION_BY_METRICS_THRESHOLD, + rule=None + ): + if rule is None: + rule = {"threshold": '100', + "aggregation_method": "mean", + "comparison_operator": "lt" + } + + return {AodhProps.DESCRIPTION: "metric test", + AodhProps.TIMESTAMP: "2017-04-03T01:39:13.839584", + AodhProps.ENABLED: True, + AodhProps.STATE_TIMESTAMP: "2017-04-03T01:39:13.839584", + AodhProps.ALARM_ID: "7e5c3754-e2eb-4782-ae00-7da5ded8568b", + AodhProps.REPEAT_ACTIONS: False, + AodhProps.PROJECT_ID: "c365d18fcc03493187016ae743f0cc4d", + AodhProps.NAME: "test", + AodhProps.SEVERITY: "low", + AodhProps.RESOURCE_ID: "88cd2d1d-8af4-4d00-9b5e-f82f8c8b0f8d", + AodhProps.METRICS: "6ade05e5-f98b-4b7d-a0b3-9d330c4c3c41", + AodhProps.TYPE: type, + AodhProps.STATE: state, + AodhProps.RULE: rule} + + def _create_alarm_data_resource( + self, + state='ok', + type=AType.GNOCCHI_AGGREGATION_BY_RESOURCES_THRESHOLD, + rule=None): + if rule is None: + rule = {"evaluation_periods": 3, + "metric": "cpu_util", + "aggregation_method": "mean", + "granularity": 300, + "threshold": 50.0, + "query": [{"=": + {"resource_id": + "6df1747a-ef31-4897-854e-ffa2ae568e45"}}], + "comparison_operator": "ge", + "resource_type": "instance" + } + + return {AodhProps.DESCRIPTION: "test", + AodhProps.TIMESTAMP: "2016-11-09T01:39:13.839584", + AodhProps.ENABLED: True, + AodhProps.STATE_TIMESTAMP: "2016-11-09T01:39:13.839584", + AodhProps.ALARM_ID: "7e5c3754-e2eb-4782-ae00-7da5ded8568b", + AodhProps.REPEAT_ACTIONS: False, + AodhProps.PROJECT_ID: "c365d18fcc03493187016ae743f0cc4d", + AodhProps.NAME: "test", + AodhProps.SEVERITY: "low", + AodhProps.RESOURCE_ID: "88cd2d1d-8af4-4d00-9b5e-f82f8c8b0f8d", + AodhProps.TYPE: type, + AodhProps.STATE: state, + AodhProps.RULE: rule} + def _create_alarm_data_gnocchi(self, state="ok", type="gnocchi_resources_threshold",