Implement aodh alarm notification
Implement: blueprint aodh-message-bus-notifications Signed-off-by: dongwenjuan <dong.wenjuan@zte.com.cn> Change-Id: Ibd55345dea3b465006cdbd89bff2e67c3ac9daba
This commit is contained in:
parent
c4542eaaa5
commit
d57af3234d
@ -53,4 +53,13 @@ Enabling Vitrage in DevStack
|
|||||||
notification_topics = notifications,vitrage_notifications
|
notification_topics = notifications,vitrage_notifications
|
||||||
notification_driver=messagingv2
|
notification_driver=messagingv2
|
||||||
|
|
||||||
7. Run ``./stack.sh``
|
7. Add this to add notification from aodh to vitrage
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
[[post-config|$AODH_CONF]]
|
||||||
|
[oslo_messaging_notifications]
|
||||||
|
driver = messagingv2
|
||||||
|
topics = notifications,vitrage_notifications
|
||||||
|
|
||||||
|
8. Run ``./stack.sh``
|
||||||
|
@ -41,6 +41,7 @@ ENABLED_SERVICES+=,vitrage-api,vitrage-graph
|
|||||||
ENABLED_SERVICES+=,key,aodi-api,aodh-notifier,aodh-evaluator
|
ENABLED_SERVICES+=,key,aodi-api,aodh-notifier,aodh-evaluator
|
||||||
ENABLED_SERVICES+=,ceilometer-alarm-evaluator,ceilometer-alarm-notifier
|
ENABLED_SERVICES+=,ceilometer-alarm-evaluator,ceilometer-alarm-notifier
|
||||||
ENABLED_SERVICES+=,ceilometer-api
|
ENABLED_SERVICES+=,ceilometer-api
|
||||||
|
ENABLED_SERVICES+=,aodh-api
|
||||||
export ENABLED_SERVICES
|
export ENABLED_SERVICES
|
||||||
|
|
||||||
|
|
||||||
@ -69,6 +70,11 @@ notification_topics = notifications,vitrage_notifications
|
|||||||
notification_driver = messagingv2
|
notification_driver = messagingv2
|
||||||
policy_file = /etc/heat/policy.json-tempest
|
policy_file = /etc/heat/policy.json-tempest
|
||||||
|
|
||||||
|
[[post-config|\$AODH_CONF]]
|
||||||
|
[oslo_messaging_notifications]
|
||||||
|
driver = messagingv2
|
||||||
|
topics = notifications, vitrage_notifications
|
||||||
|
|
||||||
[[post-config|\$VITRAGE_CONF]]
|
[[post-config|\$VITRAGE_CONF]]
|
||||||
[static_physical]
|
[static_physical]
|
||||||
changes_interval = 5
|
changes_interval = 5
|
||||||
|
@ -85,15 +85,16 @@ class AlarmDriverBase(DriverBase):
|
|||||||
def _get_all_alarms(self):
|
def _get_all_alarms(self):
|
||||||
alarms = self._get_alarms()
|
alarms = self._get_alarms()
|
||||||
self._enrich_alarms(alarms)
|
self._enrich_alarms(alarms)
|
||||||
return self._filter_and_cache_alarms(alarms,
|
return self._filter_and_cache_alarms(
|
||||||
AlarmDriverBase._filter_get_all)
|
alarms,
|
||||||
|
self._filter_get_erroneous)
|
||||||
|
|
||||||
def _get_changed_alarms(self):
|
def _get_changed_alarms(self):
|
||||||
alarms = self._get_alarms()
|
alarms = self._get_alarms()
|
||||||
self._enrich_alarms(alarms)
|
self._enrich_alarms(alarms)
|
||||||
return self._filter_and_cache_alarms(
|
return self._filter_and_cache_alarms(
|
||||||
alarms,
|
alarms,
|
||||||
AlarmDriverBase._filter_get_changes)
|
self._filter_get_change)
|
||||||
|
|
||||||
def _filter_and_cache_alarms(self, alarms, filter_):
|
def _filter_and_cache_alarms(self, alarms, filter_):
|
||||||
alarms_to_update = []
|
alarms_to_update = []
|
||||||
@ -101,16 +102,11 @@ class AlarmDriverBase(DriverBase):
|
|||||||
|
|
||||||
for alarm in alarms:
|
for alarm in alarms:
|
||||||
alarm_key = self._alarm_key(alarm)
|
alarm_key = self._alarm_key(alarm)
|
||||||
old_alarm, timestamp = self.cache.get(alarm_key, (None, None))
|
old_alarm = self.cache.get(alarm_key, (None, None))[0]
|
||||||
|
if self._filter_and_cache_alarm(
|
||||||
if filter_(self, alarm, old_alarm):
|
alarm, old_alarm, filter_, now):
|
||||||
# delete state changed alarm: alarm->OK
|
|
||||||
if not self._is_erroneous(alarm):
|
|
||||||
alarm[DSProps.EVENT_TYPE] = GraphAction.DELETE_ENTITY
|
|
||||||
alarms_to_update.append(alarm)
|
alarms_to_update.append(alarm)
|
||||||
|
|
||||||
self.cache[alarm_key] = alarm, now
|
|
||||||
|
|
||||||
# add alarms that were deleted
|
# add alarms that were deleted
|
||||||
values = list(self.cache.values())
|
values = list(self.cache.values())
|
||||||
for cached_alarm, timestamp in values:
|
for cached_alarm, timestamp in values:
|
||||||
@ -122,13 +118,16 @@ class AlarmDriverBase(DriverBase):
|
|||||||
|
|
||||||
return alarms_to_update
|
return alarms_to_update
|
||||||
|
|
||||||
def _filter_get_all(self, alarm, old_alarm):
|
def _filter_get_valid(self, alarm, old_alarm):
|
||||||
|
return alarm if self._is_valid(alarm) else None
|
||||||
|
|
||||||
|
def _filter_get_erroneous(self, alarm, old_alarm):
|
||||||
return alarm \
|
return alarm \
|
||||||
if self._is_valid(alarm) and \
|
if self._is_valid(alarm) and \
|
||||||
(self._is_erroneous(alarm) or self._is_erroneous(old_alarm)) \
|
(self._is_erroneous(alarm) or self._is_erroneous(old_alarm)) \
|
||||||
else None
|
else None
|
||||||
|
|
||||||
def _filter_get_changes(self, alarm, old_alarm):
|
def _filter_get_change(self, alarm, old_alarm):
|
||||||
if not self._is_valid(alarm):
|
if not self._is_valid(alarm):
|
||||||
return None
|
return None
|
||||||
if self._status_changed(alarm, old_alarm):
|
if self._status_changed(alarm, old_alarm):
|
||||||
@ -137,3 +136,8 @@ class AlarmDriverBase(DriverBase):
|
|||||||
return alarm
|
return alarm
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _filter_and_cache_alarm(self, alarm, old_alarm, filter_, time):
|
||||||
|
ret = alarm if filter_(alarm, old_alarm) else None
|
||||||
|
self.cache[self._alarm_key(alarm)] = alarm, time
|
||||||
|
return ret
|
||||||
|
@ -14,9 +14,11 @@
|
|||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from vitrage.common.constants import DatasourceAction
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||||
from vitrage.common.constants import EntityCategory
|
from vitrage.common.constants import EntityCategory
|
||||||
from vitrage.common.constants import GraphAction
|
from vitrage.common.constants import GraphAction
|
||||||
|
from vitrage.common.exception import VitrageTransformerError
|
||||||
from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
|
from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
|
||||||
from vitrage.datasources import transformer_base as tbase
|
from vitrage.datasources import transformer_base as tbase
|
||||||
|
|
||||||
@ -31,6 +33,27 @@ class AlarmTransformerBase(tbase.TransformerBase):
|
|||||||
def _ok_status(self, entity_event):
|
def _ok_status(self, entity_event):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _extract_graph_action(self, entity_event):
|
||||||
|
|
||||||
|
if DSProps.EVENT_TYPE in entity_event and \
|
||||||
|
entity_event[DSProps.EVENT_TYPE] == GraphAction.DELETE_ENTITY:
|
||||||
|
return entity_event[DSProps.EVENT_TYPE]
|
||||||
|
|
||||||
|
datasource_action = entity_event[DSProps.DATASOURCE_ACTION]
|
||||||
|
|
||||||
|
if datasource_action in \
|
||||||
|
(DatasourceAction.UPDATE, DatasourceAction.SNAPSHOT):
|
||||||
|
return GraphAction.DELETE_ENTITY if self._ok_status(entity_event) else \
|
||||||
|
self.GRAPH_ACTION_MAPPING.get(
|
||||||
|
entity_event.get(DSProps.EVENT_TYPE, None),
|
||||||
|
GraphAction.UPDATE_ENTITY)
|
||||||
|
|
||||||
|
if DatasourceAction.INIT_SNAPSHOT == datasource_action:
|
||||||
|
return GraphAction.CREATE_ENTITY
|
||||||
|
|
||||||
|
raise VitrageTransformerError('Invalid datasource action: (%s)'
|
||||||
|
% datasource_action)
|
||||||
|
|
||||||
def create_placeholder_vertex(self, **kwargs):
|
def create_placeholder_vertex(self, **kwargs):
|
||||||
LOG.info('An alarm cannot be a placeholder')
|
LOG.info('An alarm cannot be a placeholder')
|
||||||
pass
|
pass
|
||||||
|
@ -28,7 +28,7 @@ OPTS = [
|
|||||||
help='Aodh driver class path',
|
help='Aodh driver class path',
|
||||||
required=True),
|
required=True),
|
||||||
cfg.StrOpt('update_method',
|
cfg.StrOpt('update_method',
|
||||||
default=UpdateMethod.PULL,
|
default=UpdateMethod.PUSH,
|
||||||
help='None: updates only via Vitrage periodic snapshots.'
|
help='None: updates only via Vitrage periodic snapshots.'
|
||||||
'Pull: updates every [changes_interval] seconds.'
|
'Pull: updates every [changes_interval] seconds.'
|
||||||
'Push: updates by getting notifications from the'
|
'Push: updates by getting notifications from the'
|
||||||
|
@ -14,20 +14,27 @@
|
|||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
|
from vitrage.common.constants import DatasourceAction
|
||||||
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||||
from vitrage.datasources.alarm_driver_base import AlarmDriverBase
|
from vitrage.datasources.alarm_driver_base import AlarmDriverBase
|
||||||
from vitrage.datasources.aodh import AODH_DATASOURCE
|
from vitrage.datasources.aodh import AODH_DATASOURCE
|
||||||
|
from vitrage.datasources.aodh.properties import AodhEventType
|
||||||
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
||||||
from vitrage.datasources.aodh.properties import AodhState
|
from vitrage.datasources.aodh.properties import AodhState
|
||||||
from vitrage import os_clients
|
from vitrage import os_clients
|
||||||
|
from vitrage.utils import datetime as datetime_utils
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AodhDriver(AlarmDriverBase):
|
class AodhDriver(AlarmDriverBase):
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
super(AodhDriver, self).__init__()
|
super(AodhDriver, self).__init__()
|
||||||
self._client = None
|
self._client = None
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
self._init_aodh_event_actions()
|
||||||
|
self._cache_all_alarms()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def client(self):
|
def client(self):
|
||||||
@ -41,12 +48,17 @@ class AodhDriver(AlarmDriverBase):
|
|||||||
def _alarm_key(self, alarm):
|
def _alarm_key(self, alarm):
|
||||||
return alarm[AodhProps.ALARM_ID]
|
return alarm[AodhProps.ALARM_ID]
|
||||||
|
|
||||||
|
def _cache_all_alarms(self):
|
||||||
|
alarms = self._get_alarms()
|
||||||
|
self._filter_and_cache_alarms(alarms,
|
||||||
|
self._filter_get_valid)
|
||||||
|
|
||||||
def _get_alarms(self):
|
def _get_alarms(self):
|
||||||
try:
|
try:
|
||||||
aodh_alarms = self.client.alarms.list()
|
aodh_alarms = self.client.alarms.list()
|
||||||
return [self._convert_alarm(alarm) for alarm in aodh_alarms]
|
return [self._convert_alarm(alarm) for alarm in aodh_alarms]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception("Exception: %s", e)
|
LOG.exception("Failed to get all alarms, Exception: %s", e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _is_erroneous(self, alarm):
|
def _is_erroneous(self, alarm):
|
||||||
@ -104,7 +116,8 @@ class AodhDriver(AlarmDriverBase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _convert_alarm(cls, alarm):
|
def _convert_alarm(cls, alarm):
|
||||||
alarm_type = alarm.type
|
alarm_type = alarm.type
|
||||||
if alarm_type == AodhProps.EVENT and _is_vitrage_alarm(alarm):
|
if alarm_type == AodhProps.EVENT and \
|
||||||
|
_is_vitrage_alarm(alarm.event_rule):
|
||||||
return cls._convert_vitrage_alarm(alarm)
|
return cls._convert_vitrage_alarm(alarm)
|
||||||
elif alarm_type == AodhProps.EVENT:
|
elif alarm_type == AodhProps.EVENT:
|
||||||
return cls._convert_event_alarm(alarm)
|
return cls._convert_event_alarm(alarm)
|
||||||
@ -113,6 +126,167 @@ class AodhDriver(AlarmDriverBase):
|
|||||||
else:
|
else:
|
||||||
LOG.warning('Unsupported Aodh alarm of type %s' % alarm_type)
|
LOG.warning('Unsupported Aodh alarm of type %s' % alarm_type)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_event_types():
|
||||||
|
# Add event_types to receive notifications about
|
||||||
|
return [AodhEventType.CREATION,
|
||||||
|
AodhEventType.STATE_TRANSITION,
|
||||||
|
AodhEventType.RULE_CHANGE,
|
||||||
|
AodhEventType.DELETION]
|
||||||
|
|
||||||
|
def enrich_event(self, event, event_type):
|
||||||
|
if event_type in self.actions:
|
||||||
|
entity = self.actions[event_type](event)
|
||||||
|
else:
|
||||||
|
LOG.warning('Unsupported Aodh event type %s' % event_type)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Don't need to update entity, only update the cache
|
||||||
|
if entity is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
entity[DSProps.EVENT_TYPE] = event_type
|
||||||
|
|
||||||
|
return AodhDriver.make_pickleable([entity],
|
||||||
|
AODH_DATASOURCE,
|
||||||
|
DatasourceAction.UPDATE)[0]
|
||||||
|
|
||||||
|
def _init_aodh_event_actions(self):
|
||||||
|
self.actions = {
|
||||||
|
AodhEventType.CREATION: self._convert_alarm_creation_event,
|
||||||
|
AodhEventType.RULE_CHANGE: self._convert_alarm_rule_change_event,
|
||||||
|
AodhEventType.STATE_TRANSITION:
|
||||||
|
self._convert_alarm_state_transition_event,
|
||||||
|
AodhEventType.DELETION: self._convert_alarm_deletion_event
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _convert_base_event(cls, event):
|
||||||
|
return {
|
||||||
|
AodhProps.PROJECT_ID: event[AodhProps.PROJECT_ID],
|
||||||
|
AodhProps.ALARM_ID: event[AodhProps.ALARM_ID],
|
||||||
|
AodhProps.SEVERITY: event[AodhProps.SEVERITY],
|
||||||
|
AodhProps.TIMESTAMP: event[AodhProps.TIMESTAMP],
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _convert_vitrage_alarm_event(cls, rule):
|
||||||
|
return {
|
||||||
|
AodhProps.VITRAGE_ID: _parse_query(rule, AodhProps.VITRAGE_ID),
|
||||||
|
AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _convert_threshold_alarm_event(cls, event):
|
||||||
|
rule = event[AodhProps.DETAIL][AodhProps.RULE]
|
||||||
|
return {
|
||||||
|
AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID),
|
||||||
|
AodhProps.STATE_TIMESTAMP: event[AodhProps.STATE_TIMESTAMP]
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _convert_event_alarm_event(cls, rule):
|
||||||
|
return {
|
||||||
|
AodhProps.EVENT_TYPE: rule[AodhProps.EVENT_TYPE],
|
||||||
|
AodhProps.RESOURCE_ID:
|
||||||
|
_parse_query(rule, AodhProps.EVENT_RESOURCE_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _convert_detail_event(cls, event):
|
||||||
|
alarm_info = event[AodhProps.DETAIL]
|
||||||
|
alarm_rule = alarm_info[AodhProps.RULE]
|
||||||
|
|
||||||
|
entity_detail = {
|
||||||
|
AodhProps.DESCRIPTION: alarm_info[AodhProps.DESCRIPTION],
|
||||||
|
AodhProps.ENABLED: alarm_info[AodhProps.ENABLED],
|
||||||
|
AodhProps.NAME: alarm_info[AodhProps.NAME],
|
||||||
|
AodhProps.STATE: alarm_info[AodhProps.STATE],
|
||||||
|
AodhProps.REPEAT_ACTIONS: alarm_info[AodhProps.REPEAT_ACTIONS],
|
||||||
|
AodhProps.TYPE: alarm_info[AodhProps.TYPE]
|
||||||
|
}
|
||||||
|
|
||||||
|
if _is_vitrage_alarm(alarm_rule):
|
||||||
|
entity_detail.update(cls._convert_vitrage_alarm_event(alarm_rule))
|
||||||
|
elif entity_detail[AodhProps.TYPE] == AodhProps.EVENT:
|
||||||
|
entity_detail.update(cls._convert_event_alarm_event(alarm_rule))
|
||||||
|
elif entity_detail[AodhProps.TYPE] == AodhProps.THRESHOLD:
|
||||||
|
entity_detail.update(
|
||||||
|
cls._convert_threshold_alarm_event(event))
|
||||||
|
|
||||||
|
return entity_detail
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse_changed_rule(cls, change_rule):
|
||||||
|
entity = {}
|
||||||
|
if AodhProps.EVENT_TYPE in change_rule:
|
||||||
|
entity[AodhProps.EVENT_TYPE] = change_rule[AodhProps.EVENT_TYPE]
|
||||||
|
if 'query' in change_rule:
|
||||||
|
event_resource_id = \
|
||||||
|
_parse_query(change_rule, AodhProps.EVENT_RESOURCE_ID)
|
||||||
|
resource_id = \
|
||||||
|
_parse_query(change_rule, AodhProps.RESOURCE_ID)
|
||||||
|
if event_resource_id or resource_id:
|
||||||
|
entity[AodhProps.RESOURCE_ID] = event_resource_id if \
|
||||||
|
event_resource_id is not None else resource_id
|
||||||
|
|
||||||
|
return entity
|
||||||
|
|
||||||
|
def _convert_alarm_creation_event(self, event):
|
||||||
|
entity = self._convert_base_event(event)
|
||||||
|
detail = self._convert_detail_event(event)
|
||||||
|
entity.update(detail)
|
||||||
|
|
||||||
|
return self._filter_and_cache_alarm(entity, None,
|
||||||
|
self._filter_get_erroneous,
|
||||||
|
datetime_utils.utcnow(False))
|
||||||
|
|
||||||
|
def _convert_alarm_rule_change_event(self, event):
|
||||||
|
"""handle alarm rule change notification
|
||||||
|
|
||||||
|
example of changed rule:
|
||||||
|
"detail": {"severity": "critical",
|
||||||
|
"rule":
|
||||||
|
{"query": [{"field": "traits.resource_id",
|
||||||
|
"type": "",
|
||||||
|
"value": "1",
|
||||||
|
"op": "eq"}],
|
||||||
|
"event_type": "instance.update"}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
alarm_key = self._alarm_key(event)
|
||||||
|
old_alarm = self.cache.get(alarm_key, (None, None))[0]
|
||||||
|
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
|
||||||
|
if changed_type == AodhProps.RULE:
|
||||||
|
entity.update(self._parse_changed_rule(
|
||||||
|
changed_rule[changed_type]))
|
||||||
|
# handle other changed alarm properties
|
||||||
|
elif changed_type in AodhProps.__dict__.values():
|
||||||
|
entity[changed_type] = changed_info
|
||||||
|
|
||||||
|
return self._filter_and_cache_alarm(entity, old_alarm,
|
||||||
|
self._filter_get_erroneous,
|
||||||
|
datetime_utils.utcnow(False))
|
||||||
|
|
||||||
|
def _convert_alarm_state_transition_event(self, event):
|
||||||
|
alarm_key = self._alarm_key(event)
|
||||||
|
old_alarm = self.cache.get(alarm_key, (None, None))[0]
|
||||||
|
entity = old_alarm.copy()
|
||||||
|
entity[AodhProps.STATE] = event[AodhProps.DETAIL][AodhProps.STATE]
|
||||||
|
|
||||||
|
return self._filter_and_cache_alarm(entity, old_alarm,
|
||||||
|
self._filter_get_change,
|
||||||
|
datetime_utils.utcnow(False))
|
||||||
|
|
||||||
|
def _convert_alarm_deletion_event(self, event):
|
||||||
|
alarm_key = self._alarm_key(event)
|
||||||
|
alarm = self.cache.pop(alarm_key)[0]
|
||||||
|
return alarm if self._is_erroneous(alarm) else None
|
||||||
|
|
||||||
|
|
||||||
def _parse_query(data, key):
|
def _parse_query(data, key):
|
||||||
query_fields = data.get(AodhProps.QUERY, {})
|
query_fields = data.get(AodhProps.QUERY, {})
|
||||||
@ -123,5 +297,5 @@ def _parse_query(data, key):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _is_vitrage_alarm(alarm):
|
def _is_vitrage_alarm(rule):
|
||||||
return _parse_query(alarm.event_rule, AodhProps.VITRAGE_ID) is not None
|
return _parse_query(rule, AodhProps.VITRAGE_ID) is not None
|
||||||
|
@ -32,9 +32,18 @@ class AodhProperties(object):
|
|||||||
TIMESTAMP = 'timestamp'
|
TIMESTAMP = 'timestamp'
|
||||||
TYPE = 'type'
|
TYPE = 'type'
|
||||||
VITRAGE_ID = 'vitrage_id'
|
VITRAGE_ID = 'vitrage_id'
|
||||||
|
DETAIL = 'detail'
|
||||||
|
RULE = 'rule'
|
||||||
|
|
||||||
|
|
||||||
class AodhState(object):
|
class AodhState(object):
|
||||||
OK = 'ok'
|
OK = 'ok'
|
||||||
ALARM = 'alarm'
|
ALARM = 'alarm'
|
||||||
INSUFFICIENT_DATA = 'insufficient_data'
|
INSUFFICIENT_DATA = 'insufficient_data'
|
||||||
|
|
||||||
|
|
||||||
|
class AodhEventType(object):
|
||||||
|
CREATION = 'alarm.creation'
|
||||||
|
RULE_CHANGE = 'alarm.rule_change'
|
||||||
|
STATE_TRANSITION = 'alarm.state_transition'
|
||||||
|
DELETION = 'alarm.deletion'
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||||
from vitrage.common.constants import EdgeLabel
|
from vitrage.common.constants import EdgeLabel
|
||||||
from vitrage.common.constants import EntityCategory
|
from vitrage.common.constants import EntityCategory
|
||||||
|
from vitrage.common.constants import GraphAction
|
||||||
from vitrage.common.constants import VertexProperties as VProps
|
from vitrage.common.constants import VertexProperties as VProps
|
||||||
from vitrage.datasources.alarm_transformer_base import AlarmTransformerBase
|
from vitrage.datasources.alarm_transformer_base import AlarmTransformerBase
|
||||||
from vitrage.datasources.aodh import AODH_DATASOURCE
|
from vitrage.datasources.aodh import AODH_DATASOURCE
|
||||||
|
from vitrage.datasources.aodh.properties import AodhEventType
|
||||||
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
||||||
from vitrage.datasources.aodh.properties import AodhState
|
from vitrage.datasources.aodh.properties import AodhState
|
||||||
from vitrage.datasources import transformer_base as tbase
|
from vitrage.datasources import transformer_base as tbase
|
||||||
@ -28,6 +30,11 @@ from vitrage.utils import datetime as datetime_utils
|
|||||||
|
|
||||||
class AodhTransformer(AlarmTransformerBase):
|
class AodhTransformer(AlarmTransformerBase):
|
||||||
|
|
||||||
|
# Event types which need to refer them differently
|
||||||
|
GRAPH_ACTION_MAPPING = {
|
||||||
|
AodhEventType.DELETION: GraphAction.DELETE_ENTITY,
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, transformers, conf):
|
def __init__(self, transformers, conf):
|
||||||
super(AodhTransformer, self).__init__(transformers, conf)
|
super(AodhTransformer, self).__init__(transformers, conf)
|
||||||
|
|
||||||
|
@ -95,5 +95,6 @@ class NotificationsEndpoint(object):
|
|||||||
|
|
||||||
def _enqueue_events(self, enriched_events):
|
def _enqueue_events(self, enriched_events):
|
||||||
for event in enriched_events:
|
for event in enriched_events:
|
||||||
self.enqueue_callback(event)
|
if event is not None:
|
||||||
LOG.debug('EVENT ENQUEUED: \n' + str(event))
|
self.enqueue_callback(event)
|
||||||
|
LOG.debug('EVENT ENQUEUED: \n' + str(event))
|
||||||
|
@ -212,7 +212,6 @@ class TransformerBase(object):
|
|||||||
:return: the action that the processor needs to perform
|
:return: the action that the processor needs to perform
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if DSProps.EVENT_TYPE in entity_event and \
|
if DSProps.EVENT_TYPE in entity_event and \
|
||||||
entity_event[DSProps.EVENT_TYPE] in GraphAction.__dict__.values():
|
entity_event[DSProps.EVENT_TYPE] in GraphAction.__dict__.values():
|
||||||
return entity_event[DSProps.EVENT_TYPE]
|
return entity_event[DSProps.EVENT_TYPE]
|
||||||
|
@ -19,7 +19,6 @@ from six.moves import queue
|
|||||||
from vitrage.common.constants import DatasourceAction
|
from vitrage.common.constants import DatasourceAction
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||||
from vitrage.common.constants import EdgeProperties as EProps
|
from vitrage.common.constants import EdgeProperties as EProps
|
||||||
from vitrage.common.constants import GraphAction
|
|
||||||
from vitrage.common.constants import VertexProperties as VProps
|
from vitrage.common.constants import VertexProperties as VProps
|
||||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
||||||
from vitrage.evaluator.scenario_evaluator import ScenarioEvaluator
|
from vitrage.evaluator.scenario_evaluator import ScenarioEvaluator
|
||||||
@ -239,7 +238,6 @@ class TestScenarioEvaluator(TestFunctionalBase):
|
|||||||
|
|
||||||
# remove WARNING nagios alarm, leaving only CRITICAL one
|
# remove WARNING nagios alarm, leaving only CRITICAL one
|
||||||
warning_test['status'] = 'OK'
|
warning_test['status'] = 'OK'
|
||||||
warning_test[DSProps.EVENT_TYPE] = GraphAction.DELETE_ENTITY
|
|
||||||
host_v = self.get_host_after_event(event_queue, warning_test,
|
host_v = self.get_host_after_event(event_queue, warning_test,
|
||||||
processor, _TARGET_HOST)
|
processor, _TARGET_HOST)
|
||||||
alarms = \
|
alarms = \
|
||||||
@ -251,7 +249,6 @@ class TestScenarioEvaluator(TestFunctionalBase):
|
|||||||
|
|
||||||
# next disable the alarm
|
# next disable the alarm
|
||||||
critical_test['status'] = 'OK'
|
critical_test['status'] = 'OK'
|
||||||
critical_test[DSProps.EVENT_TYPE] = GraphAction.DELETE_ENTITY
|
|
||||||
host_v = self.get_host_after_event(event_queue, critical_test,
|
host_v = self.get_host_after_event(event_queue, critical_test,
|
||||||
processor, _TARGET_HOST)
|
processor, _TARGET_HOST)
|
||||||
alarms = \
|
alarms = \
|
||||||
|
@ -435,3 +435,34 @@ def simple_zabbix_alarm_generators(host_num,
|
|||||||
})
|
})
|
||||||
|
|
||||||
return tg.get_trace_generators(test_entity_spec_list)
|
return tg.get_trace_generators(test_entity_spec_list)
|
||||||
|
|
||||||
|
|
||||||
|
def simple_aodh_alarm_notification_generators(alarm_num,
|
||||||
|
update_events=0,
|
||||||
|
update_vals=None):
|
||||||
|
"""A function for returning aodh alarm event generators.
|
||||||
|
|
||||||
|
Returns generators for a given number of Aodh alarms.
|
||||||
|
|
||||||
|
:param alarm_num: number of alarms
|
||||||
|
:param update_events: number of update alarms
|
||||||
|
:param update_vals: preset vals for ALL update events
|
||||||
|
:return: generators for alarm_num zones as specified
|
||||||
|
|
||||||
|
Returns generators for a given number of alarms and
|
||||||
|
instances.
|
||||||
|
"""
|
||||||
|
|
||||||
|
alarms = ['alarm-{0}'.format(index) for index in range(alarm_num)]
|
||||||
|
|
||||||
|
test_entity_spec_list = [
|
||||||
|
{tg.DYNAMIC_INFO_FKEY: tg.DRIVER_AODH_UPDATE_D,
|
||||||
|
tg.STATIC_INFO_FKEY: None,
|
||||||
|
tg.MAPPING_KEY: alarms,
|
||||||
|
tg.EXTERNAL_INFO_KEY: update_vals,
|
||||||
|
tg.NAME_KEY: 'Aodh update generator',
|
||||||
|
tg.NUM_EVENTS: update_events
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return tg.get_trace_generators(test_entity_spec_list)
|
||||||
|
@ -158,3 +158,33 @@ def simple_aodh_alarm_generators(alarm_num,
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
return tg.get_trace_generators(test_entity_spec_list)
|
return tg.get_trace_generators(test_entity_spec_list)
|
||||||
|
|
||||||
|
|
||||||
|
def simple_aodh_update_alarm_generators(alarm_num,
|
||||||
|
update_events=0,
|
||||||
|
update_vals=None):
|
||||||
|
"""A simple function for returning aodh alarm generators.
|
||||||
|
|
||||||
|
Returns generators for a given number of alarms.
|
||||||
|
|
||||||
|
:param alarm_num: number of alarms
|
||||||
|
:param update_events: number of update events
|
||||||
|
:param update_vals: values of update
|
||||||
|
:return: generators for alarm_num alarms as specified
|
||||||
|
"""
|
||||||
|
|
||||||
|
mapping = [('alarm-{0}'.format(ind), 'resource-{0}'.format(ind))
|
||||||
|
for ind in range(alarm_num)
|
||||||
|
]
|
||||||
|
|
||||||
|
test_entity_spec_list = [
|
||||||
|
{tg.DYNAMIC_INFO_FKEY: tg.TRANS_AODH_UPDATE_D,
|
||||||
|
tg.DYNAMIC_INFO_FPATH: tg.MOCK_TRANSFORMER_PATH,
|
||||||
|
tg.STATIC_INFO_FKEY: None,
|
||||||
|
tg.MAPPING_KEY: mapping,
|
||||||
|
tg.EXTERNAL_INFO_KEY: update_vals,
|
||||||
|
tg.NAME_KEY: 'Aodh update generator',
|
||||||
|
tg.NUM_EVENTS: update_events
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return tg.get_trace_generators(test_entity_spec_list)
|
||||||
|
@ -44,6 +44,7 @@ GENERATOR = 'generator'
|
|||||||
# Mock driver specs
|
# Mock driver specs
|
||||||
MOCK_DRIVER_PATH = '%s/mock_configurations/driver' % \
|
MOCK_DRIVER_PATH = '%s/mock_configurations/driver' % \
|
||||||
utils.get_resources_dir()
|
utils.get_resources_dir()
|
||||||
|
DRIVER_AODH_UPDATE_D = 'driver_aodh_update_dynamic.json'
|
||||||
DRIVER_HOST_SNAPSHOT_D = 'driver_host_snapshot_dynamic.json'
|
DRIVER_HOST_SNAPSHOT_D = 'driver_host_snapshot_dynamic.json'
|
||||||
DRIVER_INST_SNAPSHOT_D = 'driver_inst_snapshot_dynamic.json'
|
DRIVER_INST_SNAPSHOT_D = 'driver_inst_snapshot_dynamic.json'
|
||||||
DRIVER_INST_SNAPSHOT_S = 'driver_inst_snapshot_static.json'
|
DRIVER_INST_SNAPSHOT_S = 'driver_inst_snapshot_static.json'
|
||||||
@ -64,6 +65,7 @@ DRIVER_ZONE_SNAPSHOT_D = 'driver_zone_snapshot_dynamic.json'
|
|||||||
MOCK_TRANSFORMER_PATH = '%s/mock_configurations/transformer' % \
|
MOCK_TRANSFORMER_PATH = '%s/mock_configurations/transformer' % \
|
||||||
utils.get_resources_dir()
|
utils.get_resources_dir()
|
||||||
TRANS_AODH_SNAPSHOT_D = 'transformer_aodh_snapshot_dynamic.json'
|
TRANS_AODH_SNAPSHOT_D = 'transformer_aodh_snapshot_dynamic.json'
|
||||||
|
TRANS_AODH_UPDATE_D = 'transformer_aodh_update_dynamic.json'
|
||||||
TRANS_INST_SNAPSHOT_D = 'transformer_inst_snapshot_dynamic.json'
|
TRANS_INST_SNAPSHOT_D = 'transformer_inst_snapshot_dynamic.json'
|
||||||
TRANS_INST_SNAPSHOT_S = 'transformer_inst_snapshot_static.json'
|
TRANS_INST_SNAPSHOT_S = 'transformer_inst_snapshot_static.json'
|
||||||
TRANS_HOST_SNAPSHOT_D = 'transformer_host_snapshot_dynamic.json'
|
TRANS_HOST_SNAPSHOT_D = 'transformer_host_snapshot_dynamic.json'
|
||||||
@ -105,7 +107,8 @@ class EventTraceGenerator(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
static_info_parsers = \
|
static_info_parsers = \
|
||||||
{DRIVER_INST_SNAPSHOT_D: _get_vm_snapshot_driver_values,
|
{DRIVER_AODH_UPDATE_D: _get_aodh_alarm_update_driver_values,
|
||||||
|
DRIVER_INST_SNAPSHOT_D: _get_vm_snapshot_driver_values,
|
||||||
DRIVER_INST_UPDATE_D: _get_vm_update_driver_values,
|
DRIVER_INST_UPDATE_D: _get_vm_update_driver_values,
|
||||||
DRIVER_HOST_SNAPSHOT_D: _get_host_snapshot_driver_values,
|
DRIVER_HOST_SNAPSHOT_D: _get_host_snapshot_driver_values,
|
||||||
DRIVER_ZONE_SNAPSHOT_D: _get_zone_snapshot_driver_values,
|
DRIVER_ZONE_SNAPSHOT_D: _get_zone_snapshot_driver_values,
|
||||||
@ -120,6 +123,7 @@ class EventTraceGenerator(object):
|
|||||||
_get_consistency_update_driver_values,
|
_get_consistency_update_driver_values,
|
||||||
|
|
||||||
TRANS_AODH_SNAPSHOT_D: _get_trans_aodh_alarm_snapshot_values,
|
TRANS_AODH_SNAPSHOT_D: _get_trans_aodh_alarm_snapshot_values,
|
||||||
|
TRANS_AODH_UPDATE_D: _get_trans_aodh_alarm_snapshot_values,
|
||||||
TRANS_INST_SNAPSHOT_D: _get_trans_vm_snapshot_values,
|
TRANS_INST_SNAPSHOT_D: _get_trans_vm_snapshot_values,
|
||||||
TRANS_HOST_SNAPSHOT_D: _get_trans_host_snapshot_values,
|
TRANS_HOST_SNAPSHOT_D: _get_trans_host_snapshot_values,
|
||||||
TRANS_ZONE_SNAPSHOT_D: _get_trans_zone_snapshot_values}
|
TRANS_ZONE_SNAPSHOT_D: _get_trans_zone_snapshot_values}
|
||||||
@ -604,6 +608,19 @@ def _get_trans_aodh_alarm_snapshot_values(spec):
|
|||||||
return static_values
|
return static_values
|
||||||
|
|
||||||
|
|
||||||
|
def _get_aodh_alarm_update_driver_values(spec):
|
||||||
|
alarms = spec[MAPPING_KEY]
|
||||||
|
static_info_re = None
|
||||||
|
if spec[STATIC_INFO_FKEY] is not None:
|
||||||
|
static_info_re = utils.load_specs(spec[STATIC_INFO_FKEY])
|
||||||
|
static_values = []
|
||||||
|
for alarm in alarms:
|
||||||
|
alarm_id = {"alarm_id": alarm}
|
||||||
|
static_values.append(combine_data(
|
||||||
|
static_info_re, alarm_id, spec.get(EXTERNAL_INFO_KEY, None)))
|
||||||
|
return static_values
|
||||||
|
|
||||||
|
|
||||||
def combine_data(static_info_re, mapping_info, external_info):
|
def combine_data(static_info_re, mapping_info, external_info):
|
||||||
if external_info:
|
if external_info:
|
||||||
mapping_info = utils.merge_vals(mapping_info, external_info)
|
mapping_info = utils.merge_vals(mapping_info, external_info)
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"on_behalf_of": "c365d18fcc03493187016ae743f0cc4d",
|
||||||
|
"user_id": "3b0fd6ce33f24e38a4f415c380245e96",
|
||||||
|
"severity": "low",
|
||||||
|
"event_id": "e47602a8-cecd-4dd2-b50c-0f54ebca642a",
|
||||||
|
"timestamp": "2016-11-29T08:05:37.877253",
|
||||||
|
"alarm_id": "alarm-0",
|
||||||
|
"project_id": "c365d18fcc03493187016ae743f0cc4d",
|
||||||
|
"type": "",
|
||||||
|
"detail": {}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"alarm_id": "21127fbd-7633-494e-8e5c-fdf415cdec0c",
|
||||||
|
"description": "test",
|
||||||
|
"enabled": "True",
|
||||||
|
"name": "test",
|
||||||
|
"project_id": "f0895991f44044ccba8e62b201b70360",
|
||||||
|
"repeat_actions": "False",
|
||||||
|
"severity": "low",
|
||||||
|
"state": "alarm",
|
||||||
|
"timestamp": "2016-11-29T06:31:50.094836",
|
||||||
|
"state_timestamp": "2016-11-11T01:58:36.054090",
|
||||||
|
"type": "event",
|
||||||
|
"event_type": "compute.instance.*",
|
||||||
|
"resource_id": "3dcee183-ca42-4ccb-84af-9f0196b2e160",
|
||||||
|
"vitrage_event_type": "alarm.creation",
|
||||||
|
"vitrage_entity_type": "aodh",
|
||||||
|
"vitrage_datasource_action": "update",
|
||||||
|
"vitrage_sample_date": "2016-11-29T06:31:50.094836",
|
||||||
|
"graph_query_result": [
|
||||||
|
{
|
||||||
|
"category": "RESOURCE",
|
||||||
|
"is_placeholder": false,
|
||||||
|
"is_deleted": false,
|
||||||
|
"name": "test",
|
||||||
|
"update_timestamp": "2016-12-02 07:18:05.628479+00:00",
|
||||||
|
"sample_timestamp": "2016-12-02 07:18:05.628479+00:00",
|
||||||
|
"operational_state": "OK",
|
||||||
|
"aggregated_state": "ACTIVE",
|
||||||
|
"state": "ACTIVE",
|
||||||
|
"graph_index": 3,
|
||||||
|
"project_id": "f0895991f44044ccba8e62b201b70360",
|
||||||
|
"type": "nova.instance",
|
||||||
|
"id": "3dcee183-ca42-4ccb-84af-9f0196b2e160"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,114 @@
|
|||||||
|
# Copyright 2016 - ZTE, 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 vitrage.common.constants import DatasourceAction
|
||||||
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||||
|
from vitrage.common.constants import EdgeLabel
|
||||||
|
from vitrage.common.constants import EntityCategory
|
||||||
|
from vitrage.common.constants import GraphAction
|
||||||
|
from vitrage.common.constants import VertexProperties as VProps
|
||||||
|
from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
|
||||||
|
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
||||||
|
from vitrage.datasources.aodh.properties import AodhState
|
||||||
|
from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
|
||||||
|
from vitrage.datasources.transformer_base import TransformerBase
|
||||||
|
from vitrage.graph.driver.elements import Vertex
|
||||||
|
from vitrage.tests import base
|
||||||
|
|
||||||
|
|
||||||
|
class AodhTransformerBaseTest(base.BaseTest):
|
||||||
|
|
||||||
|
def _validate_aodh_vertex_props(self, vertex, event):
|
||||||
|
|
||||||
|
self.assertEqual(EntityCategory.ALARM, vertex[VProps.CATEGORY])
|
||||||
|
self.assertEqual(event[DSProps.ENTITY_TYPE], vertex[VProps.TYPE])
|
||||||
|
self.assertEqual(event[AodhProps.NAME], vertex[VProps.NAME])
|
||||||
|
self.assertEqual(event[AodhProps.SEVERITY], vertex[VProps.SEVERITY])
|
||||||
|
self.assertEqual(event[AodhProps.DESCRIPTION],
|
||||||
|
vertex[AodhProps.DESCRIPTION])
|
||||||
|
self.assertEqual(event[AodhProps.ENABLED], vertex[AodhProps.ENABLED])
|
||||||
|
self.assertEqual(event[AodhProps.PROJECT_ID],
|
||||||
|
vertex[VProps.PROJECT_ID])
|
||||||
|
self.assertEqual(event[AodhProps.REPEAT_ACTIONS],
|
||||||
|
vertex[AodhProps.REPEAT_ACTIONS])
|
||||||
|
self.assertEqual(event[AodhProps.TYPE], vertex['alarm_type'])
|
||||||
|
if event[AodhProps.TYPE] == AodhProps.EVENT:
|
||||||
|
self.assertEqual(event[AodhProps.EVENT_TYPE],
|
||||||
|
vertex[AodhProps.EVENT_TYPE])
|
||||||
|
elif event[AodhProps.TYPE] == AodhProps.THRESHOLD:
|
||||||
|
self.assertEqual(event[AodhProps.STATE_TIMESTAMP],
|
||||||
|
vertex[AodhProps.STATE_TIMESTAMP])
|
||||||
|
self.assertEqual(event[DSProps.SAMPLE_DATE],
|
||||||
|
vertex[VProps.SAMPLE_TIMESTAMP])
|
||||||
|
|
||||||
|
event_status = event[AodhProps.STATE]
|
||||||
|
if event_status == AodhState.OK:
|
||||||
|
self.assertEqual(AlarmProps.INACTIVE_STATE,
|
||||||
|
vertex[VProps.STATE])
|
||||||
|
else:
|
||||||
|
self.assertEqual(AlarmProps.ACTIVE_STATE,
|
||||||
|
vertex[VProps.STATE])
|
||||||
|
self.assertFalse(vertex[VProps.IS_PLACEHOLDER])
|
||||||
|
self.assertFalse(vertex[VProps.IS_DELETED])
|
||||||
|
|
||||||
|
def _validate_action(self, alarm, wrapper):
|
||||||
|
if DSProps.EVENT_TYPE in alarm \
|
||||||
|
and alarm[DSProps.EVENT_TYPE] in GraphAction.__dict__.values():
|
||||||
|
self.assertEqual(alarm[DSProps.EVENT_TYPE], wrapper.action)
|
||||||
|
return
|
||||||
|
|
||||||
|
ds_action = alarm[DSProps.DATASOURCE_ACTION]
|
||||||
|
if ds_action in (DatasourceAction.SNAPSHOT, DatasourceAction.UPDATE):
|
||||||
|
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
|
||||||
|
else:
|
||||||
|
self.assertEqual(GraphAction.CREATE_ENTITY, wrapper.action)
|
||||||
|
|
||||||
|
def _validate_neighbors(self, neighbors, alarm_id, event):
|
||||||
|
resource_counter = 0
|
||||||
|
|
||||||
|
for neighbor in neighbors:
|
||||||
|
resource_id = event[AodhProps.RESOURCE_ID]
|
||||||
|
self._validate_instance_neighbor(neighbor,
|
||||||
|
resource_id,
|
||||||
|
alarm_id)
|
||||||
|
resource_counter += 1
|
||||||
|
|
||||||
|
self.assertEqual(1,
|
||||||
|
resource_counter,
|
||||||
|
'Alarm can be belonged to only one resource')
|
||||||
|
|
||||||
|
def _validate_instance_neighbor(self,
|
||||||
|
alarm_neighbor,
|
||||||
|
resource_id,
|
||||||
|
alarm_vertex_id):
|
||||||
|
# validate neighbor vertex
|
||||||
|
self.assertEqual(EntityCategory.RESOURCE,
|
||||||
|
alarm_neighbor.vertex[VProps.CATEGORY])
|
||||||
|
self.assertEqual(NOVA_INSTANCE_DATASOURCE,
|
||||||
|
alarm_neighbor.vertex[VProps.TYPE])
|
||||||
|
self.assertEqual(resource_id, alarm_neighbor.vertex[VProps.ID])
|
||||||
|
self.assertFalse(alarm_neighbor.vertex[VProps.IS_PLACEHOLDER])
|
||||||
|
self.assertFalse(alarm_neighbor.vertex[VProps.IS_DELETED])
|
||||||
|
|
||||||
|
# Validate neighbor edge
|
||||||
|
edge = alarm_neighbor.edge
|
||||||
|
self.assertEqual(edge.target_id, alarm_neighbor.vertex.vertex_id)
|
||||||
|
self.assertEqual(edge.source_id, alarm_vertex_id)
|
||||||
|
self.assertEqual(edge.label, EdgeLabel.ON)
|
||||||
|
|
||||||
|
def _convert_dist_to_vertex(self, neighbor):
|
||||||
|
ver_id = neighbor[VProps.CATEGORY] + \
|
||||||
|
TransformerBase.KEY_SEPARATOR + neighbor[VProps.TYPE] + \
|
||||||
|
TransformerBase.KEY_SEPARATOR + neighbor[VProps.ID]
|
||||||
|
return Vertex(vertex_id=ver_id, properties=neighbor)
|
27
vitrage/tests/unit/datasources/aodh/mock_driver.py
Normal file
27
vitrage/tests/unit/datasources/aodh/mock_driver.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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 vitrage.datasources.aodh.driver import AodhDriver
|
||||||
|
|
||||||
|
|
||||||
|
class MockAodhDriver(AodhDriver):
|
||||||
|
"""A aodh driver for tests.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
super(MockAodhDriver, self).__init__(conf)
|
||||||
|
|
||||||
|
def _cache_all_alarms(self):
|
||||||
|
pass
|
222
vitrage/tests/unit/datasources/aodh/test_aodh_driver.py
Normal file
222
vitrage/tests/unit/datasources/aodh/test_aodh_driver.py
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
# Copyright 2016 - ZTE, 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_config import cfg
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
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 AodhProperties as AodhProps
|
||||||
|
from vitrage.tests import base
|
||||||
|
from vitrage.tests.mocks import mock_driver
|
||||||
|
from vitrage.tests.unit.datasources.aodh.mock_driver import MockAodhDriver
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AodhDriverTest(base.BaseTest):
|
||||||
|
|
||||||
|
OPTS = [
|
||||||
|
cfg.StrOpt('update_method',
|
||||||
|
default=UpdateMethod.PUSH),
|
||||||
|
]
|
||||||
|
|
||||||
|
# noinspection PyPep8Naming
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.conf = cfg.ConfigOpts()
|
||||||
|
cls.conf.register_opts(cls.OPTS, group=AODH_DATASOURCE)
|
||||||
|
|
||||||
|
def test_enrich_event(self):
|
||||||
|
|
||||||
|
aodh_driver = MockAodhDriver(self.conf)
|
||||||
|
|
||||||
|
# 1. alarm creation with 'ok' state
|
||||||
|
# prepare data
|
||||||
|
detail_data = {"type": "creation",
|
||||||
|
AodhProps.DETAIL: self._extract_alarm_data()}
|
||||||
|
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])
|
||||||
|
self.assertEqual(entity[DSProps.EVENT_TYPE],
|
||||||
|
AodhEventType.STATE_TRANSITION)
|
||||||
|
|
||||||
|
# 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": "creation",
|
||||||
|
AodhProps.DETAIL:
|
||||||
|
self._extract_alarm_data(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.assertIsNone(entity[AodhProps.RESOURCE_ID])
|
||||||
|
self.assertEqual(entity[AodhProps.EVENT_TYPE], "*")
|
||||||
|
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:
|
||||||
|
{"query": [{"field": "traits.resource_id",
|
||||||
|
"type": "",
|
||||||
|
"value": "1",
|
||||||
|
"op": "eq"}],
|
||||||
|
"event_type": "instance.update"}}}
|
||||||
|
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[AodhProps.EVENT_TYPE],
|
||||||
|
alarm[AodhProps.DETAIL][AodhProps.RULE][AodhProps.EVENT_TYPE])
|
||||||
|
self.assertEqual(entity[AodhProps.RESOURCE_ID],
|
||||||
|
"1")
|
||||||
|
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 _extract_alarm_data(self,
|
||||||
|
state="ok",
|
||||||
|
type="event",
|
||||||
|
rule={"query": [],
|
||||||
|
"event_type": "*"}):
|
||||||
|
|
||||||
|
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.TYPE: type,
|
||||||
|
AodhProps.STATE: state,
|
||||||
|
AodhProps.RULE: rule}
|
||||||
|
|
||||||
|
def _validate_aodh_entity_comm_props(self, entity, alarm):
|
||||||
|
|
||||||
|
self.assertEqual(entity[AodhProps.ALARM_ID],
|
||||||
|
alarm[AodhProps.ALARM_ID])
|
||||||
|
self.assertEqual(entity[AodhProps.PROJECT_ID],
|
||||||
|
alarm[AodhProps.PROJECT_ID])
|
||||||
|
self.assertEqual(entity[AodhProps.TIMESTAMP],
|
||||||
|
alarm[AodhProps.TIMESTAMP])
|
||||||
|
self.assertEqual(entity[AodhProps.DESCRIPTION],
|
||||||
|
alarm[AodhProps.DETAIL][AodhProps.DESCRIPTION])
|
||||||
|
self.assertEqual(entity[AodhProps.ENABLED],
|
||||||
|
alarm[AodhProps.DETAIL][AodhProps.ENABLED])
|
||||||
|
self.assertEqual(entity[AodhProps.NAME],
|
||||||
|
alarm[AodhProps.DETAIL][AodhProps.NAME])
|
||||||
|
self.assertEqual(entity[AodhProps.REPEAT_ACTIONS],
|
||||||
|
alarm[AodhProps.DETAIL][AodhProps.REPEAT_ACTIONS])
|
||||||
|
self.assertEqual(entity[AodhProps.TYPE],
|
||||||
|
alarm[AodhProps.DETAIL][AodhProps.TYPE])
|
@ -15,32 +15,25 @@
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from vitrage.common.constants import DatasourceAction
|
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||||
from vitrage.common.constants import EdgeLabel
|
|
||||||
from vitrage.common.constants import EntityCategory
|
from vitrage.common.constants import EntityCategory
|
||||||
from vitrage.common.constants import GraphAction
|
|
||||||
from vitrage.common.constants import UpdateMethod
|
from vitrage.common.constants import UpdateMethod
|
||||||
from vitrage.common.constants import VertexProperties as VProps
|
|
||||||
from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
|
|
||||||
from vitrage.datasources.aodh import AODH_DATASOURCE
|
from vitrage.datasources.aodh import AODH_DATASOURCE
|
||||||
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
|
||||||
from vitrage.datasources.aodh.properties import AodhState
|
|
||||||
from vitrage.datasources.aodh.transformer import AodhTransformer
|
from vitrage.datasources.aodh.transformer import AodhTransformer
|
||||||
from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
|
|
||||||
from vitrage.datasources.transformer_base import TransformerBase
|
from vitrage.datasources.transformer_base import TransformerBase
|
||||||
from vitrage.graph.driver.elements import Vertex
|
|
||||||
from vitrage.tests import base
|
|
||||||
from vitrage.tests.mocks import mock_transformer as mock_sync
|
from vitrage.tests.mocks import mock_transformer as mock_sync
|
||||||
|
from vitrage.tests.unit.datasources.aodh.aodh_transformer_base_test import \
|
||||||
|
AodhTransformerBaseTest
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TestAodhAlarmTransformer(base.BaseTest):
|
class TestAodhAlarmTransformer(AodhTransformerBaseTest):
|
||||||
|
|
||||||
OPTS = [
|
OPTS = [
|
||||||
cfg.StrOpt('update_method',
|
cfg.StrOpt('update_method',
|
||||||
default=UpdateMethod.PUSH),
|
default=UpdateMethod.PULL),
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -112,86 +105,49 @@ class TestAodhAlarmTransformer(base.BaseTest):
|
|||||||
|
|
||||||
self._validate_action(event, wrapper)
|
self._validate_action(event, wrapper)
|
||||||
|
|
||||||
def _validate_aodh_vertex_props(self, vertex, event):
|
|
||||||
|
|
||||||
self.assertEqual(EntityCategory.ALARM, vertex[VProps.CATEGORY])
|
class TestAodhAlarmPushTransformer(AodhTransformerBaseTest):
|
||||||
self.assertEqual(event[DSProps.ENTITY_TYPE], vertex[VProps.TYPE])
|
|
||||||
self.assertEqual(event[AodhProps.NAME], vertex[VProps.NAME])
|
|
||||||
self.assertEqual(event[AodhProps.SEVERITY], vertex[VProps.SEVERITY])
|
|
||||||
self.assertEqual(event[AodhProps.DESCRIPTION],
|
|
||||||
vertex[AodhProps.DESCRIPTION])
|
|
||||||
self.assertEqual(event[AodhProps.ENABLED], vertex[AodhProps.ENABLED])
|
|
||||||
self.assertEqual(event[AodhProps.PROJECT_ID],
|
|
||||||
vertex[VProps.PROJECT_ID])
|
|
||||||
self.assertEqual(event[AodhProps.REPEAT_ACTIONS],
|
|
||||||
vertex[AodhProps.REPEAT_ACTIONS])
|
|
||||||
self.assertEqual(event[AodhProps.TYPE], vertex['alarm_type'])
|
|
||||||
if event[AodhProps.TYPE] == AodhProps.EVENT:
|
|
||||||
self.assertEqual(event[AodhProps.EVENT_TYPE],
|
|
||||||
vertex[AodhProps.EVENT_TYPE])
|
|
||||||
elif event[AodhProps.TYPE] == AodhProps.THRESHOLD:
|
|
||||||
self.assertEqual(event[AodhProps.STATE_TIMESTAMP],
|
|
||||||
vertex[AodhProps.STATE_TIMESTAMP])
|
|
||||||
self.assertEqual(event[DSProps.SAMPLE_DATE],
|
|
||||||
vertex[VProps.SAMPLE_TIMESTAMP])
|
|
||||||
|
|
||||||
event_status = event[AodhProps.STATE]
|
OPTS = [
|
||||||
if event_status == AodhState.OK:
|
cfg.StrOpt('update_method',
|
||||||
self.assertEqual(AlarmProps.INACTIVE_STATE,
|
default=UpdateMethod.PUSH),
|
||||||
vertex[VProps.STATE])
|
]
|
||||||
else:
|
|
||||||
self.assertEqual(AlarmProps.ACTIVE_STATE,
|
|
||||||
vertex[VProps.STATE])
|
|
||||||
self.assertFalse(vertex[VProps.IS_PLACEHOLDER])
|
|
||||||
self.assertFalse(vertex[VProps.IS_DELETED])
|
|
||||||
|
|
||||||
def _validate_action(self, alarm, wrapper):
|
@classmethod
|
||||||
if DSProps.EVENT_TYPE in alarm \
|
def setUpClass(cls):
|
||||||
and alarm[DSProps.EVENT_TYPE] in GraphAction.__dict__.values():
|
cls.transformers = {}
|
||||||
self.assertEqual(alarm[DSProps.EVENT_TYPE], wrapper.action)
|
cls.conf = cfg.ConfigOpts()
|
||||||
return
|
cls.conf.register_opts(cls.OPTS, group=AODH_DATASOURCE)
|
||||||
|
cls.transformers[AODH_DATASOURCE] = \
|
||||||
|
AodhTransformer(cls.transformers, cls.conf)
|
||||||
|
|
||||||
ds_action = alarm[DSProps.DATASOURCE_ACTION]
|
def test_update_transform(self):
|
||||||
if ds_action in (DatasourceAction.SNAPSHOT, DatasourceAction.UPDATE):
|
LOG.debug('Aodh update alarm transformer test:'
|
||||||
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
|
'transform entity event update')
|
||||||
else:
|
|
||||||
self.assertEqual(GraphAction.CREATE_ENTITY, wrapper.action)
|
|
||||||
|
|
||||||
def _validate_neighbors(self, neighbors, alarm_id, event):
|
# Test setup
|
||||||
resource_counter = 0
|
spec_list = \
|
||||||
|
mock_sync.simple_aodh_update_alarm_generators(alarm_num=5,
|
||||||
|
update_events=5)
|
||||||
|
static_events = mock_sync.generate_random_events_list(spec_list)
|
||||||
|
|
||||||
for neighbor in neighbors:
|
for event in static_events:
|
||||||
resource_id = event[AodhProps.RESOURCE_ID]
|
# convert neighbor from dict to vertex object
|
||||||
self._validate_instance_neighbor(neighbor,
|
neighbors = event[TransformerBase.QUERY_RESULT]
|
||||||
resource_id,
|
vertices = []
|
||||||
alarm_id)
|
for neighbor in neighbors:
|
||||||
resource_counter += 1
|
vertices.append(self._convert_dist_to_vertex(neighbor))
|
||||||
|
event[TransformerBase.QUERY_RESULT] = vertices
|
||||||
|
|
||||||
self.assertEqual(1,
|
# Test action
|
||||||
resource_counter,
|
wrapper = self.transformers[AODH_DATASOURCE].transform(event)
|
||||||
'Alarm can be belonged to only one resource')
|
|
||||||
|
|
||||||
def _validate_instance_neighbor(self,
|
# Test assertions
|
||||||
alarm_neighbor,
|
vertex = wrapper.vertex
|
||||||
resource_id,
|
self._validate_aodh_vertex_props(vertex, event)
|
||||||
alarm_vertex_id):
|
|
||||||
# validate neighbor vertex
|
|
||||||
self.assertEqual(EntityCategory.RESOURCE,
|
|
||||||
alarm_neighbor.vertex[VProps.CATEGORY])
|
|
||||||
self.assertEqual(NOVA_INSTANCE_DATASOURCE,
|
|
||||||
alarm_neighbor.vertex[VProps.TYPE])
|
|
||||||
self.assertEqual(resource_id, alarm_neighbor.vertex[VProps.ID])
|
|
||||||
self.assertFalse(alarm_neighbor.vertex[VProps.IS_PLACEHOLDER])
|
|
||||||
self.assertFalse(alarm_neighbor.vertex[VProps.IS_DELETED])
|
|
||||||
|
|
||||||
# Validate neighbor edge
|
neighbors = wrapper.neighbors
|
||||||
edge = alarm_neighbor.edge
|
self.assertEqual(1, len(neighbors))
|
||||||
self.assertEqual(edge.target_id, alarm_neighbor.vertex.vertex_id)
|
self._validate_neighbors(neighbors, vertex.vertex_id, event)
|
||||||
self.assertEqual(edge.source_id, alarm_vertex_id)
|
|
||||||
self.assertEqual(edge.label, EdgeLabel.ON)
|
|
||||||
|
|
||||||
def _convert_dist_to_vertex(self, neighbor):
|
self._validate_action(event, wrapper)
|
||||||
ver_id = neighbor[VProps.CATEGORY] + \
|
|
||||||
TransformerBase.KEY_SEPARATOR + neighbor[VProps.TYPE] + \
|
|
||||||
TransformerBase.KEY_SEPARATOR + neighbor[VProps.ID]
|
|
||||||
return Vertex(vertex_id=ver_id, properties=neighbor)
|
|
||||||
|
@ -144,9 +144,6 @@ class NagiosDriverTest(NagiosBaseTest):
|
|||||||
self.assertEqual(2, len(services))
|
self.assertEqual(2, len(services))
|
||||||
self._assert_contains(service_data1, services)
|
self._assert_contains(service_data1, services)
|
||||||
self._assert_contains(service_data2, services)
|
self._assert_contains(service_data2, services)
|
||||||
for service in services:
|
|
||||||
self.assertEqual(GraphAction.DELETE_ENTITY,
|
|
||||||
service[DSProps.EVENT_TYPE])
|
|
||||||
|
|
||||||
# Action
|
# Action
|
||||||
services = nagios_driver._get_all_alarms()
|
services = nagios_driver._get_all_alarms()
|
||||||
@ -278,9 +275,6 @@ class NagiosDriverTest(NagiosBaseTest):
|
|||||||
self.assertEqual(2, len(services))
|
self.assertEqual(2, len(services))
|
||||||
self._assert_contains(service_data1, services)
|
self._assert_contains(service_data1, services)
|
||||||
self._assert_contains(service_data2, services)
|
self._assert_contains(service_data2, services)
|
||||||
for service in services:
|
|
||||||
self.assertEqual(GraphAction.DELETE_ENTITY,
|
|
||||||
service[DSProps.EVENT_TYPE])
|
|
||||||
|
|
||||||
# Action
|
# Action
|
||||||
services = nagios_driver._get_changed_alarms()
|
services = nagios_driver._get_changed_alarms()
|
||||||
|
@ -90,6 +90,7 @@ class NagiosTransformerTest(base.BaseTest):
|
|||||||
# Test action
|
# Test action
|
||||||
wrapper = NagiosTransformer(self.transformers, self.conf).\
|
wrapper = NagiosTransformer(self.transformers, self.conf).\
|
||||||
transform(alarm)
|
transform(alarm)
|
||||||
|
|
||||||
self._validate_vertex(wrapper.vertex, alarm)
|
self._validate_vertex(wrapper.vertex, alarm)
|
||||||
|
|
||||||
neighbors = wrapper.neighbors
|
neighbors = wrapper.neighbors
|
||||||
@ -103,14 +104,12 @@ class NagiosTransformerTest(base.BaseTest):
|
|||||||
self._validate_action(alarm, wrapper)
|
self._validate_action(alarm, wrapper)
|
||||||
|
|
||||||
def _validate_action(self, alarm, wrapper):
|
def _validate_action(self, alarm, wrapper):
|
||||||
if DSProps.EVENT_TYPE in alarm \
|
|
||||||
and alarm[DSProps.EVENT_TYPE] in GraphAction.__dict__.values():
|
|
||||||
self.assertEqual(alarm[DSProps.EVENT_TYPE], wrapper.action)
|
|
||||||
return
|
|
||||||
|
|
||||||
ds_action = alarm[DSProps.DATASOURCE_ACTION]
|
ds_action = alarm[DSProps.DATASOURCE_ACTION]
|
||||||
if ds_action in (DatasourceAction.SNAPSHOT, DatasourceAction.UPDATE):
|
if ds_action in (DatasourceAction.SNAPSHOT, DatasourceAction.UPDATE):
|
||||||
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
|
if alarm[NagiosProperties.STATUS] == 'OK':
|
||||||
|
self.assertEqual(GraphAction.DELETE_ENTITY, wrapper.action)
|
||||||
|
else:
|
||||||
|
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(GraphAction.CREATE_ENTITY, wrapper.action)
|
self.assertEqual(GraphAction.CREATE_ENTITY, wrapper.action)
|
||||||
|
|
||||||
|
@ -143,9 +143,6 @@ class ZabbixDriverTest(ZabbixBaseTest):
|
|||||||
self.assertEqual(2, len(alarms))
|
self.assertEqual(2, len(alarms))
|
||||||
self._assert_contains(expected_alarm1, alarms)
|
self._assert_contains(expected_alarm1, alarms)
|
||||||
self._assert_contains(expected_alarm2, alarms)
|
self._assert_contains(expected_alarm2, alarms)
|
||||||
for alarm in alarms:
|
|
||||||
self.assertEqual(GraphAction.DELETE_ENTITY,
|
|
||||||
alarm[DSProps.EVENT_TYPE])
|
|
||||||
|
|
||||||
# Step 4 - get all when all alarms are inactivated and their status
|
# Step 4 - get all when all alarms are inactivated and their status
|
||||||
# was not changed
|
# was not changed
|
||||||
@ -254,9 +251,6 @@ class ZabbixDriverTest(ZabbixBaseTest):
|
|||||||
self.assertEqual(2, len(alarms))
|
self.assertEqual(2, len(alarms))
|
||||||
self._assert_contains(expected_alarm1, alarms)
|
self._assert_contains(expected_alarm1, alarms)
|
||||||
self._assert_contains(expected_alarm2, alarms)
|
self._assert_contains(expected_alarm2, alarms)
|
||||||
for alarm in alarms:
|
|
||||||
self.assertEqual(GraphAction.DELETE_ENTITY,
|
|
||||||
alarm[DSProps.EVENT_TYPE])
|
|
||||||
|
|
||||||
# Step 6 - get changes when no change occurred
|
# Step 6 - get changes when no change occurred
|
||||||
# Action
|
# Action
|
||||||
|
@ -108,14 +108,12 @@ class ZabbixTransformerTest(base.BaseTest):
|
|||||||
self._validate_action(alarm, wrapper)
|
self._validate_action(alarm, wrapper)
|
||||||
|
|
||||||
def _validate_action(self, alarm, wrapper):
|
def _validate_action(self, alarm, wrapper):
|
||||||
if DSProps.EVENT_TYPE in alarm \
|
|
||||||
and alarm[DSProps.EVENT_TYPE] in GraphAction.__dict__.values():
|
|
||||||
self.assertEqual(alarm[DSProps.EVENT_TYPE], wrapper.action)
|
|
||||||
return
|
|
||||||
|
|
||||||
ds_action = alarm[DSProps.DATASOURCE_ACTION]
|
ds_action = alarm[DSProps.DATASOURCE_ACTION]
|
||||||
if ds_action in (DatasourceAction.SNAPSHOT, DatasourceAction.UPDATE):
|
if ds_action in (DatasourceAction.SNAPSHOT, DatasourceAction.UPDATE):
|
||||||
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
|
if alarm[ZabbixProps.VALUE] == ZabbixTriggerValue.OK:
|
||||||
|
self.assertEqual(GraphAction.DELETE_ENTITY, wrapper.action)
|
||||||
|
else:
|
||||||
|
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(GraphAction.CREATE_ENTITY, wrapper.action)
|
self.assertEqual(GraphAction.CREATE_ENTITY, wrapper.action)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user