deduced alarm notifier, is subscribed to graph changes, upon a deduced alarm added an activate notification is sent to the notifers service

Change-Id: I4b51ea0a1f0db8c42ab8d2c9497ebecebe6d07a0
This commit is contained in:
Idan Hefetz 2016-04-12 11:21:03 +00:00
parent 199262a27e
commit 4ec0e3a8f8
14 changed files with 422 additions and 127 deletions

View File

@ -35,16 +35,12 @@ class AodhDriver(AlarmDriverBase):
return alarm[AodhProps.NAME]
def _get_alarms(self):
try:
aodh_alarms = self.client.alarms.list()
return [self._convert_alarm(alarm) for alarm in aodh_alarms]
except Exception as e:
LOG.exception("Exception: %s", e)
return []
# TODO(iafek): enable the code below
# try:
# aodh_alarms = self.client.alarms.list()
# return [_convert_alarm(alarm)
# for alarm in aodh_alarms]
# except Exception:
# LOG.error("Exception: %s", traceback.print_exc())
# return []
def _is_erroneous(self, alarm):
return alarm and alarm[AodhProps.STATE] != AodhState.OK
@ -56,22 +52,30 @@ class AodhDriver(AlarmDriverBase):
def _is_valid(self, alarm):
return True
@staticmethod
def _convert_event_alarm(alarm):
converted_alarm = AodhDriver._convert_base_alarm(alarm)
event_type, resource_id = \
AodhDriver._parse_event_rule(alarm.event_rule)
converted_alarm[AodhProps.EVENT_TYPE] = event_type
converted_alarm[AodhProps.RESOURCE_ID] = resource_id
return converted_alarm
@classmethod
def _convert_event_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[AodhProps.EVENT_TYPE] = alarm.event_rule[AodhProps.EVENT_TYPE],
res[AodhProps.RESOURCE_ID] = _parse_query(alarm.event_rule,
AodhProps.RESOURCE_ID)
return res
@staticmethod
def _convert_threshold_alarm(alarm):
converted_alarm = AodhDriver._convert_base_alarm(alarm)
converted_alarm[AodhProps.STATE_TIMESTAMP] = alarm.state_timestamp
converted_alarm[AodhProps.RESOURCE_ID] = \
AodhDriver._parse_threshold_rule(alarm.threshold_rule)
return converted_alarm
@classmethod
def _convert_threshold_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[AodhProps.STATE_TIMESTAMP] = alarm.state_timestamp
res[AodhProps.RESOURCE_ID] = _parse_query(alarm.threshold_rule,
AodhProps.RESOURCE_ID)
return res
@classmethod
def _convert_vitrage_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[AodhProps.VITRAGE_ID] = _parse_query(alarm.event_rule,
AodhProps.VITRAGE_ID)
res[AodhProps.RESOURCE_ID] = _parse_query(alarm.event_rule,
AodhProps.RESOURCE_ID)
return res
@staticmethod
def _convert_base_alarm(alarm):
@ -90,32 +94,27 @@ class AodhDriver(AlarmDriverBase):
AodhProps.TYPE: alarm.type
}
@staticmethod
def _parse_event_rule(rule):
event_type = rule[AodhProps.EVENT_TYPE]
resource_id = \
AodhDriver._parse_resource_id(rule[AodhProps.QUERY])
return event_type, resource_id
@staticmethod
def _parse_threshold_rule(rule):
return AodhDriver._parse_resource_id(rule[AodhProps.QUERY])
@staticmethod
def _parse_resource_id(query_fields):
for query in query_fields:
field = query['field']
if field == AodhProps.RESOURCE_ID:
return query['value']
else:
return None
@classmethod
def _convert_alarm(cls, alarm):
alarm_type = alarm.type
if alarm_type == AodhProps.EVENT and _is_vitrage_alarm(alarm):
return cls._convert_vitrage_alarm(alarm)
elif alarm_type == AodhProps.EVENT:
return cls._convert_event_alarm(alarm)
elif alarm_type == AodhProps.THRESHOLD:
return cls._convert_threshold_alarm(alarm)
else:
LOG.warning('Unsupported Aodh alarm of type %s' % alarm_type)
def _convert_alarm(alarm):
alarm_type = alarm.type
if alarm_type == AodhProps.EVENT:
return AodhDriver._convert_event_alarm(alarm)
elif alarm_type == AodhProps.THRESHOLD:
return AodhDriver._convert_threshold_alarm(alarm)
else:
LOG.info('Unsupported Aodh alarm of type %s' % alarm_type)
def _parse_query(data, key):
query_fields = data.get(AodhProps.QUERY, {})
for query in query_fields:
field = query['field']
if field == key:
return query['value']
return None
def _is_vitrage_alarm(alarm):
return _parse_query(alarm.event_rule, AodhProps.VITRAGE_ID) is not None

