Add a new zaqar notifier
also did some minor refactorings to the other notifiers Story: 2002681 Task: 22499 Change-Id: I06dfae2b67d1966eed472123f5bb6627d4cb19d0
This commit is contained in:
parent
30383d2dea
commit
cbf1b32498
@ -38,6 +38,7 @@ Notifiers
|
|||||||
notifier-snmp-plugin
|
notifier-snmp-plugin
|
||||||
mistral-config
|
mistral-config
|
||||||
notifier-webhook-plugin
|
notifier-webhook-plugin
|
||||||
|
zaqar_notifier
|
||||||
|
|
||||||
|
|
||||||
Machine_Learning
|
Machine_Learning
|
||||||
|
21
doc/source/contributor/zaqar_notifier.rst
Normal file
21
doc/source/contributor/zaqar_notifier.rst
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
===================
|
||||||
|
Zaqar Configuration
|
||||||
|
===================
|
||||||
|
|
||||||
|
Vitrage can be configured to notify raised or cleared alarms to Zaqar (the OpenStack Messaging service)
|
||||||
|
|
||||||
|
|
||||||
|
Enable Zaqar Notifier
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
To enable Zaqar notifier, add zaqar to the list of notifiers and add the zaqar queue in
|
||||||
|
/etc/vitrage/vitrage.conf file:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
notifiers = zaqar
|
||||||
|
|
||||||
|
[zaqar]
|
||||||
|
queue = <zaqar queue name to post the message>
|
||||||
|
|
@ -141,3 +141,4 @@ Werkzeug==0.14.1
|
|||||||
wrapt==1.10.11
|
wrapt==1.10.11
|
||||||
futures==3.0.0
|
futures==3.0.0
|
||||||
docutils==0.11
|
docutils==0.11
|
||||||
|
python-zaqarclient==1.2.0
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
features:
|
||||||
|
- A new ``zaqar notifier`` was added, in order to send alrmas from Vitrage
|
||||||
|
to zaqar messaging framework.
|
@ -16,6 +16,7 @@ python-heatclient>=1.14.0 # Apache-2.0
|
|||||||
python-mistralclient>=3.3.0 # Apache-2.0
|
python-mistralclient>=3.3.0 # Apache-2.0
|
||||||
python-openstackclient>=3.12.0 # Apache-2.0
|
python-openstackclient>=3.12.0 # Apache-2.0
|
||||||
python-troveclient>=2.2.0 # Apache-2.0
|
python-troveclient>=2.2.0 # Apache-2.0
|
||||||
|
python-zaqarclient >=1.2.0
|
||||||
gnocchiclient>=3.3.1 # Apache-2.0
|
gnocchiclient>=3.3.1 # Apache-2.0
|
||||||
pyzabbix>=0.7.4 # LGPL
|
pyzabbix>=0.7.4 # LGPL
|
||||||
networkx>=2.0 # BSD
|
networkx>=2.0 # BSD
|
||||||
|
@ -120,8 +120,8 @@ class GraphAction(object):
|
|||||||
class NotifierEventTypes(object):
|
class NotifierEventTypes(object):
|
||||||
ACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.activate'
|
ACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.activate'
|
||||||
DEACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.deactivate'
|
DEACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.deactivate'
|
||||||
ACTIVATE_ALARM_EVENT = 'vitrage.alarm.activate'
|
ACTIVATE_ALARM_EVENT = 'vitrage.alarm.activate' # also deduce
|
||||||
DEACTIVATE_ALARM_EVENT = 'vitrage.alarm.deactivate'
|
DEACTIVATE_ALARM_EVENT = 'vitrage.alarm.deactivate' # also deduce
|
||||||
CHANGE_IN_ALARM_EVENT = 'vitrage.alarm.change'
|
CHANGE_IN_ALARM_EVENT = 'vitrage.alarm.change'
|
||||||
CHANGE_PROJECT_ID_EVENT = 'vitrage.alarm.change_project_id'
|
CHANGE_PROJECT_ID_EVENT = 'vitrage.alarm.change_project_id'
|
||||||
ACTIVATE_MARK_DOWN_EVENT = 'vitrage.mark_down.activate'
|
ACTIVATE_MARK_DOWN_EVENT = 'vitrage.mark_down.activate'
|
||||||
@ -129,6 +129,7 @@ class NotifierEventTypes(object):
|
|||||||
EXECUTE_EXTERNAL_ACTION = 'vitrage.execute_external_action'
|
EXECUTE_EXTERNAL_ACTION = 'vitrage.execute_external_action'
|
||||||
ACTIVATE_CAUSAL_RELATION = 'vitrage.causal_relationship.activate'
|
ACTIVATE_CAUSAL_RELATION = 'vitrage.causal_relationship.activate'
|
||||||
DEACTIVATE_CAUSAL_RELATION = 'vitrage.causal_relationship.deactivate'
|
DEACTIVATE_CAUSAL_RELATION = 'vitrage.causal_relationship.deactivate'
|
||||||
|
ALARMS = {ACTIVATE_ALARM_EVENT, DEACTIVATE_ALARM_EVENT}
|
||||||
|
|
||||||
|
|
||||||
class TemplateTopologyFields(object):
|
class TemplateTopologyFields(object):
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
# 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
|
|
@ -56,12 +56,12 @@ class AodhNotifier(NotifierBase):
|
|||||||
if response and response.alarm_id:
|
if response and response.alarm_id:
|
||||||
LOG.info('Aodh Alarm id %s: ', response.alarm_id)
|
LOG.info('Aodh Alarm id %s: ', response.alarm_id)
|
||||||
else:
|
else:
|
||||||
LOG.error('Failed to %s Aodh Alarm \n%s', event_type, str(data))
|
LOG.error('Failed to %s Aodh Alarm \n%s', event_type, data)
|
||||||
|
|
||||||
def _create_aodh_alarm(self, alarm, state):
|
def _create_aodh_alarm(self, alarm, state):
|
||||||
alarm_request = _alarm_request(alarm, state)
|
alarm_request = _alarm_request(alarm, state)
|
||||||
try:
|
try:
|
||||||
LOG.info('Aodh Alarm - Activate: ' + str(alarm_request))
|
LOG.info('Aodh Alarm - Activate: ' + alarm_request)
|
||||||
return self.client.alarm.create(alarm_request)
|
return self.client.alarm.create(alarm_request)
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception('Failed to activate Aodh Alarm. Got Exception.')
|
LOG.exception('Failed to activate Aodh Alarm. Got Exception.')
|
||||||
|
@ -51,7 +51,7 @@ class NovaNotifier(NotifierBase):
|
|||||||
if action:
|
if action:
|
||||||
action(data.get(VProps.ID), is_down)
|
action(data.get(VProps.ID), is_down)
|
||||||
else:
|
else:
|
||||||
LOG.warning('Unsupport datasource type %s for mark_down '
|
LOG.warning('Unsupported datasource type %s for mark_down '
|
||||||
'action', data.get(VProps.VITRAGE_TYPE))
|
'action', data.get(VProps.VITRAGE_TYPE))
|
||||||
|
|
||||||
def _mark_host_down(self, host_id, is_down):
|
def _mark_host_down(self, host_id, is_down):
|
||||||
@ -68,7 +68,7 @@ class NovaNotifier(NotifierBase):
|
|||||||
state = InstanceState.ERROR if is_down else InstanceState.ACTIVE
|
state = InstanceState.ERROR if is_down else InstanceState.ACTIVE
|
||||||
try:
|
try:
|
||||||
LOG.info('Nova servers.reset_state - server: %s, state: %s',
|
LOG.info('Nova servers.reset_state - server: %s, state: %s',
|
||||||
str(server_id), str(state))
|
server_id, state)
|
||||||
response = self.client.servers.reset_state(server_id, state)
|
response = self.client.servers.reset_state(server_id, state)
|
||||||
LOG.info('RESPONSE %s', str(response))
|
LOG.info('RESPONSE %s', str(response))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -67,17 +67,15 @@ class Webhook(NotifierBase):
|
|||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
super(Webhook, self).__init__(conf)
|
super(Webhook, self).__init__(conf)
|
||||||
self.conf = conf
|
|
||||||
self._db = storage.get_connection_from_config(self.conf)
|
self._db = storage.get_connection_from_config(self.conf)
|
||||||
self.max_retries = self.conf.webhook.max_retries
|
self.max_retries = self.conf.webhook.max_retries
|
||||||
self.default_headers = {'content-type': 'application/json'}
|
self.default_headers = {'content-type': 'application/json'}
|
||||||
|
|
||||||
def process_event(self, data, event_type):
|
def process_event(self, data, event_type):
|
||||||
|
|
||||||
if event_type == NotifierEventTypes.ACTIVATE_ALARM_EVENT \
|
if event_type in NotifierEventTypes.ALARMS:
|
||||||
or event_type == NotifierEventTypes.DEACTIVATE_ALARM_EVENT:
|
|
||||||
|
|
||||||
LOG.info('Webhook notifier started processing %s', str(data))
|
LOG.info('Webhook notifier started processing %s', data)
|
||||||
|
|
||||||
webhooks = self._load_webhooks()
|
webhooks = self._load_webhooks()
|
||||||
|
|
||||||
@ -89,32 +87,31 @@ class Webhook(NotifierBase):
|
|||||||
data = self._filter_fields(data)
|
data = self._filter_fields(data)
|
||||||
|
|
||||||
LOG.debug('webhook_filter: %s, filtered data: %s',
|
LOG.debug('webhook_filter: %s, filtered data: %s',
|
||||||
str(webhook_filters), str(data))
|
webhook_filters, data)
|
||||||
|
|
||||||
if self._check_against_filter(webhook_filters, data)\
|
if self._check_against_filter(webhook_filters, data)\
|
||||||
and self._check_correct_tenant(webhook, data):
|
and self._check_correct_tenant(webhook, data):
|
||||||
LOG.info('Going to post data to webhook %s',
|
LOG.info('Going to post data to webhook %s', webhook)
|
||||||
str(webhook))
|
|
||||||
self._post_data(webhook, event_type, data)
|
self._post_data(webhook, event_type, data)
|
||||||
|
|
||||||
LOG.info('Webhook notifier finished processing %s', str(data))
|
LOG.info('Webhook notifier finished processing %s', data)
|
||||||
|
|
||||||
def _post_data(self, webhook, event_type, data):
|
def _post_data(self, webhook, event_type, data):
|
||||||
try:
|
try:
|
||||||
webhook_data = {'notification': event_type, 'payload': data}
|
webhook_data = {'notification': event_type, 'payload': data}
|
||||||
webhook_headers = self._get_webhook_headers(webhook)
|
webhook_headers = self._get_webhook_headers(webhook)
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
session.mount(str(webhook[URL]),
|
session.mount(webhook[URL],
|
||||||
requests.adapters.HTTPAdapter(
|
requests.adapters.HTTPAdapter(
|
||||||
max_retries=self.max_retries))
|
max_retries=self.max_retries))
|
||||||
resp = session.post(str(webhook[URL]),
|
resp = session.post(str(webhook[URL]),
|
||||||
data=jsonutils.dumps(webhook_data),
|
data=jsonutils.dumps(webhook_data),
|
||||||
headers=webhook_headers)
|
headers=webhook_headers)
|
||||||
LOG.info('posted %s to %s. Response status %s, reason %s',
|
LOG.info('posted %s to %s. Response status %s, reason %s',
|
||||||
str(webhook_data), str(webhook[URL]),
|
webhook_data, webhook[URL],
|
||||||
resp.status_code, resp.reason)
|
resp.status_code, resp.reason)
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception("Could not post to webhook '%s'", str(webhook['id']))
|
LOG.exception("Could not post to webhook '%s'", webhook['id'])
|
||||||
|
|
||||||
def _load_webhooks(self):
|
def _load_webhooks(self):
|
||||||
db_webhooks = self._db.webhooks.query()
|
db_webhooks = self._db.webhooks.query()
|
||||||
|
28
vitrage/notifier/plugins/zaqar/__init__.py
Normal file
28
vitrage/notifier/plugins/zaqar/__init__.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Copyright 2019 - Nokia Corporation
|
||||||
|
# #
|
||||||
|
# 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
|
||||||
|
|
||||||
|
OPTS = [
|
||||||
|
cfg.StrOpt('notifier',
|
||||||
|
default='vitrage.notifier.plugins.zaqar.'
|
||||||
|
'zaqar_notifier.ZaqarNotifier',
|
||||||
|
help='zaqar notifier class path',
|
||||||
|
required=True),
|
||||||
|
|
||||||
|
cfg.StrOpt('queue',
|
||||||
|
default='alarms',
|
||||||
|
help='zaqar queue to post messages',
|
||||||
|
required=True),
|
||||||
|
]
|
40
vitrage/notifier/plugins/zaqar/zaqar_notifier.py
Normal file
40
vitrage/notifier/plugins/zaqar/zaqar_notifier.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Copyright 2019 - Nokia Corporation
|
||||||
|
# #
|
||||||
|
# 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
|
||||||
|
|
||||||
|
from vitrage.common.constants import NotifierEventTypes
|
||||||
|
from vitrage.notifier.plugins.base import NotifierBase
|
||||||
|
from vitrage import os_clients
|
||||||
|
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ZaqarNotifier(NotifierBase):
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
super(ZaqarNotifier, self).__init__(conf)
|
||||||
|
client = os_clients.zaqar_client(self.conf)
|
||||||
|
self._queue = client.queue(self.conf.zaqar.queue)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_notifier_name():
|
||||||
|
return 'zaqar'
|
||||||
|
|
||||||
|
def process_event(self, data, event_type):
|
||||||
|
if event_type in NotifierEventTypes.ALARMS:
|
||||||
|
try:
|
||||||
|
self._queue.post(data)
|
||||||
|
except Exception:
|
||||||
|
LOG.exception('Failed to post message to zaqar')
|
@ -29,6 +29,7 @@ import vitrage.machine_learning.plugins.jaccard_correlation
|
|||||||
import vitrage.notifier
|
import vitrage.notifier
|
||||||
import vitrage.notifier.plugins.snmp
|
import vitrage.notifier.plugins.snmp
|
||||||
import vitrage.notifier.plugins.webhook
|
import vitrage.notifier.plugins.webhook
|
||||||
|
import vitrage.notifier.plugins.zaqar
|
||||||
import vitrage.os_clients
|
import vitrage.os_clients
|
||||||
import vitrage.persistency
|
import vitrage.persistency
|
||||||
import vitrage.rpc
|
import vitrage.rpc
|
||||||
@ -61,6 +62,7 @@ def list_opts():
|
|||||||
('snmp', vitrage.notifier.plugins.snmp.OPTS),
|
('snmp', vitrage.notifier.plugins.snmp.OPTS),
|
||||||
('webhook', vitrage.notifier.plugins.webhook.OPTS),
|
('webhook', vitrage.notifier.plugins.webhook.OPTS),
|
||||||
('snmp_parsing', vitrage.snmp_parsing.OPTS),
|
('snmp_parsing', vitrage.snmp_parsing.OPTS),
|
||||||
|
('zaqar', vitrage.notifier.plugins.zaqar.OPTS),
|
||||||
('DEFAULT', itertools.chain(
|
('DEFAULT', itertools.chain(
|
||||||
vitrage.os_clients.OPTS,
|
vitrage.os_clients.OPTS,
|
||||||
vitrage.rpc.OPTS,
|
vitrage.rpc.OPTS,
|
||||||
|
@ -192,3 +192,16 @@ def mistral_client(conf):
|
|||||||
return client
|
return client
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception('Create Mistral client - Got Exception.')
|
LOG.exception('Create Mistral client - Got Exception.')
|
||||||
|
|
||||||
|
|
||||||
|
def zaqar_client(conf):
|
||||||
|
"""Get an instance of Zaqar client"""
|
||||||
|
try:
|
||||||
|
z_client = driver_module('zaqar')
|
||||||
|
client = z_client.Client(
|
||||||
|
session=keystone_client.get_session(conf),
|
||||||
|
)
|
||||||
|
LOG.info('Zaqar client created')
|
||||||
|
return client
|
||||||
|
except Exception:
|
||||||
|
LOG.exception('Create Zaqar client - Got Exception.')
|
||||||
|
Loading…
Reference in New Issue
Block a user