From cbf1b324989a8fff6dc1ca82de1aa3674399d272 Mon Sep 17 00:00:00 2001 From: Eyal Date: Thu, 10 Jan 2019 15:23:19 +0200 Subject: [PATCH] Add a new zaqar notifier also did some minor refactorings to the other notifiers Story: 2002681 Task: 22499 Change-Id: I06dfae2b67d1966eed472123f5bb6627d4cb19d0 --- doc/source/contributor/configuration.rst | 1 + doc/source/contributor/zaqar_notifier.rst | 21 ++++++++++ lower-constraints.txt | 1 + .../add_zaqar_notifier-63de714384091ce5.yaml | 3 ++ requirements.txt | 1 + vitrage/common/constants.py | 5 ++- vitrage/notifier/plugins/__init__.py | 15 ------- .../notifier/plugins/aodh/aodh_notifier.py | 4 +- .../notifier/plugins/nova/nova_notifier.py | 4 +- vitrage/notifier/plugins/webhook/webhook.py | 19 ++++----- vitrage/notifier/plugins/zaqar/__init__.py | 28 +++++++++++++ .../notifier/plugins/zaqar/zaqar_notifier.py | 40 +++++++++++++++++++ vitrage/opts.py | 2 + vitrage/os_clients.py | 13 ++++++ 14 files changed, 125 insertions(+), 32 deletions(-) create mode 100644 doc/source/contributor/zaqar_notifier.rst create mode 100644 releasenotes/notes/add_zaqar_notifier-63de714384091ce5.yaml create mode 100644 vitrage/notifier/plugins/zaqar/__init__.py create mode 100644 vitrage/notifier/plugins/zaqar/zaqar_notifier.py diff --git a/doc/source/contributor/configuration.rst b/doc/source/contributor/configuration.rst index 2e5d2daaf..de99b4d1f 100644 --- a/doc/source/contributor/configuration.rst +++ b/doc/source/contributor/configuration.rst @@ -38,6 +38,7 @@ Notifiers notifier-snmp-plugin mistral-config notifier-webhook-plugin + zaqar_notifier Machine_Learning diff --git a/doc/source/contributor/zaqar_notifier.rst b/doc/source/contributor/zaqar_notifier.rst new file mode 100644 index 000000000..be945c5ae --- /dev/null +++ b/doc/source/contributor/zaqar_notifier.rst @@ -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 = + diff --git a/lower-constraints.txt b/lower-constraints.txt index d124e30b7..cce90f9dd 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -141,3 +141,4 @@ Werkzeug==0.14.1 wrapt==1.10.11 futures==3.0.0 docutils==0.11 +python-zaqarclient==1.2.0 diff --git a/releasenotes/notes/add_zaqar_notifier-63de714384091ce5.yaml b/releasenotes/notes/add_zaqar_notifier-63de714384091ce5.yaml new file mode 100644 index 000000000..9712ca236 --- /dev/null +++ b/releasenotes/notes/add_zaqar_notifier-63de714384091ce5.yaml @@ -0,0 +1,3 @@ +features: + - A new ``zaqar notifier`` was added, in order to send alrmas from Vitrage + to zaqar messaging framework. \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index bee35a9b4..457d9b157 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/vitrage/common/constants.py b/vitrage/common/constants.py index 3247e9403..61e6728cc 100644 --- a/vitrage/common/constants.py +++ b/vitrage/common/constants.py @@ -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): diff --git a/vitrage/notifier/plugins/__init__.py b/vitrage/notifier/plugins/__init__.py index 70097d786..e69de29bb 100644 --- a/vitrage/notifier/plugins/__init__.py +++ b/vitrage/notifier/plugins/__init__.py @@ -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 diff --git a/vitrage/notifier/plugins/aodh/aodh_notifier.py b/vitrage/notifier/plugins/aodh/aodh_notifier.py index 05d38028a..a2afa8d7d 100644 --- a/vitrage/notifier/plugins/aodh/aodh_notifier.py +++ b/vitrage/notifier/plugins/aodh/aodh_notifier.py @@ -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.') diff --git a/vitrage/notifier/plugins/nova/nova_notifier.py b/vitrage/notifier/plugins/nova/nova_notifier.py index 17f2070de..e37d1ab84 100644 --- a/vitrage/notifier/plugins/nova/nova_notifier.py +++ b/vitrage/notifier/plugins/nova/nova_notifier.py @@ -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: diff --git a/vitrage/notifier/plugins/webhook/webhook.py b/vitrage/notifier/plugins/webhook/webhook.py index 0561b727c..51ea3151d 100644 --- a/vitrage/notifier/plugins/webhook/webhook.py +++ b/vitrage/notifier/plugins/webhook/webhook.py @@ -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() diff --git a/vitrage/notifier/plugins/zaqar/__init__.py b/vitrage/notifier/plugins/zaqar/__init__.py new file mode 100644 index 000000000..f1f469b6f --- /dev/null +++ b/vitrage/notifier/plugins/zaqar/__init__.py @@ -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), +] diff --git a/vitrage/notifier/plugins/zaqar/zaqar_notifier.py b/vitrage/notifier/plugins/zaqar/zaqar_notifier.py new file mode 100644 index 000000000..c44a4529b --- /dev/null +++ b/vitrage/notifier/plugins/zaqar/zaqar_notifier.py @@ -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') diff --git a/vitrage/opts.py b/vitrage/opts.py index 5a57b19a1..1e33a68c1 100644 --- a/vitrage/opts.py +++ b/vitrage/opts.py @@ -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, diff --git a/vitrage/os_clients.py b/vitrage/os_clients.py index 2405ef13b..4f739d4f2 100644 --- a/vitrage/os_clients.py +++ b/vitrage/os_clients.py @@ -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.')