Add HipChat and Slack Notification types
This patch 1. Supports for loading new notification types as plugins. 2) Adds new plugins for HipChat and Slack 3) Insert Notification types during startup Partially-implements: blueprint notification-engine-plugin Change-Id: I246ced3fe22a9797a3c8384f7bda166797cfac3a
This commit is contained in:
parent
c74ea85c71
commit
be6fb21e19
@ -1,5 +1,5 @@
|
||||
# Copyright 2015 FUJITSU LIMITED
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
@ -21,3 +21,5 @@ class BaseRepo(object):
|
||||
self._find_alarm_state_sql = """SELECT state
|
||||
FROM alarm
|
||||
WHERE alarm.id = %s"""
|
||||
self._insert_notification_types_sql = """INSERT INTO notification_method_type (name) VALUES ( %s)"""
|
||||
self._find_all_notification_types_sql = """SELECT name from notification_method_type """
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Copyright 2015 FUJITSU LIMITED
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
@ -85,4 +85,30 @@ class MysqlRepo(BaseRepo):
|
||||
except pymysql.Error as e:
|
||||
self._mysql = None
|
||||
log.exception("Couldn't fetch the current alarm state %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
||||
def fetch_notification_method_types(self):
|
||||
try:
|
||||
if self._mysql is None:
|
||||
self._connect_to_mysql()
|
||||
cur = self._mysql.cursor()
|
||||
cur.execute(self._find_all_notification_types_sql)
|
||||
|
||||
for row in cur:
|
||||
yield (row[0])
|
||||
except pymysql.Error as e:
|
||||
self._mysql = None
|
||||
log.exception("Couldn't fetch notification types %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
||||
def insert_notification_method_types(self, notification_types):
|
||||
try:
|
||||
if self._mysql is None:
|
||||
self._connect_to_mysql()
|
||||
cur = self._mysql.cursor()
|
||||
cur.executemany(self._insert_notification_types_sql, notification_types)
|
||||
|
||||
except pymysql.Error as e:
|
||||
self._mysql = None
|
||||
log.exception("Couldn't insert notification types %s", e)
|
||||
raise exc.DatabaseException(e)
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 Fujitsu Technology Solutions
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -44,3 +44,8 @@ def create_notification_method_model(metadata=None):
|
||||
Column('period', int),
|
||||
Column('created_at', DateTime, default=lambda: datetime.utcnow()),
|
||||
Column('updated_at', DateTime, onupdate=lambda: datetime.utcnow()))
|
||||
|
||||
|
||||
def create_notification_method_type_model(metadata=None):
|
||||
return Table('notification_method_type', metadata,
|
||||
Column('name', String(20), primary_key=True))
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Copyright 2015 FUJITSU LIMITED
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
@ -30,6 +30,7 @@ class OrmRepo(object):
|
||||
|
||||
aa = models.create_alarm_action_model(metadata).alias('aa')
|
||||
nm = models.create_notification_method_model(metadata).alias('nm')
|
||||
nmt = models.create_notification_method_type_model(metadata).alias('nmt')
|
||||
|
||||
self._orm_query = select([nm.c.name, nm.c.type, nm.c.address, nm.c.periodic_interval])\
|
||||
.select_from(aa.join(nm, aa.c.action_id == nm.c.id))\
|
||||
@ -37,6 +38,8 @@ class OrmRepo(object):
|
||||
and_(aa.c.alarm_definition_id == bindparam('alarm_definition_id'),
|
||||
aa.c.alarm_state == bindparam('alarm_state')))
|
||||
|
||||
self._orm_nmt_query = select([nmt.c.name])
|
||||
|
||||
self._orm = None
|
||||
|
||||
def fetch_notification(self, alarm):
|
||||
@ -51,3 +54,25 @@ class OrmRepo(object):
|
||||
except DatabaseError as e:
|
||||
log.exception("Couldn't fetch alarms actions %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
||||
def fetch_notification_method_types(self):
|
||||
try:
|
||||
with self._orm_engine.connect() as conn:
|
||||
log.debug('Orm query {%s}', str(self._orm_nmt_query))
|
||||
notification_method_types = conn.execute(self._orm_nmt_query).fetchall()
|
||||
|
||||
return [row[0] for row in notification_method_types]
|
||||
except DatabaseError as e:
|
||||
log.exception("Couldn't fetch notification method types %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
||||
def insert_notification_method_types(self, notification_types):
|
||||
try:
|
||||
with self._orm_engine.connect() as conn:
|
||||
for notification_type in notification_types:
|
||||
conn.execute(self.nmt.insert(), notification_type)
|
||||
|
||||
except DatabaseError as e:
|
||||
self._mysql = None
|
||||
log.exception("Couldn't insert notification types %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Copyright 2015 FUJITSU LIMITED
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
@ -59,3 +59,29 @@ class PostgresqlRepo(BaseRepo):
|
||||
except psycopg2.Error as e:
|
||||
log.exception("Couldn't fetch current alarm state %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
||||
def fetch_notification_method_types(self):
|
||||
try:
|
||||
if self._pgsql is None:
|
||||
self._connect_to_pgsql()
|
||||
cur = self._pgsql.cursor()
|
||||
cur.execute(self._find_all_notification_types_sql)
|
||||
|
||||
for row in cur:
|
||||
yield (row[0])
|
||||
except psycopg2.Error as e:
|
||||
self._mysql = None
|
||||
log.exception("Couldn't fetch notification types %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
||||
def insert_notification_method_types(self, notification_types):
|
||||
try:
|
||||
if self._pgsql is None:
|
||||
self._connect_to_pgsql()
|
||||
cur = self._pgsql.cursor()
|
||||
cur.executemany(self._insert_notification_types_sql, notification_types)
|
||||
|
||||
except psycopg2.Error as e:
|
||||
self._mysql = None
|
||||
log.exception("Couldn't insert notification types %s", e)
|
||||
raise exc.DatabaseException(e)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -41,7 +41,7 @@ class NotificationEngine(object):
|
||||
self._producer = KafkaProducer(config['kafka']['url'])
|
||||
self._alarm_ttl = config['processors']['alarm']['ttl']
|
||||
self._alarms = AlarmProcessor(self._alarm_ttl, config)
|
||||
self._notifier = NotificationProcessor(config['notification_types'])
|
||||
self._notifier = NotificationProcessor(config)
|
||||
|
||||
self._config = config
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -45,7 +45,7 @@ class PeriodicEngine(object):
|
||||
|
||||
self._producer = KafkaProducer(config['kafka']['url'])
|
||||
|
||||
self._notifier = NotificationProcessor(config['notification_types'])
|
||||
self._notifier = NotificationProcessor(config)
|
||||
self._db_repo = get_db_repo(config)
|
||||
|
||||
def _keep_sending(self, alarm_id, original_state):
|
||||
|
0
monasca_notification/plugins/__init__.py
Normal file
0
monasca_notification/plugins/__init__.py
Normal file
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -17,7 +17,7 @@ import email.mime.text
|
||||
import smtplib
|
||||
import time
|
||||
|
||||
from abstract_notifier import AbstractNotifier
|
||||
from monasca_notification.plugins.abstract_notifier import AbstractNotifier
|
||||
|
||||
EMAIL_SINGLE_HOST_BASE = u'''On host "{hostname}" for target "{target_host}" {message}
|
||||
|
112
monasca_notification/plugins/hipchat_notifier.py
Normal file
112
monasca_notification/plugins/hipchat_notifier.py
Normal file
@ -0,0 +1,112 @@
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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 json
|
||||
import requests
|
||||
import urlparse
|
||||
|
||||
from monasca_notification.plugins.abstract_notifier import AbstractNotifier
|
||||
|
||||
"""
|
||||
notification.address = https://hipchat.hpcloud.net/v2/room/<room_id>/notification?auth_token=432432
|
||||
|
||||
How to get access token?
|
||||
1) Login to Hipchat with the user account which is used for notification
|
||||
2) Go to this page. https://hipchat.hpcloud.net/account/api (Replace your hipchat server name)
|
||||
3) You can see option to "Create token". Use the capability "SendNotification"
|
||||
|
||||
How to get the Room ID?
|
||||
1) Login to Hipchat with the user account which is used for notification
|
||||
2) Go to this page. https://hipchat.hpcloud.net/account/api (Replace your hipchat server name)
|
||||
3) Click on the Rooms tab
|
||||
4) Click on any Room of your choice.
|
||||
5) Room ID is the API ID field
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class HipChatNotifier(AbstractNotifier):
|
||||
def __init__(self, log):
|
||||
self._log = log
|
||||
|
||||
def config(self, config_dict):
|
||||
self._config = {'timeout': 5}
|
||||
self._config.update(config_dict)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "hipchat"
|
||||
|
||||
@property
|
||||
def statsd_name(self):
|
||||
return 'sent_hipchat_count'
|
||||
|
||||
def _build_hipchat_message(self, notification):
|
||||
"""Builds hipchat message body
|
||||
"""
|
||||
body = {'alarm_id': notification.alarm_id,
|
||||
'alarm_definition_id': notification.raw_alarm['alarmDefinitionId'],
|
||||
'alarm_name': notification.alarm_name,
|
||||
'alarm_description': notification.raw_alarm['alarmDescription'],
|
||||
'alarm_timestamp': notification.alarm_timestamp,
|
||||
'state': notification.state,
|
||||
'old_state': notification.raw_alarm['oldState'],
|
||||
'message': notification.message,
|
||||
'tenant_id': notification.tenant_id,
|
||||
'metrics': notification.metrics}
|
||||
|
||||
hipchat_request = {}
|
||||
hipchat_request['color'] = 'green'
|
||||
hipchat_request['message_format'] = 'text'
|
||||
hipchat_request['message'] = json.dumps(body, indent=3)
|
||||
|
||||
return hipchat_request
|
||||
|
||||
def send_notification(self, notification):
|
||||
"""Send the notification via hipchat
|
||||
Posts on the given url
|
||||
"""
|
||||
|
||||
hipchat_message = self._build_hipchat_message(notification)
|
||||
parsed_url = urlparse.urlsplit(notification.address)
|
||||
|
||||
query_params = urlparse.parse_qs(parsed_url.query)
|
||||
# URL without query params
|
||||
url = urlparse.urljoin(notification.address, urlparse.urlparse(notification.address).path)
|
||||
|
||||
# Default option is to do cert verification
|
||||
verify = self._config.get('insecure', False)
|
||||
# If ca_certs is specified, do cert validation and ignore insecure flag
|
||||
if (self._config.get("ca_certs")):
|
||||
verify = self._config.get("ca_certs")
|
||||
|
||||
try:
|
||||
# Posting on the given URL
|
||||
result = requests.post(url=url,
|
||||
data=hipchat_message,
|
||||
verify=verify,
|
||||
params=query_params,
|
||||
timeout=self._config['timeout'])
|
||||
|
||||
if result.status_code in range(200, 300):
|
||||
self._log.info("Notification successfully posted.")
|
||||
return True
|
||||
else:
|
||||
msg = "Received an HTTP code {} when trying to send to hipchat on URL {} with response {} ."
|
||||
self._log.error(msg.format(result.status_code, url, result.text))
|
||||
return False
|
||||
except Exception:
|
||||
self._log.exception("Error trying to send to hipchat on URL {}".format(url))
|
||||
return False
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,8 @@
|
||||
import json
|
||||
import requests
|
||||
|
||||
from abstract_notifier import AbstractNotifier
|
||||
from monasca_notification.plugins.abstract_notifier import AbstractNotifier
|
||||
|
||||
|
||||
VALID_HTTP_CODES = [200, 201, 204]
|
||||
|
116
monasca_notification/plugins/slack_notifier.py
Normal file
116
monasca_notification/plugins/slack_notifier.py
Normal file
@ -0,0 +1,116 @@
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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 json
|
||||
import requests
|
||||
import urlparse
|
||||
|
||||
from monasca_notification.plugins.abstract_notifier import AbstractNotifier
|
||||
|
||||
"""
|
||||
notification.address = https://slack.com/api/chat.postMessage?token=token&channel=#channel"
|
||||
|
||||
Slack documentation about tokens:
|
||||
1. Login to your slack account via browser and check the following pages
|
||||
a. https://api.slack.com/docs/oauth-test-tokens
|
||||
b. https://api.slack.com/tokens
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class SlackNotifier(AbstractNotifier):
|
||||
def __init__(self, log):
|
||||
self._log = log
|
||||
|
||||
def config(self, config_dict):
|
||||
self._config = {'timeout': 5}
|
||||
self._config.update(config_dict)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "slack"
|
||||
|
||||
@property
|
||||
def statsd_name(self):
|
||||
return 'sent_slack_count'
|
||||
|
||||
def _build_slack_message(self, notification):
|
||||
"""Builds slack message body
|
||||
"""
|
||||
body = {'alarm_id': notification.alarm_id,
|
||||
'alarm_definition_id': notification.raw_alarm['alarmDefinitionId'],
|
||||
'alarm_name': notification.alarm_name,
|
||||
'alarm_description': notification.raw_alarm['alarmDescription'],
|
||||
'alarm_timestamp': notification.alarm_timestamp,
|
||||
'state': notification.state,
|
||||
'old_state': notification.raw_alarm['oldState'],
|
||||
'message': notification.message,
|
||||
'tenant_id': notification.tenant_id,
|
||||
'metrics': notification.metrics}
|
||||
|
||||
slack_request = {}
|
||||
slack_request['text'] = json.dumps(body, indent=3)
|
||||
|
||||
return slack_request
|
||||
|
||||
def send_notification(self, notification):
|
||||
"""Send the notification via slack
|
||||
Posts on the given url
|
||||
"""
|
||||
|
||||
slack_message = self._build_slack_message(notification)
|
||||
|
||||
address = notification.address
|
||||
# "#" is reserved character and replace it with ascii equivalent
|
||||
# Slack room has "#" as first character
|
||||
address = address.replace("#", "%23")
|
||||
|
||||
parsed_url = urlparse.urlsplit(address)
|
||||
query_params = urlparse.parse_qs(parsed_url.query)
|
||||
# URL without query params
|
||||
url = urlparse.urljoin(address, urlparse.urlparse(address).path)
|
||||
|
||||
# Default option is to do cert verification
|
||||
verify = self._config.get('insecure', False)
|
||||
# If ca_certs is specified, do cert validation and ignore insecure flag
|
||||
if (self._config.get("ca_certs")):
|
||||
verify = self._config.get("ca_certs")
|
||||
|
||||
try:
|
||||
# Posting on the given URL
|
||||
self._log.debug("Sending to the url {0} , with query_params {1}".format(url, query_params))
|
||||
result = requests.post(url=url,
|
||||
data=slack_message,
|
||||
verify=verify,
|
||||
params=query_params,
|
||||
timeout=self._config['timeout'])
|
||||
|
||||
if result.status_code not in range(200, 300):
|
||||
self._log.error("Received an HTTP code {} when trying to post on URL {}."
|
||||
.format(result.status_code, url))
|
||||
return False
|
||||
|
||||
# Slack returns 200 ok even if the token is invalid. Response has valid error message
|
||||
response = json.loads(result.text)
|
||||
if response.get('ok'):
|
||||
self._log.info("Notification successfully posted.")
|
||||
return True
|
||||
else:
|
||||
self._log.error("Received an error message {} when trying to send to slack on URL {}."
|
||||
.format(response.get("error"), url))
|
||||
return False
|
||||
except Exception:
|
||||
self._log.exception("Error trying to send to slack on URL {}".format(url))
|
||||
return False
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
import json
|
||||
import requests
|
||||
|
||||
from abstract_notifier import AbstractNotifier
|
||||
from monasca_notification.plugins.abstract_notifier import AbstractNotifier
|
||||
|
||||
|
||||
class WebhookNotifier(AbstractNotifier):
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2014-2015 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,6 +16,7 @@
|
||||
import logging
|
||||
import monascastatsd
|
||||
|
||||
from monasca_notification.common.utils import get_db_repo
|
||||
from monasca_notification.processors.base import BaseProcessor
|
||||
from monasca_notification.types import notifiers
|
||||
|
||||
@ -27,7 +28,24 @@ class NotificationProcessor(BaseProcessor):
|
||||
def __init__(self, config):
|
||||
self.statsd = monascastatsd.Client(name='monasca', dimensions=BaseProcessor.dimensions)
|
||||
notifiers.init(self.statsd)
|
||||
notifiers.config(config)
|
||||
notifiers.load_plugins(config['notification_types'])
|
||||
notifiers.config(config['notification_types'])
|
||||
self._db_repo = get_db_repo(config)
|
||||
self.insert_configured_plugins()
|
||||
|
||||
def insert_configured_plugins(self):
|
||||
"""Persists configured plugin types in DB
|
||||
For each notification type configured add it in db, if it is not there
|
||||
"""
|
||||
configured_plugin_types = notifiers.enabled_notifications()
|
||||
|
||||
persisted_plugin_types = self._db_repo.fetch_notification_method_types()
|
||||
remaining_plugin_types = set(configured_plugin_types) - set(persisted_plugin_types)
|
||||
|
||||
if remaining_plugin_types:
|
||||
log.info("New plugins detected: Adding new notification types {} to database"
|
||||
.format(remaining_plugin_types))
|
||||
self._db_repo.insert_notification_method_types(remaining_plugin_types)
|
||||
|
||||
def send(self, notifications):
|
||||
"""Send the notifications
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -47,7 +47,7 @@ class RetryEngine(object):
|
||||
|
||||
self._producer = KafkaProducer(config['kafka']['url'])
|
||||
|
||||
self._notifier = NotificationProcessor(config['notification_types'])
|
||||
self._notifier = NotificationProcessor(config)
|
||||
|
||||
def run(self):
|
||||
for raw_notification in self._consumer:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,10 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
from monasca_notification.types import email_notifier
|
||||
from monasca_notification.types import pagerduty_notifier
|
||||
from monasca_notification.types import webhook_notifier
|
||||
from monasca_common.simport import simport
|
||||
from monasca_notification.plugins import email_notifier
|
||||
from monasca_notification.plugins import pagerduty_notifier
|
||||
from monasca_notification.plugins import webhook_notifier
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -40,10 +41,18 @@ def init(statsd_obj):
|
||||
possible_notifiers.append(pagerduty_notifier.PagerdutyNotifier(log))
|
||||
|
||||
|
||||
def load_plugins(config):
|
||||
for plugin_class in config.get("plugins", []):
|
||||
try:
|
||||
possible_notifiers.append(simport.load(plugin_class)(log))
|
||||
except Exception:
|
||||
log.exception("unable to load the class {0} , ignoring it".format(plugin_class))
|
||||
|
||||
|
||||
def enabled_notifications():
|
||||
results = []
|
||||
for key in configured_notifiers:
|
||||
results.append(key)
|
||||
results.append(key.upper())
|
||||
return results
|
||||
|
||||
|
||||
|
@ -33,6 +33,10 @@ postgresql:
|
||||
host: 127.0.0.1
|
||||
|
||||
notification_types:
|
||||
plugins:
|
||||
- monasca_notification.plugins.hipchat_notifier:HipChatNotifier
|
||||
- monasca_notification.plugins.slack_notifier:SlackNotifier
|
||||
|
||||
email:
|
||||
server: 192.168.10.4
|
||||
port: 25
|
||||
@ -48,6 +52,16 @@ notification_types:
|
||||
timeout: 5
|
||||
url: "https://events.pagerduty.com/generic/2010-04-15/create_event.json"
|
||||
|
||||
hipchat:
|
||||
timeout: 5
|
||||
ca_certs: "/etc/ssl/certs/ca-certificates.crt"
|
||||
insecure: False
|
||||
|
||||
slack:
|
||||
timeout: 5
|
||||
ca_certs: "/etc/ssl/certs/ca-certificates.crt"
|
||||
insecure: False
|
||||
|
||||
processors:
|
||||
alarm:
|
||||
number: 2
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -20,7 +20,7 @@ import time
|
||||
import unittest
|
||||
|
||||
from monasca_notification.notification import Notification
|
||||
from monasca_notification.types import email_notifier
|
||||
from monasca_notification.plugins import email_notifier
|
||||
|
||||
UNICODE_CHAR = unichr(2344)
|
||||
UNICODE_CHAR_ENCODED = UNICODE_CHAR.encode("utf-8")
|
||||
@ -90,7 +90,7 @@ class TestEmail(unittest.TestCase):
|
||||
def _smtbStubException(self, *arg, **kwargs):
|
||||
return smtpStubException(self.trap)
|
||||
|
||||
@mock.patch('monasca_notification.types.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.plugins.email_notifier.smtplib')
|
||||
def notify(self, smtp_stub, metric, mock_smtp):
|
||||
mock_smtp.SMTP = smtp_stub
|
||||
|
||||
@ -185,7 +185,7 @@ class TestEmail(unittest.TestCase):
|
||||
return_value = self.trap.pop(0)
|
||||
self.assertTrue(return_value)
|
||||
|
||||
@mock.patch('monasca_notification.types.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.plugins.email_notifier.smtplib')
|
||||
def test_smtp_sendmail_failed_connection_twice(self, mock_smtp):
|
||||
"""Email that fails on smtp_connect twice
|
||||
"""
|
||||
@ -229,7 +229,7 @@ class TestEmail(unittest.TestCase):
|
||||
self.assertIn("SMTP server disconnected. Will reconnect and retry message.", self.trap)
|
||||
self.assertIn("Unable to connect to email server.", self.trap)
|
||||
|
||||
@mock.patch('monasca_notification.types.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.plugins.email_notifier.smtplib')
|
||||
def test_smtp_sendmail_smtp_None(self, mock_smtp):
|
||||
"""Email that fails on smtp_connect twice
|
||||
"""
|
||||
@ -277,7 +277,7 @@ class TestEmail(unittest.TestCase):
|
||||
.format(self.email_config['server']),
|
||||
self.trap)
|
||||
|
||||
@mock.patch('monasca_notification.types.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.plugins.email_notifier.smtplib')
|
||||
def test_smtp_sendmail_failed_connection_once_then_email(self, mock_smtp):
|
||||
"""Email that fails on smtp_connect once then email
|
||||
"""
|
||||
@ -319,7 +319,7 @@ class TestEmail(unittest.TestCase):
|
||||
self.assertIn("Error sending Email Notification", self.trap)
|
||||
self.assertNotIn("Unable to connect to email server.", self.trap)
|
||||
|
||||
@mock.patch('monasca_notification.types.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.plugins.email_notifier.smtplib')
|
||||
def test_smtp_sendmail_failed_connection_once(self, mock_smtp):
|
||||
"""Email that fails on smtp_connect once
|
||||
"""
|
||||
@ -359,7 +359,7 @@ class TestEmail(unittest.TestCase):
|
||||
self.assertIn("Sent email to %s, notification %s"
|
||||
% (notification.address, notification.to_json()), self.trap)
|
||||
|
||||
@mock.patch('monasca_notification.types.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.plugins.email_notifier.smtplib')
|
||||
def test_smtp_sendmail_failed_exception(self, mock_smtp):
|
||||
"""Email that fails on exception
|
||||
"""
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -47,17 +47,24 @@ class TestNotificationProcessor(unittest.TestCase):
|
||||
'timeout': 60,
|
||||
'from_addr': 'hpcs.mon@hp.com'}
|
||||
|
||||
self.mysql_config = {'ssl': None,
|
||||
'host': 'mysql_host',
|
||||
'port': 'mysql_port',
|
||||
'user': 'mysql_user',
|
||||
'db': 'dbname',
|
||||
'passwd': 'mysql_passwd'}
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Test helper functions
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@mock.patch('pymysql.connect')
|
||||
@mock.patch('monasca_notification.processors.notification_processor.monascastatsd')
|
||||
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.processors.notification_processor.notifiers.log')
|
||||
def _start_processor(self, notifications, mock_log, mock_smtp, mock_statsd):
|
||||
def _start_processor(self, notifications, mock_log, mock_smtp, mock_statsd, mock_pymsql):
|
||||
"""Start the processor with the proper mocks
|
||||
"""
|
||||
# Since the log runs in another thread I can mock it directly, instead change the methods to put to a queue
|
||||
@ -68,6 +75,8 @@ class TestNotificationProcessor(unittest.TestCase):
|
||||
|
||||
config = {}
|
||||
config["email"] = self.email_config
|
||||
config["mysql"] = self.mysql_config
|
||||
config["notification_types"] = {}
|
||||
|
||||
processor = (notification_processor.NotificationProcessor(config))
|
||||
processor.send(notifications)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -153,7 +153,7 @@ class TestInterface(unittest.TestCase):
|
||||
|
||||
self.assertEqual(len(notifications), 3)
|
||||
self.assertEqual(sorted(notifications),
|
||||
["email", "pagerduty", "webhook"])
|
||||
["EMAIL", "PAGERDUTY", "WEBHOOK"])
|
||||
|
||||
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib')
|
||||
@mock.patch('monasca_notification.types.notifiers.log')
|
||||
@ -364,3 +364,30 @@ class TestInterface(unittest.TestCase):
|
||||
self.assertEqual(self.statsd.timer.timer_calls['email_time_start'], 3)
|
||||
self.assertEqual(self.statsd.timer.timer_calls['email_time_stop'], 3)
|
||||
self.assertEqual(self.statsd.counter.counter, 3)
|
||||
|
||||
def test_plugin_load(self):
|
||||
config_dict = {"plugins": ["monasca_notification.plugins.hipchat_notifier:HipChatNotifier",
|
||||
"monasca_notification.plugins.slack_notifier:SlackNotifier"]}
|
||||
|
||||
notifiers.init(self.statsd)
|
||||
notifiers.load_plugins(config_dict)
|
||||
self.assertEqual(len(notifiers.possible_notifiers), 5)
|
||||
|
||||
configured_plugins = ["email", "webhook", "pagerduty", "hipchat", "slack"]
|
||||
for plugin in notifiers.configured_notifiers:
|
||||
self.asssertIn(plugin.type in configured_plugins)
|
||||
|
||||
@mock.patch('monasca_notification.types.notifiers.log')
|
||||
def test_invalid_plugin_load_exception_ignored(self, mock_log):
|
||||
mock_log.exception = self.trap.append
|
||||
config_dict = {"plugins": ["monasca_notification.plugins.hipchat_notifier:UnknownPlugin",
|
||||
"monasca_notification.plugins.slack_notifier:SlackNotifier"]}
|
||||
|
||||
notifiers.init(self.statsd)
|
||||
notifiers.load_plugins(config_dict)
|
||||
self.assertEqual(len(notifiers.possible_notifiers), 4)
|
||||
self.assertEqual(len(self.trap), 1)
|
||||
|
||||
configured_plugins = ["email", "webhook", "pagerduty", "slack"]
|
||||
for plugin in notifiers.configured_notifiers:
|
||||
self.asssertIn(plugin.type in configured_plugins)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -21,7 +21,7 @@ import time
|
||||
import unittest
|
||||
|
||||
from monasca_notification.notification import Notification
|
||||
from monasca_notification.types import pagerduty_notifier
|
||||
from monasca_notification.plugins import pagerduty_notifier
|
||||
|
||||
|
||||
def alarm(metrics):
|
||||
@ -125,7 +125,7 @@ class TestWebhook(unittest.TestCase):
|
||||
self.assertRegexpMatches(log_msg, "key=<ABCDEF>")
|
||||
self.assertRegexpMatches(log_msg, "response=%s" % http_response)
|
||||
|
||||
@mock.patch('monasca_notification.types.pagerduty_notifier.requests')
|
||||
@mock.patch('monasca_notification.plugins.pagerduty_notifier.requests')
|
||||
def notify(self, http_func, mock_requests):
|
||||
mock_log = mock.MagicMock()
|
||||
mock_log.warn = self.trap.put
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -20,7 +20,7 @@ import requests
|
||||
import unittest
|
||||
|
||||
from monasca_notification.notification import Notification
|
||||
from monasca_notification.types import webhook_notifier
|
||||
from monasca_notification.plugins import webhook_notifier
|
||||
|
||||
|
||||
def alarm(metrics):
|
||||
@ -67,7 +67,7 @@ class TestWebhook(unittest.TestCase):
|
||||
self.trap.put("timeout %s" % kwargs["timeout"])
|
||||
raise requests.exceptions.Timeout
|
||||
|
||||
@mock.patch('monasca_notification.types.webhook_notifier.requests')
|
||||
@mock.patch('monasca_notification.plugins.webhook_notifier.requests')
|
||||
def notify(self, http_func, mock_requests):
|
||||
mock_log = mock.MagicMock()
|
||||
mock_log.warn = self.trap.put
|
||||
|
Loading…
Reference in New Issue
Block a user