Merge "add nova force-down-notifier"
This commit is contained in:
commit
34cf3cfb1d
@ -26,7 +26,7 @@ LOG = log.getLogger(__name__)
|
||||
|
||||
OPTS = [
|
||||
cfg.StrOpt('aodh_version', default='2', help='Aodh version'),
|
||||
cfg.FloatOpt('nova_version', default='2.0', help='Nova version'),
|
||||
cfg.FloatOpt('nova_version', default='2.11', help='Nova version'),
|
||||
cfg.StrOpt('cinder_version', default='1', help='Cinder version'),
|
||||
]
|
||||
|
||||
|
@ -24,6 +24,6 @@ OPTS = [
|
||||
),
|
||||
cfg.StrOpt('notifier_topic',
|
||||
default='vitrage.graph',
|
||||
help='The topic that vitrage-graph uses for alarm '
|
||||
help='The topic that vitrage-graph uses for graph '
|
||||
'notification messages.'),
|
||||
]
|
||||
|
@ -24,7 +24,7 @@ from vitrage.messaging import get_transport
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class DeducedAlarmNotifier(object):
|
||||
class GraphNotifier(object):
|
||||
"""Allows writing to message bus"""
|
||||
def __init__(self, conf):
|
||||
self.oslo_notifier = None
|
||||
@ -32,16 +32,16 @@ class DeducedAlarmNotifier(object):
|
||||
topic = conf.entity_graph.notifier_topic
|
||||
notifier_plugins = conf.notifiers
|
||||
if not topic or not notifier_plugins:
|
||||
LOG.info('DeducedAlarmNotifier is disabled')
|
||||
LOG.info('Graph Notifier is disabled')
|
||||
return
|
||||
|
||||
self.oslo_notifier = oslo_messaging.Notifier(
|
||||
get_transport(conf),
|
||||
driver='messagingv2',
|
||||
publisher_id='vitrage.deduced',
|
||||
publisher_id='vitrage.graph',
|
||||
topic=topic)
|
||||
except Exception as e:
|
||||
LOG.info('DeducedAlarmNotifier missing configuration %s' % str(e))
|
||||
LOG.info('Graph Notifier - missing configuration %s' % str(e))
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
@ -57,38 +57,67 @@ class DeducedAlarmNotifier(object):
|
||||
change that happened. Deleted elements should arrive with the
|
||||
is_deleted property set to True
|
||||
"""
|
||||
notification_type = _get_notification_type(before, current, is_vertex)
|
||||
if not notification_type:
|
||||
notification_types = _get_notification_type(before, current, is_vertex)
|
||||
if not notification_types:
|
||||
return
|
||||
|
||||
LOG.debug('DeducedAlarmNotifier : %s', notification_type)
|
||||
LOG.debug('DeducedAlarmNotifier : %s', current.properties)
|
||||
LOG.info('notification_types : %s', str(notification_types))
|
||||
LOG.info('notification properties : %s', current.properties)
|
||||
|
||||
try:
|
||||
self.oslo_notifier.info({}, notification_type, current.properties)
|
||||
except Exception as e:
|
||||
LOG.exception('DeducedAlarmNotifier cannot notify - %s', e)
|
||||
for notification_type in notification_types:
|
||||
try:
|
||||
self.oslo_notifier.info(
|
||||
{},
|
||||
notification_type,
|
||||
current.properties)
|
||||
except Exception as e:
|
||||
LOG.exception('Cannot notify - %s - %s', notification_type, e)
|
||||
|
||||
|
||||
def _get_notification_type(before, current, is_vertex):
|
||||
if not is_vertex:
|
||||
return None
|
||||
if not _is_active_deduced_alarm(before) and \
|
||||
_is_active_deduced_alarm(current):
|
||||
return NotifierEventTypes.ACTIVATE_DEDUCED_ALARM_EVENT
|
||||
if _is_active_deduced_alarm(before) and \
|
||||
not _is_active_deduced_alarm(current):
|
||||
return NotifierEventTypes.DEACTIVATE_DEDUCED_ALARM_EVENT
|
||||
|
||||
def notification_type(is_active,
|
||||
activate_event_type,
|
||||
deactivate_event_type):
|
||||
if not is_active(before):
|
||||
if is_active(current):
|
||||
return activate_event_type
|
||||
else:
|
||||
if not is_active(current):
|
||||
return deactivate_event_type
|
||||
|
||||
notification_types = [
|
||||
notification_type(_is_active_deduced_alarm,
|
||||
NotifierEventTypes.ACTIVATE_DEDUCED_ALARM_EVENT,
|
||||
NotifierEventTypes.DEACTIVATE_DEDUCED_ALARM_EVENT),
|
||||
notification_type(_is_marked_down,
|
||||
NotifierEventTypes.ACTIVATE_MARK_DOWN_EVENT,
|
||||
NotifierEventTypes.DEACTIVATE_MARK_DOWN_EVENT),
|
||||
]
|
||||
return list(filter(None, notification_types))
|
||||
|
||||
|
||||
def _is_active_deduced_alarm(vertex):
|
||||
if not vertex:
|
||||
return False
|
||||
if vertex.get(VProps.CATEGORY) == EntityCategory.ALARM and \
|
||||
vertex.get(VProps.TYPE) == evaluator.VITRAGE_TYPE:
|
||||
return _is_relevant_vertex(vertex)
|
||||
return False
|
||||
|
||||
if not (vertex.get(VProps.CATEGORY) == EntityCategory.ALARM and
|
||||
vertex.get(VProps.TYPE) == evaluator.VITRAGE_TYPE):
|
||||
|
||||
def _is_marked_down(vertex):
|
||||
if not vertex:
|
||||
return False
|
||||
if vertex.get(VProps.CATEGORY) == EntityCategory.RESOURCE and \
|
||||
vertex.get(VProps.IS_MARKED_DOWN) is True:
|
||||
return _is_relevant_vertex(vertex)
|
||||
return False
|
||||
|
||||
|
||||
def _is_relevant_vertex(vertex):
|
||||
if vertex.get(VProps.IS_DELETED, False) or \
|
||||
vertex.get(VProps.IS_PLACEHOLDER, False):
|
||||
return False
|
||||
|
@ -22,7 +22,7 @@ from vitrage.entity_graph.mappings.datasource_info_mapper import \
|
||||
DatasourceInfoMapper
|
||||
from vitrage.entity_graph.processor import base as processor
|
||||
from vitrage.entity_graph.processor import entity_graph
|
||||
from vitrage.entity_graph.processor.notifier import DeducedAlarmNotifier
|
||||
from vitrage.entity_graph.processor.notifier import GraphNotifier
|
||||
from vitrage.entity_graph.processor import processor_utils as PUtils
|
||||
from vitrage.entity_graph.transformer_manager import TransformerManager
|
||||
from vitrage.graph import Direction
|
||||
@ -41,7 +41,7 @@ class Processor(processor.ProcessorBase):
|
||||
self.initialization_status = initialization_status
|
||||
self.entity_graph = entity_graph.EntityGraph("Entity Graph") if \
|
||||
e_graph is None else e_graph
|
||||
self._notifier = DeducedAlarmNotifier(conf)
|
||||
self._notifier = GraphNotifier(conf)
|
||||
|
||||
def process_event(self, event):
|
||||
"""Decides which action to run on given event
|
||||
|
@ -16,5 +16,5 @@ from oslo_config import cfg
|
||||
|
||||
OPTS = [
|
||||
cfg.ListOpt('notifiers',
|
||||
help='Names of enabled notifiers (example aodh)'),
|
||||
help='Names of enabled notifiers (example aodh, nova)'),
|
||||
]
|
||||
|
15
vitrage/notifier/plugins/nova/__init__.py
Normal file
15
vitrage/notifier/plugins/nova/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
|
||||
pass
|
51
vitrage/notifier/plugins/nova/nova_notifier.py
Normal file
51
vitrage/notifier/plugins/nova/nova_notifier.py
Normal file
@ -0,0 +1,51 @@
|
||||
# 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 import clients
|
||||
from vitrage.common.constants import NotifierEventTypes
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
||||
from vitrage.notifier.plugins.base import NotifierBase
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NovaNotifier(NotifierBase):
|
||||
|
||||
@staticmethod
|
||||
def get_notifier_name():
|
||||
return 'nova'
|
||||
|
||||
def __init__(self, conf):
|
||||
super(NovaNotifier, self).__init__(conf)
|
||||
self.client = clients.nova_client(conf)
|
||||
|
||||
def process_event(self, data, event_type):
|
||||
if data and data.get(VProps.TYPE) is NOVA_HOST_DATASOURCE:
|
||||
if event_type == NotifierEventTypes.ACTIVATE_MARK_DOWN_EVENT:
|
||||
self._mark_host_down(data.get(VProps.ID), True)
|
||||
elif event_type == NotifierEventTypes.DEACTIVATE_MARK_DOWN_EVENT:
|
||||
self._mark_host_down(data.get(VProps.ID), False)
|
||||
|
||||
def _mark_host_down(self, host_id, is_down):
|
||||
try:
|
||||
LOG.info('Nova services.force_down - host id: %s, is_down: %s',
|
||||
str(host_id), str(is_down))
|
||||
response = self.client.services.force_down(
|
||||
host_id, 'nova-compute', is_down)
|
||||
LOG.info('RESPONSE %s', str(response))
|
||||
except Exception as e:
|
||||
LOG.exception('Failed to services.force_down - %s', e)
|
||||
return
|
@ -18,6 +18,7 @@ from oslo_service import service as os_service
|
||||
|
||||
from vitrage import messaging
|
||||
from vitrage.notifier.plugins.aodh.aodh_notifier import AodhNotifier
|
||||
from vitrage.notifier.plugins.nova.nova_notifier import NovaNotifier
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
@ -59,7 +60,7 @@ class VitrageNotifierService(os_service.Service):
|
||||
if not conf_notifier_names:
|
||||
LOG.info('There are no notifier plugins in configuration')
|
||||
return []
|
||||
for plugin in [AodhNotifier]:
|
||||
for plugin in [AodhNotifier, NovaNotifier]:
|
||||
plugin_name = plugin.get_notifier_name()
|
||||
if plugin_name in conf_notifier_names:
|
||||
LOG.info('Notifier plugin %s started', plugin_name)
|
||||
|
@ -18,6 +18,7 @@ test_vitrage graph
|
||||
|
||||
Tests for `vitrage` graph driver
|
||||
"""
|
||||
import copy
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import NotifierEventTypes as NType
|
||||
@ -33,16 +34,14 @@ resource = Vertex('123', {
|
||||
VProps.TYPE: 'some_resource_type',
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: False,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
deduced_alarm = Vertex('123', {
|
||||
VProps.CATEGORY: EntityCategory.ALARM,
|
||||
VProps.TYPE: evaluator.VITRAGE_TYPE,
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: False,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
non_deduced_alarm = Vertex('123', {
|
||||
@ -50,56 +49,146 @@ non_deduced_alarm = Vertex('123', {
|
||||
VProps.TYPE: 'TEST_ALARM',
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: True,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
deleted_alarm = Vertex('123', {
|
||||
VProps.CATEGORY: EntityCategory.ALARM,
|
||||
VProps.TYPE: evaluator.VITRAGE_TYPE,
|
||||
VProps.IS_DELETED: True,
|
||||
VProps.IS_PLACEHOLDER: False,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
placeholder_alarm = Vertex('123', {
|
||||
VProps.CATEGORY: EntityCategory.ALARM,
|
||||
VProps.TYPE: evaluator.VITRAGE_TYPE,
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: True,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
host = Vertex('123', {
|
||||
VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: 'nova.host',
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: False,
|
||||
})
|
||||
|
||||
forced_down_host = Vertex('123', {
|
||||
VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: 'nova.host',
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: False,
|
||||
VProps.IS_MARKED_DOWN: True,
|
||||
})
|
||||
|
||||
|
||||
class GraphTest(base.BaseTest):
|
||||
def get_first(self, lst):
|
||||
self.assertIsNotNone(lst)
|
||||
return lst[0] if len(lst) > 0 else None
|
||||
|
||||
def test_notification_type_new_alarm(self):
|
||||
ret = _get_notification_type(None, deduced_alarm, True)
|
||||
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT, ret,
|
||||
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT,
|
||||
self.get_first(ret),
|
||||
'new alarm should notify activate')
|
||||
|
||||
ret = _get_notification_type(None, non_deduced_alarm, True)
|
||||
self.assertIsNone(ret, 'alarm that is not a deduced alarm')
|
||||
self.assertIsNone(self.get_first(ret),
|
||||
'alarm that is not a deduced alarm')
|
||||
|
||||
def test_notification_type_deleted_alarm(self):
|
||||
ret = _get_notification_type(deduced_alarm, deleted_alarm, True)
|
||||
self.assertEqual(NType.DEACTIVATE_DEDUCED_ALARM_EVENT, ret,
|
||||
self.assertEqual(NType.DEACTIVATE_DEDUCED_ALARM_EVENT,
|
||||
self.get_first(ret),
|
||||
'deleted alarm should notify deactivate')
|
||||
|
||||
def test_notification_type_resource_vertex(self):
|
||||
ret = _get_notification_type(None, resource, True)
|
||||
self.assertIsNone(ret, 'any non alarm vertex should be ignored')
|
||||
self.assertIsNone(self.get_first(ret),
|
||||
'any non alarm vertex should be ignored')
|
||||
|
||||
def test_notification_type_updated_alarm(self):
|
||||
ret = _get_notification_type(deduced_alarm, deduced_alarm, True)
|
||||
self.assertIsNone(ret, 'A not new alarm vertex should be ignored')
|
||||
self.assertIsNone(self.get_first(ret),
|
||||
'A not new alarm vertex should be ignored')
|
||||
|
||||
ret = _get_notification_type(deleted_alarm, deduced_alarm, True)
|
||||
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT, ret,
|
||||
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT,
|
||||
self.get_first(ret),
|
||||
'old alarm become not deleted should notify activate')
|
||||
|
||||
ret = _get_notification_type(placeholder_alarm, deduced_alarm, True)
|
||||
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT, ret,
|
||||
self.assertEqual(NType.ACTIVATE_DEDUCED_ALARM_EVENT,
|
||||
self.get_first(ret),
|
||||
'placeholder become active should notify activate')
|
||||
|
||||
def test_notification_type_placeholder_alarm(self):
|
||||
ret = _get_notification_type(None, placeholder_alarm, True)
|
||||
self.assertIsNone(ret, 'A not new alarm vertex should be ignored')
|
||||
self.assertIsNone(self.get_first(ret),
|
||||
'A not new alarm vertex should be ignored')
|
||||
|
||||
def test_notification_type_new_host(self):
|
||||
ret = _get_notification_type(None, forced_down_host, True)
|
||||
self.assertEqual(NType.ACTIVATE_MARK_DOWN_EVENT,
|
||||
self.get_first(ret),
|
||||
'new host with forced_down should notify activate')
|
||||
|
||||
ret = _get_notification_type(None, host, True)
|
||||
self.assertIsNone(self.get_first(ret), 'host without forced_down')
|
||||
|
||||
def test_notification_type_deleted_host(self):
|
||||
deleted_host = copy.deepcopy(forced_down_host)
|
||||
deleted_host[VProps.IS_DELETED] = True
|
||||
ret = _get_notification_type(forced_down_host, deleted_host, True)
|
||||
self.assertEqual(
|
||||
NType.DEACTIVATE_MARK_DOWN_EVENT,
|
||||
self.get_first(ret),
|
||||
'deleted host with forced_down should notify deactivate')
|
||||
|
||||
deleted_host = copy.deepcopy(host)
|
||||
deleted_host[VProps.IS_DELETED] = True
|
||||
ret = _get_notification_type(forced_down_host, deleted_host, True)
|
||||
self.assertEqual(
|
||||
NType.DEACTIVATE_MARK_DOWN_EVENT,
|
||||
self.get_first(ret),
|
||||
'deleted host with forced_down should notify deactivate')
|
||||
|
||||
deleted_host = copy.deepcopy(host)
|
||||
deleted_host[VProps.IS_DELETED] = True
|
||||
ret = _get_notification_type(host, deleted_host, True)
|
||||
self.assertIsNone(
|
||||
self.get_first(ret),
|
||||
'deleted host without forced_down should not notify')
|
||||
|
||||
def test_notification_type_updated_host(self):
|
||||
ret = _get_notification_type(forced_down_host, forced_down_host, True)
|
||||
self.assertIsNone(self.get_first(ret),
|
||||
'A not new host should be ignored')
|
||||
|
||||
deleted_host = copy.deepcopy(forced_down_host)
|
||||
deleted_host[VProps.IS_DELETED] = True
|
||||
ret = _get_notification_type(deleted_host, forced_down_host, True)
|
||||
self.assertEqual(NType.ACTIVATE_MARK_DOWN_EVENT,
|
||||
self.get_first(ret),
|
||||
'old host become not deleted should notify activate')
|
||||
|
||||
deleted_host = copy.deepcopy(forced_down_host)
|
||||
deleted_host[VProps.IS_DELETED] = True
|
||||
ret = _get_notification_type(deleted_host, host, True)
|
||||
self.assertIsNone(self.get_first(ret),
|
||||
'old host become not deleted should not notify')
|
||||
|
||||
placeholder_host = copy.deepcopy(forced_down_host)
|
||||
placeholder_host[VProps.IS_PLACEHOLDER] = True
|
||||
ret = _get_notification_type(placeholder_host, forced_down_host, True)
|
||||
self.assertEqual(NType.ACTIVATE_MARK_DOWN_EVENT,
|
||||
self.get_first(ret),
|
||||
'placeholder become active should notify activate')
|
||||
|
||||
def test_notification_type_placeholder_host(self):
|
||||
placeholder_host = copy.deepcopy(forced_down_host)
|
||||
placeholder_host[VProps.IS_PLACEHOLDER] = True
|
||||
ret = _get_notification_type(None, placeholder_host, True)
|
||||
self.assertIsNone(self.get_first(ret),
|
||||
'A not new host vertex should be ignored')
|
||||
|
Loading…
x
Reference in New Issue
Block a user