Implement Doctor datasource for handling alarms coming from OPNFV Doctor monitor
Implements: blueprint doctor-datasource Change-Id: If41b8b5ef1d7a62d374e15bc3cc5739afecc06ca
This commit is contained in:
parent
9844aa077e
commit
2c1432c222
12
etc/vitrage/datasources_values/doctor.yaml
Normal file
12
etc/vitrage/datasources_values/doctor.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
category: ALARM
|
||||
values:
|
||||
- aggregated values:
|
||||
priority: 40
|
||||
original values:
|
||||
- name: critical
|
||||
operational_value: CRITICAL
|
||||
- aggregated values:
|
||||
priority: 10
|
||||
original values:
|
||||
- name: OK
|
||||
operational_value: OK
|
70
etc/vitrage/templates.sample/host_down_scenarios.yaml
Normal file
70
etc/vitrage/templates.sample/host_down_scenarios.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
metadata:
|
||||
name: host_down_scenarios
|
||||
description: scenarios triggered by Doctor monitor 'compute.host.down' alarm
|
||||
definitions:
|
||||
entities:
|
||||
- entity:
|
||||
category: ALARM
|
||||
name: compute.host.down
|
||||
template_id: host_down_alarm
|
||||
- entity:
|
||||
category: ALARM
|
||||
type: vitrage
|
||||
name: Instance Down
|
||||
template_id: instance_alarm
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.instance
|
||||
template_id: instance
|
||||
- entity:
|
||||
category: RESOURCE
|
||||
type: nova.host
|
||||
template_id: host
|
||||
relationships:
|
||||
- relationship:
|
||||
source: host_down_alarm
|
||||
relationship_type: on
|
||||
target: host
|
||||
template_id : host_down_alarm_on_host
|
||||
- relationship:
|
||||
source: host
|
||||
relationship_type: contains
|
||||
target: instance
|
||||
template_id : host_contains_instance
|
||||
- relationship:
|
||||
source: instance_alarm
|
||||
relationship_type: on
|
||||
target: instance
|
||||
template_id : alarm_on_instance
|
||||
scenarios:
|
||||
- scenario:
|
||||
condition: host_down_alarm_on_host
|
||||
actions:
|
||||
- action:
|
||||
action_type: set_state
|
||||
action_target:
|
||||
target: host
|
||||
properties:
|
||||
state: ERROR
|
||||
- action:
|
||||
action_type: mark_down
|
||||
action_target:
|
||||
target: host
|
||||
- scenario:
|
||||
condition: host_down_alarm_on_host and host_contains_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: raise_alarm
|
||||
action_target:
|
||||
target: instance
|
||||
properties:
|
||||
alarm_name: Instance Down
|
||||
severity: critical
|
||||
- scenario:
|
||||
condition: host_down_alarm_on_host and host_contains_instance and alarm_on_instance
|
||||
actions:
|
||||
- action:
|
||||
action_type: add_causal_relationship
|
||||
action_target:
|
||||
source: host_down_alarm
|
||||
target: instance_alarm
|
@ -141,3 +141,7 @@ class AlarmDriverBase(DriverBase):
|
||||
ret = alarm if filter_(alarm, old_alarm) else None
|
||||
self.cache[self._alarm_key(alarm)] = alarm, time
|
||||
return ret
|
||||
|
||||
def _old_alarm(self, event):
|
||||
alarm_key = self._alarm_key(event)
|
||||
return self.cache.get(alarm_key, (None, None))[0]
|
||||
|
@ -16,11 +16,16 @@ 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 EdgeLabel
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import GraphAction
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.common.exception import VitrageTransformerError
|
||||
from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
|
||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import transformer_base as tbase
|
||||
from vitrage.datasources.transformer_base import Neighbor
|
||||
import vitrage.graph.utils as graph_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -63,11 +68,36 @@ class AlarmTransformerBase(tbase.TransformerBase):
|
||||
|
||||
def _get_alarm_state(self, entity_event):
|
||||
event_type = entity_event.get(DSProps.EVENT_TYPE, None)
|
||||
if event_type is not None:
|
||||
return AlarmProps.INACTIVE_STATE if \
|
||||
GraphAction.DELETE_ENTITY == event_type else \
|
||||
AlarmProps.ACTIVE_STATE
|
||||
if event_type and event_type == GraphAction.DELETE_ENTITY:
|
||||
return AlarmProps.INACTIVE_STATE
|
||||
else:
|
||||
return AlarmProps.INACTIVE_STATE if \
|
||||
self._ok_status(entity_event) else \
|
||||
AlarmProps.ACTIVE_STATE
|
||||
|
||||
def _create_neighbor(self,
|
||||
vitrage_id,
|
||||
sample_timestamp,
|
||||
resource_type,
|
||||
resource_name):
|
||||
# Any resource transformer will do (nova for example)
|
||||
transformer = self.transformers[NOVA_HOST_DATASOURCE]
|
||||
|
||||
if transformer:
|
||||
properties = {
|
||||
VProps.TYPE: resource_type,
|
||||
VProps.ID: resource_name,
|
||||
VProps.SAMPLE_TIMESTAMP: sample_timestamp
|
||||
}
|
||||
resource_vertex = transformer.create_placeholder_vertex(
|
||||
**properties)
|
||||
|
||||
relationship_edge = graph_utils.create_edge(
|
||||
source_id=vitrage_id,
|
||||
target_id=resource_vertex.vertex_id,
|
||||
relationship_type=EdgeLabel.ON)
|
||||
|
||||
return Neighbor(resource_vertex, relationship_edge)
|
||||
|
||||
LOG.warning('Cannot create neighbour, host transformer does not exist')
|
||||
return None
|
||||
|
@ -254,8 +254,7 @@ class AodhDriver(AlarmDriverBase):
|
||||
"event_type": "instance.update"}}
|
||||
"""
|
||||
|
||||
alarm_key = self._alarm_key(event)
|
||||
old_alarm = self.cache.get(alarm_key, (None, None))[0]
|
||||
old_alarm = self._old_alarm(event)
|
||||
entity = old_alarm.copy()
|
||||
|
||||
changed_rule = event[AodhProps.DETAIL]
|
||||
@ -273,8 +272,7 @@ class AodhDriver(AlarmDriverBase):
|
||||
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]
|
||||
old_alarm = self._old_alarm(event)
|
||||
entity = old_alarm.copy()
|
||||
entity[AodhProps.STATE] = event[AodhProps.DETAIL][AodhProps.STATE]
|
||||
|
||||
|
37
vitrage/datasources/doctor/__init__.py
Normal file
37
vitrage/datasources/doctor/__init__.py
Normal file
@ -0,0 +1,37 @@
|
||||
# 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_config import cfg
|
||||
from vitrage.common.constants import UpdateMethod
|
||||
|
||||
DOCTOR_DATASOURCE = 'doctor'
|
||||
|
||||
OPTS = [
|
||||
cfg.StrOpt('transformer',
|
||||
default='vitrage.datasources.doctor.transformer.'
|
||||
'DoctorTransformer',
|
||||
help='Doctor transformer class path',
|
||||
required=True),
|
||||
cfg.StrOpt('driver',
|
||||
default='vitrage.datasources.doctor.driver.DoctorDriver',
|
||||
help='Doctor driver class path',
|
||||
required=True),
|
||||
cfg.StrOpt('update_method',
|
||||
default=UpdateMethod.PUSH,
|
||||
help='None: updates only via Vitrage periodic snapshots.'
|
||||
'Pull: updates every [changes_interval] seconds.'
|
||||
'Push: updates by getting notifications from the'
|
||||
' datasource itself.',
|
||||
required=True),
|
||||
]
|
112
vitrage/datasources/doctor/driver.py
Normal file
112
vitrage/datasources/doctor/driver.py
Normal file
@ -0,0 +1,112 @@
|
||||
# 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 collections import namedtuple
|
||||
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.doctor import DOCTOR_DATASOURCE
|
||||
from vitrage.datasources.doctor.properties import DoctorDetails
|
||||
from vitrage.datasources.doctor.properties import DoctorProperties \
|
||||
as DoctorProps
|
||||
from vitrage.datasources.doctor.properties import DoctorStatus
|
||||
from vitrage.datasources.doctor.properties import get_detail
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class DoctorDriver(AlarmDriverBase):
|
||||
AlarmKey = namedtuple('AlarmKey', ['alarm_name', 'hostname'])
|
||||
|
||||
def __init__(self, conf):
|
||||
super(DoctorDriver, self).__init__()
|
||||
self.conf = conf
|
||||
self._client = None
|
||||
|
||||
def _entity_type(self):
|
||||
return DOCTOR_DATASOURCE
|
||||
|
||||
def _alarm_key(self, alarm):
|
||||
return self.AlarmKey(alarm_name=alarm[DoctorProps.TYPE],
|
||||
hostname=get_detail(alarm,
|
||||
DoctorDetails.HOSTNAME))
|
||||
|
||||
def _is_erroneous(self, alarm):
|
||||
return alarm and \
|
||||
get_detail(alarm, DoctorDetails.STATUS) != DoctorStatus.UP
|
||||
|
||||
def _is_valid(self, alarm):
|
||||
if not alarm or DoctorProps.TIME not in alarm or \
|
||||
DoctorProps.TYPE not in alarm or \
|
||||
DoctorProps.DETAILS not in alarm:
|
||||
return False
|
||||
|
||||
details = alarm[DoctorProps.DETAILS]
|
||||
return DoctorDetails.STATUS in details and \
|
||||
DoctorDetails.SEVERITY in details and \
|
||||
DoctorDetails.HOSTNAME in details
|
||||
|
||||
def _status_changed(self, new_alarm, old_alarm):
|
||||
return get_detail(old_alarm, DoctorDetails.STATUS) != \
|
||||
get_detail(new_alarm, DoctorDetails.STATUS)
|
||||
|
||||
def _get_alarms(self):
|
||||
# pulling alarms is not supported in Doctor monitor
|
||||
return []
|
||||
|
||||
def enrich_event(self, event, event_type):
|
||||
"""Enrich the given event
|
||||
|
||||
:param event: dictionary of this form:
|
||||
{
|
||||
'time': '2016-04-12T08:00:00.12345',
|
||||
'type': 'compute.host.down',
|
||||
'details': {
|
||||
'hostname': 'compute-1',
|
||||
'source': 'sample_monitor',
|
||||
'cause': 'link-down',
|
||||
'severity': 'critical',
|
||||
'status': 'down',
|
||||
'monitor_id': 'monitor-1',
|
||||
'monitor_event_id': '123',
|
||||
}
|
||||
}
|
||||
:param event_type: always 'compute.host.down'
|
||||
:return: the same event, with the following changes:
|
||||
- DoctorProps.UPDATE_TIME - the event 'time' if it is new, or the
|
||||
update time of the same event if it is already cached
|
||||
|
||||
"""
|
||||
|
||||
event[DSProps.EVENT_TYPE] = event_type
|
||||
|
||||
old_alarm = self._old_alarm(event)
|
||||
if old_alarm and not self._status_changed(old_alarm, event):
|
||||
event[DoctorProps.UPDATE_TIME] = old_alarm[DoctorProps.UPDATE_TIME]
|
||||
else:
|
||||
event[DoctorProps.UPDATE_TIME] = event[DoctorProps.TIME]
|
||||
|
||||
event = self._filter_and_cache_alarm(event, old_alarm,
|
||||
self._filter_get_erroneous,
|
||||
event[DoctorProps.TIME])
|
||||
|
||||
if event:
|
||||
return DoctorDriver.make_pickleable([event], DOCTOR_DATASOURCE,
|
||||
DatasourceAction.UPDATE)[0]
|
||||
|
||||
@staticmethod
|
||||
def get_event_types():
|
||||
return [DoctorProps.HOST_DOWN]
|
42
vitrage/datasources/doctor/properties.py
Normal file
42
vitrage/datasources/doctor/properties.py
Normal file
@ -0,0 +1,42 @@
|
||||
# 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.
|
||||
|
||||
|
||||
class DoctorProperties(object):
|
||||
TIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%f'
|
||||
HOST_DOWN = 'compute.host.down'
|
||||
HOST_TYPE = 'nova.host'
|
||||
TYPE = 'type'
|
||||
TIME = 'time'
|
||||
UPDATE_TIME = 'update_time'
|
||||
DETAILS = 'details'
|
||||
|
||||
|
||||
class DoctorDetails(object):
|
||||
"""The details appear inside a details section in the event """
|
||||
HOSTNAME = 'hostname'
|
||||
STATUS = 'status'
|
||||
SEVERITY = 'severity'
|
||||
|
||||
|
||||
class DoctorStatus(object):
|
||||
DOWN = 'down'
|
||||
UP = 'up'
|
||||
|
||||
|
||||
def get_detail(alarm, detail):
|
||||
return alarm[DoctorProperties.DETAILS][detail] if \
|
||||
alarm and DoctorProperties.DETAILS in alarm and \
|
||||
detail in alarm[DoctorProperties.DETAILS] \
|
||||
else None
|
97
vitrage/datasources/doctor/transformer.py
Normal file
97
vitrage/datasources/doctor/transformer.py
Normal file
@ -0,0 +1,97 @@
|
||||
# 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 as logging
|
||||
|
||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources.alarm_transformer_base import AlarmTransformerBase
|
||||
from vitrage.datasources.doctor import DOCTOR_DATASOURCE
|
||||
from vitrage.datasources.doctor.properties import DoctorDetails
|
||||
from vitrage.datasources.doctor.properties import DoctorProperties \
|
||||
as DoctorProps
|
||||
from vitrage.datasources.doctor.properties import DoctorStatus
|
||||
from vitrage.datasources.doctor.properties import get_detail
|
||||
from vitrage.datasources import transformer_base as tbase
|
||||
import vitrage.graph.utils as graph_utils
|
||||
from vitrage.utils.datetime import change_time_str_format
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DoctorTransformer(AlarmTransformerBase):
|
||||
|
||||
def __init__(self, transformers, conf):
|
||||
super(DoctorTransformer, self).__init__(transformers, conf)
|
||||
|
||||
def _create_snapshot_entity_vertex(self, entity_event):
|
||||
# The Doctor monitor does not support snapshot mode
|
||||
return None
|
||||
|
||||
def _create_update_entity_vertex(self, entity_event):
|
||||
self._unify_time_format(entity_event)
|
||||
|
||||
details = entity_event.get(DoctorProps.DETAILS, {})
|
||||
details[VProps.NAME] = entity_event[DoctorProps.TYPE]
|
||||
|
||||
return graph_utils.create_vertex(
|
||||
self._create_entity_key(entity_event),
|
||||
entity_category=EntityCategory.ALARM,
|
||||
entity_type=entity_event[DSProps.ENTITY_TYPE],
|
||||
entity_state=self._get_alarm_state(entity_event),
|
||||
sample_timestamp=entity_event[DoctorProps.TIME],
|
||||
update_timestamp=entity_event[DoctorProps.UPDATE_TIME],
|
||||
metadata=details)
|
||||
|
||||
def _create_update_neighbors(self, entity_event):
|
||||
return [self._create_neighbor(
|
||||
self._create_entity_key(entity_event),
|
||||
entity_event[DoctorProps.TIME],
|
||||
DoctorProps.HOST_TYPE,
|
||||
get_detail(entity_event, DoctorDetails.HOSTNAME))]
|
||||
|
||||
def _create_entity_key(self, entity_event):
|
||||
return tbase.build_key(self._key_values(
|
||||
entity_event[DSProps.ENTITY_TYPE],
|
||||
entity_event[DoctorProps.TYPE],
|
||||
get_detail(entity_event, DoctorDetails.HOSTNAME)))
|
||||
|
||||
def get_type(self):
|
||||
return DOCTOR_DATASOURCE
|
||||
|
||||
def _ok_status(self, entity_event):
|
||||
return entity_event and \
|
||||
get_detail(entity_event, DoctorDetails.STATUS) == DoctorStatus.UP
|
||||
|
||||
@staticmethod
|
||||
def get_enrich_query(event):
|
||||
hostname = get_detail(event, DoctorDetails.HOSTNAME)
|
||||
if not hostname:
|
||||
return None
|
||||
return {VProps.ID: hostname}
|
||||
|
||||
@staticmethod
|
||||
def _unify_time_format(entity_event):
|
||||
DoctorTransformer._unify_prop_time_format(entity_event,
|
||||
DoctorProps.TIME)
|
||||
DoctorTransformer._unify_prop_time_format(entity_event,
|
||||
DoctorProps.UPDATE_TIME)
|
||||
|
||||
@staticmethod
|
||||
def _unify_prop_time_format(entity_event, prop):
|
||||
entity_event[prop] = change_time_str_format(
|
||||
entity_event[prop],
|
||||
DoctorProps.TIME_FORMAT,
|
||||
tbase.TIMESTAMP_FORMAT)
|
@ -15,16 +15,13 @@
|
||||
from oslo_log import log as logging
|
||||
|
||||
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 VertexProperties as VProps
|
||||
from vitrage.datasources.alarm_transformer_base import AlarmTransformerBase
|
||||
from vitrage.datasources.nagios import NAGIOS_DATASOURCE
|
||||
from vitrage.datasources.nagios.properties import NagiosProperties
|
||||
from vitrage.datasources.nagios.properties import NagiosTestStatus
|
||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import transformer_base as tbase
|
||||
from vitrage.datasources.transformer_base import Neighbor
|
||||
import vitrage.graph.utils as graph_utils
|
||||
from vitrage.utils import datetime as datetime_utils
|
||||
|
||||
@ -92,33 +89,6 @@ class NagiosTransformer(AlarmTransformerBase):
|
||||
|
||||
return []
|
||||
|
||||
def _create_neighbor(self,
|
||||
vitrage_id,
|
||||
sample_timestamp,
|
||||
resource_type,
|
||||
resource_name):
|
||||
# Any resource transformer will do (nova for example)
|
||||
transformer = self.transformers[NOVA_HOST_DATASOURCE]
|
||||
|
||||
if transformer:
|
||||
properties = {
|
||||
VProps.TYPE: resource_type,
|
||||
VProps.ID: resource_name,
|
||||
VProps.SAMPLE_TIMESTAMP: sample_timestamp
|
||||
}
|
||||
resource_vertex = transformer.create_placeholder_vertex(
|
||||
**properties)
|
||||
|
||||
relationship_edge = graph_utils.create_edge(
|
||||
source_id=vitrage_id,
|
||||
target_id=resource_vertex.vertex_id,
|
||||
relationship_type=EdgeLabel.ON)
|
||||
|
||||
return Neighbor(resource_vertex, relationship_edge)
|
||||
|
||||
LOG.warning('Cannot transform host, host transformer does not exist')
|
||||
return None
|
||||
|
||||
def _ok_status(self, entity_event):
|
||||
return entity_event[NagiosProperties.STATUS] == NagiosTestStatus.OK
|
||||
|
||||
|
@ -15,14 +15,11 @@
|
||||
from oslo_log import log as logging
|
||||
|
||||
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 VertexProperties as VProps
|
||||
from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
|
||||
from vitrage.datasources.alarm_transformer_base import AlarmTransformerBase
|
||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import transformer_base as tbase
|
||||
from vitrage.datasources.transformer_base import Neighbor
|
||||
from vitrage.datasources.zabbix.properties import ZabbixProperties as ZProps
|
||||
from vitrage.datasources.zabbix.properties import ZabbixTriggerSeverity \
|
||||
as TriggerSeverity
|
||||
@ -104,33 +101,6 @@ class ZabbixTransformer(AlarmTransformerBase):
|
||||
|
||||
return []
|
||||
|
||||
def _create_neighbor(self,
|
||||
vitrage_id,
|
||||
sample_timestamp,
|
||||
resource_type,
|
||||
resource_name):
|
||||
# Any resource transformer will do (nova for example)
|
||||
transformer = self.transformers[NOVA_HOST_DATASOURCE]
|
||||
|
||||
if transformer:
|
||||
properties = {
|
||||
VProps.TYPE: resource_type,
|
||||
VProps.ID: resource_name,
|
||||
VProps.SAMPLE_TIMESTAMP: sample_timestamp
|
||||
}
|
||||
resource_vertex = transformer.create_placeholder_vertex(
|
||||
**properties)
|
||||
|
||||
relationship_edge = graph_utils.create_edge(
|
||||
source_id=vitrage_id,
|
||||
target_id=resource_vertex.vertex_id,
|
||||
relationship_type=EdgeLabel.ON)
|
||||
|
||||
return Neighbor(resource_vertex, relationship_edge)
|
||||
|
||||
LOG.warning('Cannot transform host, host transformer does not exist')
|
||||
return None
|
||||
|
||||
def _ok_status(self, entity_event):
|
||||
return entity_event[ZProps.VALUE] == TriggerValue.OK
|
||||
|
||||
|
@ -39,13 +39,19 @@ class TransformerManager(object):
|
||||
|
||||
transformers = {}
|
||||
for datasource_type in conf.datasources.types:
|
||||
transformers[datasource_type] = importutils.import_object(
|
||||
conf[datasource_type].transformer,
|
||||
transformers, conf)
|
||||
if opt_exists(conf[datasource_type], ENTITIES):
|
||||
for entity in conf[datasource_type].entities:
|
||||
transformers[entity] = importutils.import_object(
|
||||
conf[datasource_type].transformer, transformers, conf)
|
||||
try:
|
||||
transformers[datasource_type] = importutils.import_object(
|
||||
conf[datasource_type].transformer,
|
||||
transformers, conf)
|
||||
if opt_exists(conf[datasource_type], ENTITIES):
|
||||
for entity in conf[datasource_type].entities:
|
||||
transformers[entity] = importutils.import_object(
|
||||
conf[datasource_type].transformer,
|
||||
transformers, conf)
|
||||
|
||||
except Exception as e:
|
||||
LOG.exception('Failed to register transformer %s. '
|
||||
'Exception: %s', datasource_type, e)
|
||||
|
||||
transformers[VITRAGE_TYPE] = importutils.import_object(
|
||||
"%s.%s" % (EvaluatorEventTransformer.__module__,
|
||||
|
@ -437,6 +437,27 @@ def simple_zabbix_alarm_generators(host_num,
|
||||
return tg.get_trace_generators(test_entity_spec_list)
|
||||
|
||||
|
||||
def simple_doctor_alarm_generators(update_vals=None):
|
||||
"""A function for returning Doctor alarm event generators.
|
||||
|
||||
Returns generators for a given number of Doctor alarms.
|
||||
|
||||
:param update_vals: preset values for ALL update events
|
||||
:return: generators for alarms as specified
|
||||
"""
|
||||
|
||||
test_entity_spec_list = [({
|
||||
tg.DYNAMIC_INFO_FKEY: tg.DRIVER_DOCTOR_UPDATE_D,
|
||||
tg.STATIC_INFO_FKEY: None,
|
||||
tg.EXTERNAL_INFO_KEY: update_vals,
|
||||
tg.MAPPING_KEY: None,
|
||||
tg.NAME_KEY: 'Doctor alarm generator',
|
||||
tg.NUM_EVENTS: 1
|
||||
})]
|
||||
|
||||
return tg.get_trace_generators(test_entity_spec_list)
|
||||
|
||||
|
||||
def simple_aodh_alarm_notification_generators(alarm_num,
|
||||
update_events=0,
|
||||
update_vals=None):
|
||||
|
@ -188,3 +188,25 @@ def simple_aodh_update_alarm_generators(alarm_num,
|
||||
}
|
||||
]
|
||||
return tg.get_trace_generators(test_entity_spec_list)
|
||||
|
||||
|
||||
def simple_doctor_alarm_generators(update_vals=None):
|
||||
"""A function for returning Doctor alarm event generators.
|
||||
|
||||
Returns generators for a given number of Doctor alarms.
|
||||
|
||||
:param update_vals: preset values for ALL update events
|
||||
:return: generators for alarms as specified
|
||||
"""
|
||||
|
||||
test_entity_spec_list = [({
|
||||
tg.DYNAMIC_INFO_FKEY: tg.TRANS_DOCTOR_UPDATE_D,
|
||||
tg.DYNAMIC_INFO_FPATH: tg.MOCK_TRANSFORMER_PATH,
|
||||
tg.STATIC_INFO_FKEY: None,
|
||||
tg.EXTERNAL_INFO_KEY: update_vals,
|
||||
tg.MAPPING_KEY: None,
|
||||
tg.NAME_KEY: 'Doctor alarm generator',
|
||||
tg.NUM_EVENTS: 1
|
||||
})]
|
||||
|
||||
return tg.get_trace_generators(test_entity_spec_list)
|
||||
|
@ -45,6 +45,7 @@ GENERATOR = 'generator'
|
||||
MOCK_DRIVER_PATH = '%s/mock_configurations/driver' % \
|
||||
utils.get_resources_dir()
|
||||
DRIVER_AODH_UPDATE_D = 'driver_aodh_update_dynamic.json'
|
||||
DRIVER_DOCTOR_UPDATE_D = 'driver_doctor_update_dynamic.json'
|
||||
DRIVER_HOST_SNAPSHOT_D = 'driver_host_snapshot_dynamic.json'
|
||||
DRIVER_INST_SNAPSHOT_D = 'driver_inst_snapshot_dynamic.json'
|
||||
DRIVER_INST_SNAPSHOT_S = 'driver_inst_snapshot_static.json'
|
||||
@ -66,6 +67,7 @@ MOCK_TRANSFORMER_PATH = '%s/mock_configurations/transformer' % \
|
||||
utils.get_resources_dir()
|
||||
TRANS_AODH_SNAPSHOT_D = 'transformer_aodh_snapshot_dynamic.json'
|
||||
TRANS_AODH_UPDATE_D = 'transformer_aodh_update_dynamic.json'
|
||||
TRANS_DOCTOR_UPDATE_D = 'transformer_doctor_update_dynamic.json'
|
||||
TRANS_INST_SNAPSHOT_D = 'transformer_inst_snapshot_dynamic.json'
|
||||
TRANS_INST_SNAPSHOT_S = 'transformer_inst_snapshot_static.json'
|
||||
TRANS_HOST_SNAPSHOT_D = 'transformer_host_snapshot_dynamic.json'
|
||||
@ -108,6 +110,7 @@ class EventTraceGenerator(object):
|
||||
|
||||
static_info_parsers = \
|
||||
{DRIVER_AODH_UPDATE_D: _get_aodh_alarm_update_driver_values,
|
||||
DRIVER_DOCTOR_UPDATE_D: _get_doctor_update_driver_values,
|
||||
DRIVER_INST_SNAPSHOT_D: _get_vm_snapshot_driver_values,
|
||||
DRIVER_INST_UPDATE_D: _get_vm_update_driver_values,
|
||||
DRIVER_HOST_SNAPSHOT_D: _get_host_snapshot_driver_values,
|
||||
@ -124,6 +127,7 @@ class EventTraceGenerator(object):
|
||||
|
||||
TRANS_AODH_SNAPSHOT_D: _get_trans_aodh_alarm_snapshot_values,
|
||||
TRANS_AODH_UPDATE_D: _get_trans_aodh_alarm_snapshot_values,
|
||||
TRANS_DOCTOR_UPDATE_D: _get_trans_doctor_alarm_update_values,
|
||||
TRANS_INST_SNAPSHOT_D: _get_trans_vm_snapshot_values,
|
||||
TRANS_HOST_SNAPSHOT_D: _get_trans_host_snapshot_values,
|
||||
TRANS_ZONE_SNAPSHOT_D: _get_trans_zone_snapshot_values}
|
||||
@ -243,6 +247,17 @@ def _get_host_snapshot_driver_values(spec):
|
||||
return static_values
|
||||
|
||||
|
||||
def _get_doctor_update_driver_values(spec):
|
||||
"""Generates the static driver values for Doctor monitor notification.
|
||||
|
||||
:param spec: specification of event generation.
|
||||
:type spec: dict
|
||||
:return: list of notifications of Doctor monitor
|
||||
:rtype: list
|
||||
"""
|
||||
return [combine_data(None, None, spec.get(EXTERNAL_INFO_KEY, None))]
|
||||
|
||||
|
||||
def _get_zone_snapshot_driver_values(spec):
|
||||
"""Generates the static driver values for each zone.
|
||||
|
||||
@ -584,11 +599,11 @@ def _get_trans_zone_snapshot_values(spec):
|
||||
|
||||
|
||||
def _get_trans_aodh_alarm_snapshot_values(spec):
|
||||
"""Generates the static transformer values for each vm.
|
||||
"""Generates the dynamic transformer values for Aodh datasource.
|
||||
|
||||
:param spec: specification of event generation.
|
||||
:type spec: dict
|
||||
:return: list of static transformer values for each vm.
|
||||
:return: list of dynamic transformer values for Aodh datasource.
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
@ -621,6 +636,23 @@ def _get_aodh_alarm_update_driver_values(spec):
|
||||
return static_values
|
||||
|
||||
|
||||
def _get_trans_doctor_alarm_update_values(spec):
|
||||
"""Generates the dynamic transformer values for a Doctor alarm
|
||||
|
||||
:param spec: specification of event generation.
|
||||
:type spec: dict
|
||||
:return: list of dynamic transformer values for a Doctor alarm
|
||||
:rtype: list with one alarm
|
||||
"""
|
||||
|
||||
static_info_re = None
|
||||
if spec[STATIC_INFO_FKEY] is not None:
|
||||
static_info_re = utils.load_specs(spec[STATIC_INFO_FKEY])
|
||||
|
||||
return [combine_data(static_info_re,
|
||||
None, spec.get(EXTERNAL_INFO_KEY, None))]
|
||||
|
||||
|
||||
def combine_data(static_info_re, mapping_info, external_info):
|
||||
if external_info:
|
||||
mapping_info = utils.merge_vals(mapping_info, external_info)
|
||||
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"time": "2016-04-12T08:00:00.12345",
|
||||
"type": "compute.host.down",
|
||||
"details": {
|
||||
"hostname": "compute-1",
|
||||
"source": "sample_monitor",
|
||||
"cause": "link-down",
|
||||
"severity": "critical",
|
||||
"status": "down",
|
||||
"monitor_id": "monitor-1",
|
||||
"monitor_event_id": "123"
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"time": "2016-04-12T08:00:00.12345",
|
||||
"type": "compute.host.down",
|
||||
"vitrage_entity_type" : "doctor",
|
||||
"vitrage_datasource_action" : "update",
|
||||
"details": {
|
||||
"hostname": "compute-1",
|
||||
"source": "sample_monitor",
|
||||
"cause": "link-down",
|
||||
"severity": "critical",
|
||||
"status": "down",
|
||||
"monitor_id": "monitor-1",
|
||||
"monitor_event_id": "123"
|
||||
}
|
||||
}
|
134
vitrage/tests/unit/datasources/doctor/test_doctor_driver.py
Normal file
134
vitrage/tests/unit/datasources/doctor/test_doctor_driver.py
Normal file
@ -0,0 +1,134 @@
|
||||
# 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 datetime import datetime
|
||||
from oslo_config import cfg
|
||||
|
||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
||||
from vitrage.datasources.doctor.driver import DoctorDriver
|
||||
from vitrage.datasources.doctor.properties import DoctorDetails
|
||||
from vitrage.datasources.doctor.properties import DoctorProperties \
|
||||
as DoctorProps
|
||||
from vitrage.datasources.doctor.properties import DoctorStatus
|
||||
from vitrage.tests import base
|
||||
from vitrage.tests.mocks import mock_driver
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class DoctorDriverTest(base.BaseTest):
|
||||
OPTS = []
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.conf = cfg.ConfigOpts()
|
||||
cls.conf.register_opts(cls.OPTS, group='doctor')
|
||||
|
||||
def test_enrich_event(self):
|
||||
# Test setup
|
||||
driver = DoctorDriver(self.conf)
|
||||
event_type = DoctorProps.HOST_DOWN
|
||||
|
||||
time1 = datetime.now().isoformat()
|
||||
host1 = 'host1'
|
||||
event = self._generate_event(time1, host1, DoctorStatus.DOWN)
|
||||
|
||||
# Enrich event
|
||||
event = driver.enrich_event(event, event_type)
|
||||
|
||||
# Test assertions
|
||||
self._assert_event_equal(event, event_type, host1,
|
||||
DoctorStatus.DOWN, time1, time1)
|
||||
|
||||
# Add another event
|
||||
time2 = datetime.now().isoformat()
|
||||
host2 = 'host2'
|
||||
event = self._generate_event(time2, host2, DoctorStatus.DOWN)
|
||||
|
||||
# Enrich event
|
||||
event = driver.enrich_event(event, event_type)
|
||||
|
||||
# Test assertions
|
||||
self._assert_event_equal(event, event_type, host2,
|
||||
DoctorStatus.DOWN, time2, time2)
|
||||
|
||||
# Change the first event to 'up' - should be marked as deleted
|
||||
time3 = datetime.now().isoformat()
|
||||
event = self._generate_event(time3, host1, DoctorStatus.UP)
|
||||
|
||||
# Enrich event
|
||||
event = driver.enrich_event(event, event_type)
|
||||
|
||||
# Test assertions
|
||||
self._assert_event_equal(event, event_type, host1,
|
||||
DoctorStatus.UP, time3, time3)
|
||||
# self._assert_marked_as_deleted(driver, event, True)
|
||||
|
||||
# Send again the second event. The sample time should be new, but the
|
||||
# update time should remain with its old value (since the state has
|
||||
# not changed)
|
||||
time4 = datetime.now().isoformat()
|
||||
event = self._generate_event(time4, host2, DoctorStatus.DOWN)
|
||||
|
||||
# Enrich event
|
||||
event = driver.enrich_event(event, event_type)
|
||||
|
||||
# Test assertions
|
||||
self._assert_event_equal(event, event_type, host2,
|
||||
DoctorStatus.DOWN, time4, time2)
|
||||
|
||||
# Send again the first event, after it was deleted. Make sure it is
|
||||
# raised again
|
||||
time5 = datetime.now().isoformat()
|
||||
event = self._generate_event(time5, host1, DoctorStatus.DOWN)
|
||||
|
||||
# Enrich event
|
||||
event = driver.enrich_event(event, event_type)
|
||||
|
||||
# Test assertions
|
||||
self._assert_event_equal(event, event_type, host1,
|
||||
DoctorStatus.DOWN, time5, time5)
|
||||
|
||||
@staticmethod
|
||||
def _generate_event(time, hostname, status):
|
||||
details = {}
|
||||
if hostname:
|
||||
details[DoctorDetails.HOSTNAME] = hostname
|
||||
if status:
|
||||
details[DoctorDetails.STATUS] = status
|
||||
|
||||
update_vals = {DoctorProps.DETAILS: details}
|
||||
if time:
|
||||
update_vals[DoctorProps.TIME] = time
|
||||
|
||||
generators = mock_driver.simple_doctor_alarm_generators(
|
||||
update_vals=update_vals)
|
||||
|
||||
return mock_driver.generate_sequential_events_list(generators)[0]
|
||||
|
||||
def _assert_event_equal(self,
|
||||
event,
|
||||
expected_event_type,
|
||||
expected_hostname,
|
||||
expected_status,
|
||||
expected_sample_date,
|
||||
expected_update_date):
|
||||
self.assertIsNotNone(event, 'No event returned')
|
||||
self.assertEqual(expected_hostname,
|
||||
event[DoctorProps.DETAILS][DoctorDetails.HOSTNAME])
|
||||
self.assertEqual(expected_status,
|
||||
event[DoctorProps.DETAILS][DoctorDetails.STATUS])
|
||||
self.assertEqual(expected_sample_date, event[DoctorProps.TIME])
|
||||
self.assertEqual(expected_update_date, event[DoctorProps.UPDATE_TIME])
|
||||
self.assertEqual(expected_event_type, event[DSProps.EVENT_TYPE])
|
119
vitrage/tests/unit/datasources/doctor/test_doctor_transformer.py
Normal file
119
vitrage/tests/unit/datasources/doctor/test_doctor_transformer.py
Normal file
@ -0,0 +1,119 @@
|
||||
# Copyright 2017 - 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 datetime import datetime
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import UpdateMethod
|
||||
from vitrage.datasources.doctor import DOCTOR_DATASOURCE
|
||||
from vitrage.datasources.doctor.properties import DoctorDetails
|
||||
from vitrage.datasources.doctor.properties import DoctorProperties \
|
||||
as DoctorProps
|
||||
from vitrage.datasources.doctor.properties import DoctorStatus
|
||||
from vitrage.datasources.doctor.transformer import DoctorTransformer
|
||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources.nova.host.transformer import HostTransformer
|
||||
from vitrage.tests.mocks import mock_transformer
|
||||
from vitrage.tests.unit.datasources.test_alarm_transformer_base import \
|
||||
BaseAlarmTransformerTest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class DoctorTransformerTest(BaseAlarmTransformerTest):
|
||||
|
||||
OPTS = [
|
||||
cfg.StrOpt('update_method',
|
||||
default=UpdateMethod.PUSH),
|
||||
]
|
||||
|
||||
# noinspection PyAttributeOutsideInit,PyPep8Naming
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.transformers = {}
|
||||
cls.conf = cfg.ConfigOpts()
|
||||
cls.conf.register_opts(cls.OPTS, group=DOCTOR_DATASOURCE)
|
||||
cls.conf.register_opts(cls.OPTS, group=NOVA_HOST_DATASOURCE)
|
||||
cls.transformers[DOCTOR_DATASOURCE] = \
|
||||
DoctorTransformer(cls.transformers, cls.conf)
|
||||
cls.transformers[NOVA_HOST_DATASOURCE] = \
|
||||
HostTransformer(cls.transformers, cls.conf)
|
||||
|
||||
def test_create_update_entity_vertex(self):
|
||||
# Test setup
|
||||
time1 = datetime.now().isoformat()
|
||||
host1 = 'host1'
|
||||
event = self._generate_event(time1, host1, DoctorStatus.DOWN)
|
||||
self.assertIsNotNone(event)
|
||||
|
||||
# Test action
|
||||
transformer = self.transformers[DOCTOR_DATASOURCE]
|
||||
wrapper = transformer.transform(event)
|
||||
|
||||
# Test assertions
|
||||
self._validate_vertex_props(wrapper.vertex, event)
|
||||
|
||||
# Validate the neighbors: only one valid host neighbor
|
||||
self._validate_host_neighbor(wrapper,
|
||||
transformer._create_entity_key(event),
|
||||
host1)
|
||||
|
||||
# Validate the expected action on the graph - update or delete
|
||||
self._validate_graph_action(wrapper)
|
||||
|
||||
# Create an event with status 'UP'
|
||||
time2 = datetime.now().isoformat()
|
||||
host2 = 'host2'
|
||||
event = self._generate_event(time2, host2, DoctorStatus.UP)
|
||||
self.assertIsNotNone(event)
|
||||
|
||||
# Test action
|
||||
transformer = self.transformers[DOCTOR_DATASOURCE]
|
||||
wrapper = transformer.transform(event)
|
||||
|
||||
# Test assertions
|
||||
self._validate_vertex_props(wrapper.vertex, event)
|
||||
self._validate_host_neighbor(wrapper,
|
||||
transformer._create_entity_key(event),
|
||||
host2)
|
||||
self._validate_graph_action(wrapper)
|
||||
|
||||
def _validate_vertex_props(self, vertex, event):
|
||||
self._validate_alarm_vertex_props(vertex,
|
||||
event[DoctorProps.TYPE],
|
||||
DOCTOR_DATASOURCE,
|
||||
event[DoctorProps.TIME])
|
||||
|
||||
@staticmethod
|
||||
def _generate_event(time, hostname, status):
|
||||
details = {}
|
||||
if hostname:
|
||||
details[DoctorDetails.HOSTNAME] = hostname
|
||||
if status:
|
||||
details[DoctorDetails.STATUS] = status
|
||||
|
||||
update_vals = {DoctorProps.DETAILS: details}
|
||||
if time:
|
||||
update_vals[DoctorProps.TIME] = time
|
||||
update_vals[DoctorProps.UPDATE_TIME] = time
|
||||
|
||||
generators = mock_transformer.simple_doctor_alarm_generators(
|
||||
update_vals=update_vals)
|
||||
|
||||
return mock_transformer.generate_random_events_list(generators)[0]
|
||||
|
||||
def _is_erroneous(self, vertex):
|
||||
return vertex[DoctorDetails.STATUS] == DoctorStatus.DOWN
|
@ -0,0 +1,83 @@
|
||||
# Copyright 2017 - 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.
|
||||
|
||||
import abc
|
||||
from oslo_log import log as logging
|
||||
|
||||
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.nova.host import NOVA_HOST_DATASOURCE
|
||||
from vitrage.tests.unit.datasources.test_transformer_base import \
|
||||
BaseTransformerTest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class BaseAlarmTransformerTest(BaseTransformerTest):
|
||||
|
||||
def _validate_alarm_vertex_props(self,
|
||||
vertex,
|
||||
expected_name,
|
||||
expected_datasource_name,
|
||||
expected_sample_time):
|
||||
self._validate_base_vertex_props(vertex,
|
||||
expected_name,
|
||||
expected_datasource_name)
|
||||
|
||||
self.assertEqual(EntityCategory.ALARM, vertex[VProps.CATEGORY])
|
||||
self.assertEqual(expected_sample_time, vertex[VProps.SAMPLE_TIMESTAMP])
|
||||
|
||||
if self._is_erroneous(vertex):
|
||||
self.assertEqual(AlarmProps.ACTIVE_STATE, vertex[VProps.STATE])
|
||||
else:
|
||||
self.assertEqual(AlarmProps.INACTIVE_STATE, vertex[VProps.STATE])
|
||||
|
||||
def _validate_host_neighbor(self,
|
||||
wrapper,
|
||||
alarm_id,
|
||||
host_name):
|
||||
|
||||
self.assertEqual(1, len(wrapper.neighbors))
|
||||
host_neighbor = wrapper.neighbors[0]
|
||||
|
||||
host_transformer = self.transformers[NOVA_HOST_DATASOURCE]
|
||||
properties = {
|
||||
VProps.ID: host_name,
|
||||
VProps.TYPE: NOVA_HOST_DATASOURCE,
|
||||
VProps.SAMPLE_TIMESTAMP: wrapper.vertex[VProps.SAMPLE_TIMESTAMP],
|
||||
}
|
||||
expected_neighbor = host_transformer.\
|
||||
create_placeholder_vertex(**properties)
|
||||
|
||||
self.assertEqual(expected_neighbor, host_neighbor.vertex)
|
||||
|
||||
# Validate neighbor edge
|
||||
edge = host_neighbor.edge
|
||||
self.assertEqual(edge.source_id, alarm_id)
|
||||
self.assertEqual(edge.target_id, host_neighbor.vertex.vertex_id)
|
||||
self.assertEqual(edge.label, EdgeLabel.ON)
|
||||
|
||||
def _validate_graph_action(self, wrapper):
|
||||
if self._is_erroneous(wrapper.vertex):
|
||||
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
|
||||
else:
|
||||
self.assertEqual(GraphAction.DELETE_ENTITY, wrapper.action)
|
||||
|
||||
@abc.abstractmethod
|
||||
def _is_erroneous(self, vertex):
|
||||
pass
|
32
vitrage/tests/unit/datasources/test_transformer_base.py
Normal file
32
vitrage/tests/unit/datasources/test_transformer_base.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2017 - 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 as logging
|
||||
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.tests import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class BaseTransformerTest(base.BaseTest):
|
||||
|
||||
def _validate_base_vertex_props(self,
|
||||
vertex,
|
||||
expected_name,
|
||||
expected_datasource_name):
|
||||
self.assertFalse(vertex[VProps.IS_PLACEHOLDER])
|
||||
self.assertEqual(expected_datasource_name, vertex[VProps.TYPE])
|
||||
self.assertEqual(expected_name, vertex[VProps.NAME])
|
Loading…
Reference in New Issue
Block a user