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:
Eyal 2019-01-10 15:23:19 +02:00
parent 30383d2dea
commit cbf1b32498
14 changed files with 125 additions and 32 deletions

View File

@ -38,6 +38,7 @@ Notifiers
notifier-snmp-plugin
mistral-config
notifier-webhook-plugin
zaqar_notifier
Machine_Learning

View 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>

View File

@ -141,3 +141,4 @@ Werkzeug==0.14.1
wrapt==1.10.11
futures==3.0.0
docutils==0.11
python-zaqarclient==1.2.0

View File

@ -0,0 +1,3 @@
features:
- A new ``zaqar notifier`` was added, in order to send alrmas from Vitrage
to zaqar messaging framework.

View File

@ -16,6 +16,7 @@ python-heatclient>=1.14.0 # Apache-2.0
python-mistralclient>=3.3.0 # Apache-2.0
python-openstackclient>=3.12.0 # Apache-2.0
python-troveclient>=2.2.0 # Apache-2.0
python-zaqarclient >=1.2.0
gnocchiclient>=3.3.1 # Apache-2.0
pyzabbix>=0.7.4 # LGPL
networkx>=2.0 # BSD

View File

@ -120,8 +120,8 @@ class GraphAction(object):
class NotifierEventTypes(object):
ACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.activate'
DEACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.deactivate'
ACTIVATE_ALARM_EVENT = 'vitrage.alarm.activate'
DEACTIVATE_ALARM_EVENT = 'vitrage.alarm.deactivate'
ACTIVATE_ALARM_EVENT = 'vitrage.alarm.activate' # also deduce
DEACTIVATE_ALARM_EVENT = 'vitrage.alarm.deactivate' # also deduce
CHANGE_IN_ALARM_EVENT = 'vitrage.alarm.change'
CHANGE_PROJECT_ID_EVENT = 'vitrage.alarm.change_project_id'
ACTIVATE_MARK_DOWN_EVENT = 'vitrage.mark_down.activate'
@ -129,6 +129,7 @@ class NotifierEventTypes(object):
EXECUTE_EXTERNAL_ACTION = 'vitrage.execute_external_action'
ACTIVATE_CAUSAL_RELATION = 'vitrage.causal_relationship.activate'
DEACTIVATE_CAUSAL_RELATION = 'vitrage.causal_relationship.deactivate'
ALARMS = {ACTIVATE_ALARM_EVENT, DEACTIVATE_ALARM_EVENT}
class TemplateTopologyFields(object):

View File

@ -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

View File

@ -56,12 +56,12 @@ class AodhNotifier(NotifierBase):
if response and response.alarm_id:
LOG.info('Aodh Alarm id %s: ', response.alarm_id)
else:
LOG.error('Failed to %s Aodh Alarm \n%s', event_type, str(data))
LOG.error('Failed to %s Aodh Alarm \n%s', event_type, data)
def _create_aodh_alarm(self, alarm, state):
alarm_request = _alarm_request(alarm, state)
try:
LOG.info('Aodh Alarm - Activate: ' + str(alarm_request))
LOG.info('Aodh Alarm - Activate: ' + alarm_request)
return self.client.alarm.create(alarm_request)
except Exception:
LOG.exception('Failed to activate Aodh Alarm. Got Exception.')

View File

@ -51,7 +51,7 @@ class NovaNotifier(NotifierBase):
if action:
action(data.get(VProps.ID), is_down)
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))
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
try:
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)
LOG.info('RESPONSE %s', str(response))
except Exception:

View File

@ -67,17 +67,15 @@ class Webhook(NotifierBase):
def __init__(self, conf):
super(Webhook, self).__init__(conf)
self.conf = conf
self._db = storage.get_connection_from_config(self.conf)
self.max_retries = self.conf.webhook.max_retries
self.default_headers = {'content-type': 'application/json'}
def process_event(self, data, event_type):
if event_type == NotifierEventTypes.ACTIVATE_ALARM_EVENT \
or event_type == NotifierEventTypes.DEACTIVATE_ALARM_EVENT:
if event_type in NotifierEventTypes.ALARMS:
LOG.info('Webhook notifier started processing %s', str(data))
LOG.info('Webhook notifier started processing %s', data)
webhooks = self._load_webhooks()
@ -89,32 +87,31 @@ class Webhook(NotifierBase):
data = self._filter_fields(data)
LOG.debug('webhook_filter: %s, filtered data: %s',
str(webhook_filters), str(data))
webhook_filters, data)
if self._check_against_filter(webhook_filters, data)\
and self._check_correct_tenant(webhook, data):
LOG.info('Going to post data to webhook %s',
str(webhook))
LOG.info('Going to post data to webhook %s', webhook)
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):
try:
webhook_data = {'notification': event_type, 'payload': data}
webhook_headers = self._get_webhook_headers(webhook)
session = requests.Session()
session.mount(str(webhook[URL]),
session.mount(webhook[URL],
requests.adapters.HTTPAdapter(
max_retries=self.max_retries))
resp = session.post(str(webhook[URL]),
data=jsonutils.dumps(webhook_data),
headers=webhook_headers)
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)
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):
db_webhooks = self._db.webhooks.query()

View 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),
]

View 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')

View File

@ -29,6 +29,7 @@ import vitrage.machine_learning.plugins.jaccard_correlation
import vitrage.notifier
import vitrage.notifier.plugins.snmp
import vitrage.notifier.plugins.webhook
import vitrage.notifier.plugins.zaqar
import vitrage.os_clients
import vitrage.persistency
import vitrage.rpc
@ -61,6 +62,7 @@ def list_opts():
('snmp', vitrage.notifier.plugins.snmp.OPTS),
('webhook', vitrage.notifier.plugins.webhook.OPTS),
('snmp_parsing', vitrage.snmp_parsing.OPTS),
('zaqar', vitrage.notifier.plugins.zaqar.OPTS),
('DEFAULT', itertools.chain(
vitrage.os_clients.OPTS,
vitrage.rpc.OPTS,

View File

@ -192,3 +192,16 @@ def mistral_client(conf):
return client
except 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.')