View File

@ -30,6 +30,7 @@ class AodhProperties(object):
THRESHOLD = 'threshold'
TIMESTAMP = 'timestamp'
TYPE = 'type'
VITRAGE_ID = 'vitrage_id'
class AodhState(object):

View File

@ -36,10 +36,14 @@ class AodhTransformer(AlarmTransformerBase):
super(AodhTransformer, self).__init__(transformers)
def _create_snapshot_entity_vertex(self, entity_event):
self._create_vertex(entity_event)
if _is_vitrage_alarm(entity_event):
return self._create_merge_alarm_vertex(entity_event)
return self._create_vertex(entity_event)
def _create_update_entity_vertex(self, entity_event):
self._create_vertex(entity_event)
if _is_vitrage_alarm(entity_event):
return self._create_merge_alarm_vertex(entity_event)
return self._create_vertex(entity_event)
def _create_vertex(self, entity_event):
metadata = {
@ -74,6 +78,30 @@ class AodhTransformer(AlarmTransformerBase):
update_timestamp=update_timestamp,
metadata=metadata)
def _create_merge_alarm_vertex(self, entity_event):
"""Handle an alarm that already has a vitrage_id
This is a deduced alarm created in aodh by vitrage, so it already
exists in the graph.
This function will update the exiting vertex (and not create a new one)
"""
metadata = {
AodhProps.DESCRIPTION: entity_event[AodhProps.DESCRIPTION],
VProps.PROJECT_ID: entity_event[AodhProps.PROJECT_ID],
}
sample_timestamp = entity_event[DSProps.SAMPLE_DATE]
update_timestamp = self._format_update_timestamp(
AodhTransformer._timestamp(entity_event), sample_timestamp)
return graph_utils.create_vertex(
self._create_entity_key(entity_event),
entity_id=entity_event.get(AodhProps.ALARM_ID),
entity_category=EntityCategory.ALARM,
entity_type='vitrage',
sample_timestamp=sample_timestamp,
update_timestamp=update_timestamp,
metadata=metadata)
def _create_neighbors(self, entity_event):
graph_neighbors = entity_event.get(self.QUERY_RESULT, [])
result = []
@ -89,6 +117,9 @@ class AodhTransformer(AlarmTransformerBase):
return entity_event[AodhProps.STATE] == self.STATUS_OK
def _create_entity_key(self, entity_event):
if _is_vitrage_alarm(entity_event):
return entity_event.get(AodhProps.VITRAGE_ID)
sync_type = entity_event[DSProps.SYNC_TYPE]
alarm_name = entity_event[AodhProps.NAME]
resource_id = entity_event[AodhProps.RESOURCE_ID]
@ -110,3 +141,7 @@ class AodhTransformer(AlarmTransformerBase):
if not affected_resource_id:
return None
return {VProps.ID: affected_resource_id}
def _is_vitrage_alarm(entity_event):
return entity_event.get(AodhProps.VITRAGE_ID) is not None

View File

@ -22,4 +22,8 @@ OPTS = [
help='A path for the configuration files of the data sources'
' values'
),
cfg.StrOpt('notifier_topic',
default='vitrage.graph',
help='The topic that vitrage-graph uses for alarm '
'notification messages.'),
]

View File

