akhil abb315961e Enable keystone authentication with webhook notification
This commit adds functionality of sending webhook notifications to
various projects that require keystone authentications. For which user
need to set auth credentials in conf under keystone header.
By default it is disabled, which can be enabled in conf.

Change-Id: I3e773af8c3ebe0cf1d57e8fa1351b1e725a9cfa0
Partially-Implements: blueprint add-monasca-push-driver
Story: 2003105
Task: 23220
2018-08-07 22:22:15 +05:30

169 lines
6.4 KiB
Python

# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
# Copyright 2016 FUJITSU LIMITED
# 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 monascastatsd
from keystoneauth1 import exceptions as kaexception
from keystoneauth1 import loading as kaloading
from oslo_config import cfg
from oslo_log import log
import six
from monasca_notification.common.repositories import exceptions
from monasca_notification.notification import Notification
LOG = log.getLogger(__name__)
CONF = cfg.CONF
NOTIFICATION_DIMENSIONS = {'service': 'monitoring',
'component': 'monasca-notification'}
def get_db_repo():
repo_driver = CONF.database.repo_driver
LOG.debug('Enabling the %s RDB repository', repo_driver)
return repo_driver(CONF)
def construct_notification_object(db_repo, notification_json):
try:
notification = Notification(notification_json['id'],
notification_json['type'],
notification_json['name'],
notification_json['address'],
notification_json['period'],
notification_json['retry_count'],
notification_json['raw_alarm'])
# Grab notification method from database to see if it was changed
stored_notification = grab_stored_notification_method(db_repo, notification.id)
# Notification method was deleted
if stored_notification is None:
LOG.debug("Notification method {0} was deleted from database. "
"Will stop sending.".format(notification.id))
return None
# Update notification method with most up to date values
else:
notification.name = stored_notification[0]
notification.type = stored_notification[1]
notification.address = stored_notification[2]
notification.period = stored_notification[3]
return notification
except exceptions.DatabaseException:
LOG.warn("Error querying mysql for notification method. "
"Using currently cached method.")
return notification
except Exception as e:
LOG.warn("Error when attempting to construct notification {0}".format(e))
return None
def grab_stored_notification_method(db_repo, notification_id):
try:
stored_notification = db_repo.get_notification(notification_id)
except exceptions.DatabaseException:
LOG.debug('Database Error. Attempting reconnect')
stored_notification = db_repo.get_notification(notification_id)
return stored_notification
def get_statsd_client(dimensions=None):
local_dims = dimensions.copy() if dimensions else {}
local_dims.update(NOTIFICATION_DIMENSIONS)
if CONF.statsd.enable:
LOG.debug("Establishing connection with statsd on {0}:{1}"
.format(CONF.statsd.host, CONF.statsd.port))
client = monascastatsd.Client(name='monasca',
host=CONF.statsd.host,
port=CONF.statsd.port,
dimensions=local_dims)
else:
LOG.warn("StatsD monitoring disabled. Overriding monascastatsd.Client to use it offline")
client = OfflineClient(name='monasca',
host=CONF.statsd.host,
port=CONF.statsd.port,
dimensions=local_dims)
return client
class OfflineClient(monascastatsd.Client):
def _set_connection(self, connection, host, port):
if connection is None:
self.connection = OfflineConnection(host=host,
port=port,
max_buffer_size=self._max_buffer_size)
else:
self.connection = connection
class OfflineConnection(monascastatsd.Connection):
def __init__(self, host='localhost', port=8125, max_buffer_size=50):
"""Initialize an Offline Connection object.
>>> monascastatsd = MonascaStatsd()
:name: the name for this client. Everything sent by this client
will be prefixed by name
:param host: the host of the MonascaStatsd server.
:param port: the port of the MonascaStatsd server.
:param max_buffer_size: Maximum number of metric to buffer before
sending to the server if sending metrics in batch
"""
self.max_buffer_size = max_buffer_size
self._send = self._send_to_server
self.connect(host, port)
self.encoding = 'utf-8'
def connect(self, host, port):
"""Avoid connecting to the monascastatsd server.
"""
pass
def _send_to_server(self, packet):
pass
def get_keystone_session():
auth_details = {}
auth_details['auth_url'] = CONF.keystone.auth_url
auth_details['username'] = CONF.keystone.username
auth_details['password'] = CONF.keystone.password
auth_details['project_name'] = CONF.keystone.project_name
auth_details['user_domain_name'] = CONF.keystone.user_domain_name
auth_details['project_domain_name'] = CONF.keystone.project_domain_name
loader = kaloading.get_plugin_loader('password')
auth_plugin = loader.load_from_options(**auth_details)
session = kaloading.session.Session().load_from_options(
auth=auth_plugin)
return session
def get_auth_token():
error_message = 'Keystone request failed: {}'
try:
session = get_keystone_session()
auth_token = session.get_token()
return auth_token
except (kaexception.Unauthorized, kaexception.DiscoveryFailure) as e:
LOG.exception(error_message.format(six.text_type(e)))
raise
except Exception as e:
LOG.exception(error_message.format(six.text_type(e)))
raise