From: Helena McGough Date: Wed, 23 Aug 2017 10:11:42 +0000 (+0000) Subject: Openstack-Aodh plugin X-Git-Tag: v4.0.0~100 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=f358b4fdd006b427e5b653d467c29ae37a47406e;p=osm%2FMON.git Openstack-Aodh plugin - Initial Aodh plugin work for MON Change-Id: I9525f37871390609f6a02e7acb87f62e643ee615 Signed-off-by: Helena McGough --- diff --git a/plugins/OpenStack/Aodh/__init__.py b/plugins/OpenStack/Aodh/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugins/OpenStack/Aodh/alarming.py b/plugins/OpenStack/Aodh/alarming.py new file mode 100644 index 0000000..3ae31ba --- /dev/null +++ b/plugins/OpenStack/Aodh/alarming.py @@ -0,0 +1,62 @@ +"""Send alarm info from Aodh to SO via MON""" + +import json +from plugins.Openstack.Aodh.aodh_common import Aodh_Common + + +class Alarming(object): + """Receives alarm info from Aodh.""" + + def __init__(self): + """Create the aodh_receiver instance.""" + self._aodh_common = Aodh_Common() + + def alarming(self): + """Receive payload from Aodh.""" + auth_token = self._aodh_common._authenticate() + endpoint = self._aodh_common.get_endpoint() + + alarm_list = self._get_alarm_list(endpoint, auth_token) + # Confirm communication with Aodh by listing alarms + print("Alarm List ", alarm_list.text) + + alarm_id = self._create_alarm(endpoint, auth_token) + print(alarm_id) + +# alarm_info = self._get_alarm_info(endpoint, +# auth_token, "372af0e2-5c36-4e4d-8ce9-ca92d97d07d0") +# print("Alarm info", alarm_info.text) + return + + def _get_alarm_list(self, endpoint, auth_token): + """Get a list of alarms that exist in Aodh.""" + url = "{}/v2/alarms/".format(endpoint) + + alarm_list = self._aodh_common._perform_request(url, auth_token, + req_type="get") + return alarm_list + + def _get_alarm_info(self, endpoint, auth_token, alarmID): + """Get information about a specific alarm from Aodh.""" + url = "{}/v2/alarms/%s".format(endpoint) % (alarmID) + + alarm_details = self._aodh_common._perform_request(url, auth_token, + req_type="get") + return alarm_details + + def _create_alarm(self, endpoint, auth_token): + """Get a list of alarms that exist in Aodh.""" + url = "{}/v2/alarms/".format(endpoint) + + rule = {'event_type': "threshold",} + payload = json.dumps({'state': 'alarm', + 'name': 'my_alarm', + 'severity': 'moderate', + 'type': 'event', + 'event_rule': rule,}) + + new_alarm = self._aodh_common._perform_request(url, auth_token, + req_type="post", payload=payload) + alarm_id =json.loads(new_alarm.text)['alarm_id'] + return alarm_id + diff --git a/plugins/OpenStack/Aodh/aodh_common.py b/plugins/OpenStack/Aodh/aodh_common.py new file mode 100644 index 0000000..28e44fc --- /dev/null +++ b/plugins/OpenStack/Aodh/aodh_common.py @@ -0,0 +1,82 @@ +"""Common methods for the Aodh Sender/Receiver.""" + +import threading +import os +import requests + +from keystoneauth1.identity import v3 +from keystoneauth1.identity.v3 import AuthMethod +from keystoneauth1 import session +from keystoneclient.v3 import client +from keystoneclient.service_catalog import ServiceCatalog + +from plugins.Openstack.settings import Config + + +class Aodh_Common(object): + """Common calls for Aodh Sender/Receiver.""" + + def __init__(self): + """Create the common instance.""" + self._auth_token = None + self._endpoint = None + self._ks = None + + def _authenticate(self): + """Authenticate and/or renew the authentication token""" + + if self._auth_token is not None: + return self._auth_token + + try: + cfg = Config.instance() + self._ks = client.Client(auth_url=cfg.OS_AUTH_URL, + username=cfg.OS_USERNAME, + password=cfg.OS_PASSWORD, + tenant_name=cfg.OS_TENANT_NAME) + self._auth_token = self._ks.auth_token + except Exception as exc: + + # TODO: Log errors + self._auth_token = None + + return self._auth_token + + def get_endpoint(self): + endpoint = self._ks.service_catalog.url_for( + service_type='alarming', + endpoint_type='internalURL', + region_name='RegionOne') + return endpoint + + @classmethod + def _perform_request(cls, url, auth_token, req_type="get", payload=None): + """Perform the POST/PUT/GET/DELETE request.""" + + # request headers + headers = {'X-Auth-Token': auth_token, + 'Content-type': 'application/json'} + # perform request and return its result + try: + if req_type == "put": + response = requests.put( + url, data=payload, headers=headers, + timeout=1) + elif req_type == "post": + response = requests.post( + url, data=payload, headers=headers, + timeout=1) + elif req_type == "get": + response = requests.get( + url, headers=headers, timeout=1) + elif req_type == "delete": + response = requests.delete( + url, headers=headers, timeout=1) + else: + print("Invalid request type") + + except Exception as e: + # Log info later + print("Exception thrown on request", e) + + return response diff --git a/plugins/OpenStack/Aodh/plugin_instance.py b/plugins/OpenStack/Aodh/plugin_instance.py new file mode 100644 index 0000000..8096f3f --- /dev/null +++ b/plugins/OpenStack/Aodh/plugin_instance.py @@ -0,0 +1,38 @@ +"""Aodh plugin for the OSM monitoring module.""" + +import sys +import logging + +path = "/home/stack/MON" +if path not in sys.path: + sys.path.append(path) + +from plugins.Openstack.Aodh.alarming import Alarming +from plugins.Openstack.settings import Config + + +def register_plugin(): + """Register the plugin.""" + config = Config.instance() + instance = Plugin(config=config) + instance.config() + instance.alarm() + + +class Plugin(object): + """Aodh plugin for OSM MON.""" + + def __init__(self, config): + """Plugin instance.""" + self._config = config + self._alarm = Alarming() + + def config(self): + """Configure plugin.""" + self._config.read_environ() + + def alarm(self): + """Allow alarm info to be received from Aodh.""" + self._alarm.alarming() + +register_plugin() diff --git a/plugins/OpenStack/__init__.py b/plugins/OpenStack/__init__.py new file mode 100644 index 0000000..805dce3 Binary files /dev/null and b/plugins/OpenStack/__init__.py differ diff --git a/plugins/OpenStack/settings.py b/plugins/OpenStack/settings.py new file mode 100644 index 0000000..4dacef9 --- /dev/null +++ b/plugins/OpenStack/settings.py @@ -0,0 +1,63 @@ +"""Configurations for the Aodh plugin.""" + +from __future__ import unicode_literals + +from plugins.Openstack.singleton import Singleton + +from collections import namedtuple +import six +import os + + +class BadConfigError(Exception): + """Configuration exception""" + pass + + +class CfgParam(namedtuple('CfgParam', ['key', 'default', 'data_type'])): + """Configuration parameter definition""" + + def value(self, data): + """Convert a string to the parameter type""" + + try: + return self.data_type(data) + except (ValueError, TypeError) as exc: + raise BadConfigError( + 'Invalid value "%s" for configuration parameter "%s"' % ( + data, self.key)) + + +@Singleton +class Config(object): + """Plugin confguration""" + + _configuration = [ + CfgParam('OS_AUTH_URL', None, six.text_type), + CfgParam('OS_IDENTITY_API_VERSION', "3", six.text_type), + CfgParam('OS_USERNAME', "aodh", six.text_type), + CfgParam('OS_PASSWORD', "password", six.text_type), + CfgParam('OS_TENANT_NAME', "service", six.text_type), + ] + + _config_dict = {cfg.key: cfg for cfg in _configuration} + _config_keys = _config_dict.keys() + + def __init__(self): + """Set the default values""" + for cfg in self._configuration: + setattr(self, cfg.key, cfg.default) + + def read_environ(self): + """Check the appropriate environment variables and update defaults.""" + + for key in self._config_keys: + if (key == "OS_IDENTITY_API_VERSION" or key == "OS_PASSWORD"): + val = str(os.environ[key]) + setattr(self, key, val) + elif (key == "OS_AUTH_URL"): + val = str(os.environ[key]) + "/v3" + setattr(self, key, val) + else: + # TODO: Log errors and no config updates required + return diff --git a/plugins/OpenStack/singleton.py b/plugins/OpenStack/singleton.py new file mode 100644 index 0000000..2edc20b --- /dev/null +++ b/plugins/OpenStack/singleton.py @@ -0,0 +1,16 @@ +from __future__ import unicode_literals + + +class Singleton(object): + """Simple singleton class""" + + def __init__(self, decorated): + self._decorated = decorated + + def instance(self): + """Return singleton instance""" + try: + return self._instance + except AttributeError: + self._instance = self._decorated() + return self._instance