@ -0,0 +1,95 @@
# Copyright 2016 - Nokia
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
import oslo_messaging
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import NotifierEventTypes
from vitrage.common.constants import VertexProperties as VProps
from vitrage.evaluator.actions import evaluator_event_transformer as evaluator
from vitrage.messaging import get_transport
LOG = log.getLogger(__name__)
class DeducedAlarmNotifier(object):
"""Allows writing to message bus"""
def __init__(self, conf):
self.oslo_notifier = None
try:
topic = conf.entity_graph.notifier_topic
notifier_plugins = conf.notifiers
if not topic or not notifier_plugins:
LOG.info('DeducedAlarmNotifier is disabled')
return
self.oslo_notifier = oslo_messaging.Notifier(
get_transport(conf),
driver='messagingv2',
publisher_id='vitrage.deduced',
topic=topic)
except Exception:
LOG.info('DeducedAlarmNotifier missing configuration')
@property
def enabled(self):
return self.oslo_notifier is not None
def notify_when_applicable(self, before, current, is_vertex):
"""Callback subscribed to driver.graph updates
:param is_vertex:
:param before: The graph element (vertex or edge) prior to the
change that happened. None if the element was just created.
:param current: The graph element (vertex or edge) after the
change that happened. Deleted elements should arrive with the
is_deleted property set to True
"""
notification_type = _get_notification_type(before, current, is_vertex)
if not notification_type:
return
LOG.debug('DeducedAlarmNotifier : %s', notification_type)
LOG.debug('DeducedAlarmNotifier : %s', current.properties)
try:
self.oslo_notifier.info({}, notification_type, current.properties)
except Exception as e:
LOG.exception('DeducedAlarmNotifier cannot notify - %s', e)
def _get_notification_type(before, current, is_vertex):
if not is_vertex:
return None
if not _is_active_deduced_alarm(before) and \
_is_active_deduced_alarm(current):
return NotifierEventTypes.ACTIVATE_DEDUCED_ALARM_EVENT
if _is_active_deduced_alarm(before) and \
not _is_active_deduced_alarm(current):
return NotifierEventTypes.DEACTIVATE_DEDUCED_ALARM_EVENT
def _is_active_deduced_alarm(vertex):
if not vertex:
return False
if not (vertex.get(VProps.CATEGORY) == EntityCategory.ALARM and
vertex.get(VProps.TYPE) == evaluator.VITRAGE_TYPE):
return False
if vertex.get(VProps.IS_DELETED, False) or \
vertex.get(VProps.IS_PLACEHOLDER, False):
return False
return True

View File

@ -20,6 +20,7 @@ from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.transformer_base import TransformerBase
from vitrage.entity_graph.processor import base as processor
from vitrage.entity_graph.processor import entity_graph
from vitrage.entity_graph.processor.notifier import DeducedAlarmNotifier
from vitrage.entity_graph.states.state_manager import StateManager
from vitrage.entity_graph.transformer_manager import TransformerManager
from vitrage.graph import Direction
@ -38,6 +39,7 @@ class Processor(processor.ProcessorBase):
self.initialization_status = initialization_status
self.entity_graph = entity_graph.EntityGraph("Entity Graph") if \
e_graph is None else e_graph
self._notifier = DeducedAlarmNotifier(conf)
def process_event(self, event):
"""Decides which action to run on given event
@ -55,7 +57,7 @@ class Processor(processor.ProcessorBase):
self._enrich_event(event)
entity = self.transformer_manager.transform(event)
self._calculate_aggregated_state(entity.vertex, entity.action)
return self.actions[entity.action](entity.vertex, entity.neighbors)
self.actions[entity.action](entity.vertex, entity.neighbors)
def create_entity(self, new_vertex, neighbors):
"""Adds new vertex to the entity graph
@ -97,8 +99,8 @@ class Processor(processor.ProcessorBase):
updated_vertex)
self._update_neighbors(updated_vertex, neighbors)
else:
LOG.info("Update event arrived on invalid resource: %s",
updated_vertex)
LOG.warning("Update event arrived on invalid resource: %s",
updated_vertex)
def delete_entity(self, deleted_vertex, neighbors):
"""Deletes the vertex from the entity graph
@ -132,8 +134,8 @@ class Processor(processor.ProcessorBase):
self.entity_graph.mark_vertex_as_deleted(deleted_vertex)
else:
LOG.info("Delete event arrived on invalid resource: %s",
deleted_vertex)
LOG.warning("Delete event arrived on invalid resource: %s",
deleted_vertex)
def update_relationship(self, entity_vertex, neighbors):
LOG.debug('Update relationship in entity graph:\n%s', neighbors)
@ -159,6 +161,12 @@ class Processor(processor.ProcessorBase):
len(self.conf.datasources.types):
self.initialization_status.status = \
self.initialization_status.RECEIVED_ALL_END_MESSAGES
self.do_on_initialization_end()
def do_on_initialization_end(self):
if self._notifier.enabled:
self.entity_graph.subscribe(self._notifier.notify_when_applicable)
LOG.info('Graph notifications subscription added')
def _update_neighbors(self, vertex, neighbors):
"""Updates vertices neighbor connections

View File

@ -58,7 +58,7 @@ class NXGraph(Graph):
self_copy._g = self._g.copy()
return self_copy
@Notifier.add_notify
@Notifier.update_notify
def add_vertex(self, v):
"""Add a vertex to the graph
@ -71,7 +71,7 @@ class NXGraph(Graph):
properties_copy = copy.copy(v.properties)
self._g.add_node(n=v.vertex_id, attr_dict=properties_copy)
@Notifier.add_notify
@Notifier.update_notify
def add_edge(self, e):
"""Add an edge to the graph

View File

@ -12,4 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
pass
from oslo_config import cfg
OPTS = [
cfg.ListOpt('notifiers',
help='Names of enabled notifiers (example aodh)'),
]

View File

@ -11,87 +11,92 @@
# 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 random
import string
from oslo_log import log as logging
from vitrage import clients
from vitrage.common.constants import NotifierEventTypes
from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.aodh.properties import AodhState
from vitrage.entity_graph.states.normalized_alarm_severity import \
NormalizedAlarmSeverity
from vitrage.notifier.plugins.base import NotifierBase
LOG = logging.getLogger(__name__)
def aodh_alarm_name_generator(name, unique=None, size=6,
chars=string.ascii_uppercase + string.digits):
if unique:
return name.join(['_', unique])
else:
unique = ''.join(random.choice(chars) for _ in range(size))
return name.join(['_', unique])
severity_translation = {
NormalizedAlarmSeverity.CRITICAL: 'critical',
NormalizedAlarmSeverity.SEVERE: 'moderate',
NormalizedAlarmSeverity.WARNING: 'low',
}
class AodhNotifier(NotifierBase):
@staticmethod
def get_notifier_name():
return 'aodh'
def __init__(self, conf):
super(AodhNotifier, self).__init__(conf)
self.client = clients.ceilometer_client(conf)
def process_event(self, data, event_type):
if event_type == NotifierEventTypes.DEACTIVATE_DEDUCED_ALARM_EVENT:
self._deactivate_aodh_alarm(data)
elif event_type == NotifierEventTypes.ACTIVATE_DEDUCED_ALARM_EVENT:
self._activate_aodh_alarm(data)
response = None
if event_type == NotifierEventTypes.ACTIVATE_DEDUCED_ALARM_EVENT:
if not data.get(VProps.ID):
response = self._create_aodh_alarm(data, AodhState.ALARM)
else:
response = self._update_aodh_alarm(data, AodhState.ALARM)
elif event_type == NotifierEventTypes.DEACTIVATE_DEDUCED_ALARM_EVENT:
response = self._update_aodh_alarm(data, AodhState.OK)
# noinspection PyMethodMayBeStatic
def _activate_aodh_alarm(self, data):
LOG.info('### Activate aodh alarm')
# alarm_name = aodh_alarm_name_generator(
# data.get(VProps.NAME),
# data.get('affected_resource_id'))
# query = [dict(
# field='resource_id',
# type='string',
# op='eq',
# value=data.get('affected_resource_id'))]
# severity = data.get(VProps.SEVERITY)
# try:
# alarm = self.client.alarms.create(
# name=alarm_name,
# description='Vitrage deduced alarm',
# query=query,
# severity=severity,
# state='alarm',
# type='event',
# event_rule={"event_type": '*'})
# LOG.info('Aodh Alarm created: ' + str(alarm))
# except Exception as e:
# LOG.exception('Failed to create Aodh Alarm, Got Exception: %s',e)
# name
# description
# type' : event or threshold
# threshold_rule
# event_rule
# state': ok, alarm, insufficient data
# severity': moderate, critical, low
# enabled
# alarm_actions
# ok_actions
# insufficient_data_actions
# repeat_actions
# project_id
# user_id
# time_constraints
if response and response.alarm_id:
LOG.info('Aodh Alarm id %s: ', response.alarm_id)
else:
LOG.error('Failed to %s Aodh Alarm \n%s', event_type, str(data))
# noinspection PyMethodMayBeStatic
def _deactivate_aodh_alarm(self, data):
LOG.info('### Deactivate aodh alarm')
# try:
# alarm = self.client.alarms.update(
# alarm_id=data.get(VProps.ID),
# state='ok')
# LOG.info('Aodh Alarm deactivated ' + str(alarm))
# except Exception as e:
# LOG.exception('Failed to update Aodh Alarm, Got Exception: %s',e)
def _create_aodh_alarm(self, alarm, state):
alarm_request = _alarm_request(alarm, state)
try:
LOG.info('Aodh Alarm - Activate: ' + str(alarm_request))
return self.client.alarms.create(**alarm_request)
except Exception as e:
LOG.exception('Failed to activate Aodh Alarm Got Exception: %s', e)
return
def _update_aodh_alarm(self, alarm, state):
aodh_id = alarm.get(VProps.ID)
try:
LOG.info('Aodh Alarm $%s update state %s', aodh_id, state)
return self.client.alarms.update(alarm_id=aodh_id, state=state)
except Exception as e:
LOG.exception('Failed to update Aodh Alarm Got Exception: %s', e)
return
def _alarm_request(data, state):
# TODO(ihefetz) resource id should come from the alarm
affected_resource_id = data.get(VProps.VITRAGE_ID).replace(
'ALARM:vitrage:deduced_vm_alarm:RESOURCE:nova.instance:', '')
alarm_name = data.get(VProps.NAME)
aodh_alarm_name = '_'.join([alarm_name, affected_resource_id])
severity = severity_translation.get(data.get(VProps.SEVERITY), 'low')
return dict(
name=aodh_alarm_name,
description=u'Vitrage deduced alarm',
event_rule=dict(query=[
dict(
field=u'resource_id',
type='',
op=u'eq',
value=affected_resource_id),
dict(
field=u'vitrage_id',
type='',
op=u'eq',
value=data.get(VProps.VITRAGE_ID))]),
severity=severity,
state=state,
type=u'event')

View File

@ -25,3 +25,8 @@ class NotifierBase(object):
@abc.abstractmethod
def process_event(self, data, event_type):
pass
@staticmethod
@abc.abstractmethod
def get_notifier_name():
pass

View File

@ -28,9 +28,9 @@ class VitrageNotifierService(os_service.Service):
def __init__(self, conf):
super(VitrageNotifierService, self).__init__()
self.conf = conf
self.notifiers = [AodhNotifier(conf)]
self.notifiers = self.get_notifier_plugins(conf)
transport = messaging.get_transport(conf)
target = oslo_messaging.Target(topic='stam')
target = oslo_messaging.Target(topic=conf.entity_graph.notifier_topic)
self.listener = messaging.get_notification_listener(
transport, [target],
[VitrageEventEndpoint(self.notifiers)])
@ -52,6 +52,20 @@ class VitrageNotifierService(os_service.Service):
LOG.info("Vitrage Notifier Service - Stopped!")
@staticmethod
def get_notifier_plugins(conf):
notifiers = []
conf_notifier_names = conf.notifiers
if not conf_notifier_names:
LOG.info('There are no notifier plugins in configuration')
return []
for plugin in [AodhNotifier]:
plugin_name = plugin.get_notifier_name()
if plugin_name in conf_notifier_names:
LOG.info('Notifier plugin %s started', plugin_name)
notifiers.append(plugin(conf))
return notifiers
class VitrageEventEndpoint(object):

View File

@ -23,6 +23,7 @@ import vitrage.datasources
import vitrage.entity_graph.consistency
import vitrage.evaluator
import vitrage.keystone_client
import vitrage.notifier
import vitrage.rpc
DATASOURCES_PATH = 'vitrage.datasources.'
@ -39,7 +40,10 @@ def list_opts():
('consistency', vitrage.entity_graph.consistency.OPTS),
('entity_graph', vitrage.entity_graph.OPTS),
('service_credentials', vitrage.keystone_client.OPTS),
('DEFAULT', itertools.chain(vitrage.clients.OPTS, vitrage.rpc.OPTS))
('DEFAULT', itertools.chain(
vitrage.clients.OPTS,
vitrage.rpc.OPTS,
vitrage.notifier.OPTS))
]

View File

@ -0,0 +1,15 @@
# Copyright 2015 - Alcatel-Lucent
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__author__ = 'stack'

View File

@ -0,0 +1,105 @@
# Copyright 2016 - Alcatel-Lucent
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
test_vitrage graph
----------------------------------
Tests for `vitrage` graph driver
"""
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import NotifierEventTypes as NType
from vitrage.common.constants import VertexProperties as VProps
from vitrage.entity_graph.processor.notifier import _get_notification_type
from vitrage.evaluator.actions import evaluator_event_transformer as evaluator
from vitrage.graph import Vertex
from vitrage.tests import base
resource = Vertex('123', {
VProps.CATEGORY: EntityCategory.RESOURCE,
VProps.TYPE: 'some_resource_type',
VProps.IS_DELETED: False,
VProps.IS_PLACEHOLDER: False,
}
)
deduced_alarm = Vertex('123', {
VProps.CATEGORY: EntityCategory.ALARM,
VProps.TYPE: evaluator.VITRAGE_TYPE,
VProps.IS_DELETED: False,
VProps.IS_PLACEHOLDER: False,
}
)
non_deduced_alarm = Vertex('123', {
VProps.CATEGORY: EntityCategory.ALARM,
VProps.TYPE: 'TEST_ALARM',
VProps.IS_DELETED: False,
VProps.IS_PLACEHOLDER: True,
}
)
deleted_alarm = Vertex('123', {
VProps.CATEGORY: EntityCategory.ALARM,
VProps.TYPE: evaluator.VITRAGE_TYPE,
VProps.IS_DELETED: True,
VProps.IS_PLACEHOLDER: False,
}
)
placeholder_alarm = Vertex('123', {
VProps.CATEGORY: EntityCategory.ALARM,
VProps.TYPE: evaluator.VITRAGE_TYPE,
VProps.IS_DELETED: False,
VProps.IS_PLACEHOLDER: True,
}
)
class GraphTest(base.BaseTest):
def test_notification_type_new_alarm(self):
ret = _get_notification_type(None, deduced_alarm, True)
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT, ret,
'new alarm should notify activate')
ret = _get_notification_type(None, non_deduced_alarm, True)
self.assertIsNone(ret, 'alarm that is not a deduced alarm')
def test_notification_type_deleted_alarm(self):
ret = _get_notification_type(deduced_alarm, deleted_alarm, True)
self.assertEqual(NType.DEACTIVATE_DEDUCED_ALARM_EVENT, ret,
'deleted alarm should notify deactivate')
def test_notification_type_resource_vertex(self):
ret = _get_notification_type(None, resource, True)
self.assertIsNone(ret, 'any non alarm vertex should be ignored')
def test_notification_type_updated_alarm(self):
ret = _get_notification_type(deduced_alarm, deduced_alarm, True)
self.assertIsNone(ret, 'A not new alarm vertex should be ignored')
ret = _get_notification_type(deleted_alarm, deduced_alarm, True)
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT, ret,
'old alarm become not deleted should notify activate')
ret = _get_notification_type(placeholder_alarm, deduced_alarm, True)
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT, ret,
'placeholder become active should notify activate')
def test_notification_type_placeholder_alarm(self):
ret = _get_notification_type(None, placeholder_alarm, True)
self.assertIsNone(ret, 'A not new alarm vertex should be ignored')