From: Benjamin Diaz Date: Thu, 3 May 2018 16:22:11 +0000 (-0300) Subject: Adds vdu_id to message bus models X-Git-Tag: v4.0.0~7 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fv3.1;p=osm%2FMON.git Adds vdu_id to message bus models LB Dockerfile now uses Python3 Removes obsolete parameters from models Refactors and fixes kafka integration tests Refactors deprecated log warnings Adds DATABASE env var to set MON database url Fixes indentation and dependency issues in AWS plugin Use open from io package for Python 2 and 3 compatibility Signed-off-by: Benjamin Diaz Change-Id: I70af22d2fbc2cb1bfd5d9632d9daa80e9d7f6b62 --- diff --git a/docker/Dockerfile b/docker/Dockerfile index ad00631..b07f781 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -25,16 +25,16 @@ FROM ubuntu:16.04 LABEL authors="Guillermo Calvino" RUN apt-get --yes update \ - && apt-get --yes install git python python-pip sudo libmysqlclient-dev \ + && apt-get --yes install git python python-pip python3 python3-pip libmysqlclient-dev libssl-dev libffi-dev \ && pip install pip==9.0.3 COPY requirements.txt /mon/requirements.txt -RUN pip install -r /mon/requirements.txt +RUN pip3 install -r /mon/requirements.txt COPY . /mon -RUN pip install /mon +RUN pip3 install /mon # These ENV must be provided # ENV BROKER_URI=kafka:9092 diff --git a/docker/scripts/runInstall.sh b/docker/scripts/runInstall.sh index 87954ed..611bbe8 100755 --- a/docker/scripts/runInstall.sh +++ b/docker/scripts/runInstall.sh @@ -21,6 +21,6 @@ # contact: bdiaz@whitestack.com or glavado@whitestack.com ## /bin/bash /mon/osm_mon/plugins/vRealiseOps/vROPs_Webservice/install.sh -nohup python /mon/osm_mon/plugins/OpenStack/Aodh/notifier.py & -python /mon/osm_mon/core/message_bus/common_consumer.py +nohup python3 /mon/osm_mon/plugins/OpenStack/Aodh/notifier.py & +python3 /mon/osm_mon/core/message_bus/common_consumer.py diff --git a/osm_mon/core/auth.py b/osm_mon/core/auth.py index 3a88a50..bb6dbba 100644 --- a/osm_mon/core/auth.py +++ b/osm_mon/core/auth.py @@ -47,8 +47,6 @@ class AuthManager: def get_credentials(self, vim_uuid): creds = self.database_manager.get_credentials(vim_uuid) - if creds.config is None: - creds.config = {} return creds def delete_auth_credentials(self, creds_dict): diff --git a/osm_mon/core/database.py b/osm_mon/core/database.py index eab4bed..857e8e5 100644 --- a/osm_mon/core/database.py +++ b/osm_mon/core/database.py @@ -25,14 +25,15 @@ import logging from peewee import * -from playhouse.sqlite_ext import SqliteExtDatabase +from playhouse.db_url import connect from osm_mon.core.settings import Config log = logging.getLogger(__name__) cfg = Config.instance() +cfg.read_environ() -db = SqliteExtDatabase('mon.db') +db = connect(cfg.DATABASE) class BaseModel(Model): diff --git a/osm_mon/core/message_bus/producer.py b/osm_mon/core/message_bus/producer.py index d4f8015..bf0839c 100755 --- a/osm_mon/core/message_bus/producer.py +++ b/osm_mon/core/message_bus/producer.py @@ -25,13 +25,9 @@ and AWS. """ import logging - import os -from jsmin import jsmin - from kafka import KafkaProducer as kaf - from kafka.errors import KafkaError __author__ = "Prithiv Mohan" @@ -83,225 +79,166 @@ class KafkaProducer(object): except KafkaError: pass - def create_alarm_request(self, key, message, topic): + def create_alarm_request(self, key, message): """Create alarm request from SO to MON.""" # External to MON - payload_create_alarm = jsmin( - open(os.path.join(json_path, 'create_alarm.json')).read()) self.publish(key, value=message, topic='alarm_request') - def create_alarm_response(self, key, message, topic): + def create_alarm_response(self, key, message): """Response to a create alarm request from MON to SO.""" # Internal to MON - payload_create_alarm_resp = jsmin( - open(os.path.join(json_path, 'create_alarm_resp.json')).read()) - self.publish(key, value=message, topic='alarm_response') - def acknowledge_alarm(self, key, message, topic): + def acknowledge_alarm(self, key, message): """Alarm acknowledgement request from SO to MON.""" # Internal to MON - payload_acknowledge_alarm = jsmin( - open(os.path.join(json_path, 'acknowledge_alarm.json')).read()) - self.publish(key, value=message, topic='alarm_request') - def list_alarm_request(self, key, message, topic): + def list_alarm_request(self, key, message): """List alarms request from SO to MON.""" # External to MON - payload_alarm_list_req = jsmin( - open(os.path.join(json_path, 'list_alarm_req.json')).read()) - self.publish(key, value=message, topic='alarm_request') - def notify_alarm(self, key, message, topic): + def notify_alarm(self, key, message): """Notify of triggered alarm from MON to SO.""" - payload_notify_alarm = jsmin( - open(os.path.join(json_path, 'notify_alarm.json')).read()) self.publish(key, value=message, topic='alarm_response') - def list_alarm_response(self, key, message, topic): + def list_alarm_response(self, key, message): """Response for list alarms request from MON to SO.""" - payload_list_alarm_resp = jsmin( - open(os.path.join(json_path, 'list_alarm_resp.json')).read()) self.publish(key, value=message, topic='alarm_response') - def update_alarm_request(self, key, message, topic): + def update_alarm_request(self, key, message): """Update alarm request from SO to MON.""" # External to Mon - payload_update_alarm_req = jsmin( - open(os.path.join(json_path, 'update_alarm_req.json')).read()) - self.publish(key, value=message, topic='alarm_request') - def update_alarm_response(self, key, message, topic): + def update_alarm_response(self, key, message): """Response from update alarm request from MON to SO.""" # Internal to Mon - payload_update_alarm_resp = jsmin( - open(os.path.join(json_path, 'update_alarm_resp.json')).read()) - self.publish(key, value=message, topic='alarm_response') - def delete_alarm_request(self, key, message, topic): + def delete_alarm_request(self, key, message): """Delete alarm request from SO to MON.""" # External to Mon - payload_delete_alarm_req = jsmin( - open(os.path.join(json_path, 'delete_alarm_req.json')).read()) - self.publish(key, value=message, topic='alarm_request') - def delete_alarm_response(self, key, message, topic): + def delete_alarm_response(self, key, message): """Response for a delete alarm request from MON to SO.""" # Internal to Mon - payload_delete_alarm_resp = jsmin( - open(os.path.join(json_path, 'delete_alarm_resp.json')).read()) - self.publish(key, value=message, topic='alarm_response') - def create_metrics_request(self, key, message, topic): + def create_metrics_request(self, key, message): """Create metrics request from SO to MON.""" # External to Mon - payload_create_metrics_req = jsmin( - open(os.path.join(json_path, 'create_metric_req.json')).read()) - self.publish(key, value=message, topic='metric_request') - def create_metrics_resp(self, key, message, topic): + def create_metrics_resp(self, key, message): """Response for a create metric request from MON to SO.""" # Internal to Mon - payload_create_metrics_resp = jsmin( - open(os.path.join(json_path, 'create_metric_resp.json')).read()) - self.publish(key, value=message, topic='metric_response') - def read_metric_data_request(self, key, message, topic): + def read_metric_data_request(self, key, message): """Read metric data request from SO to MON.""" # External to Mon - payload_read_metric_data_request = jsmin( - open(os.path.join(json_path, 'read_metric_data_req.json')).read()) - self.publish(key, value=message, topic='metric_request') - def read_metric_data_response(self, key, message, topic): + def read_metric_data_response(self, key, message): """Response from MON to SO for read metric data request.""" # Internal to Mon - payload_metric_data_response = jsmin( - open(os.path.join(json_path, 'read_metric_data_resp.json')).read()) - self.publish(key, value=message, topic='metric_response') - def list_metric_request(self, key, message, topic): + def list_metric_request(self, key, message): """List metric request from SO to MON.""" # External to MON - payload_metric_list_req = jsmin( - open(os.path.join(json_path, 'list_metric_req.json')).read()) - self.publish(key, value=message, topic='metric_request') - def list_metric_response(self, key, message, topic): + def list_metric_response(self, key, message): """Response from SO to MON for list metrics request.""" # Internal to MON - payload_metric_list_resp = jsmin( - open(os.path.join(json_path, 'list_metric_resp.json')).read()) - self.publish(key, value=message, topic='metric_response') - def delete_metric_request(self, key, message, topic): + def delete_metric_request(self, key, message): """Delete metric request from SO to MON.""" # External to Mon - payload_delete_metric_req = jsmin( - open(os.path.join(json_path, 'delete_metric_req.json')).read()) - self.publish(key, value=message, topic='metric_request') - def delete_metric_response(self, key, message, topic): + def delete_metric_response(self, key, message): """Response from MON to SO for delete metric request.""" # Internal to Mon - payload_delete_metric_resp = jsmin( - open(os.path.join(json_path, 'delete_metric_resp.json')).read()) - self.publish(key, value=message, topic='metric_response') - def update_metric_request(self, key, message, topic): + def update_metric_request(self, key, message): """Metric update request from SO to MON.""" # External to Mon - payload_update_metric_req = jsmin( - open(os.path.join(json_path, 'update_metric_req.json')).read()) - self.publish(key, value=message, topic='metric_request') - def update_metric_response(self, key, message, topic): + def update_metric_response(self, key, message): """Reponse from MON to SO for metric update.""" # Internal to Mon - payload_update_metric_resp = jsmin( - open(os.path.join(json_path, 'update_metric_resp.json')).read()) - self.publish(key, value=message, topic='metric_response') - def access_credentials(self, key, message, topic): + def access_credentials(self, key, message): """Send access credentials to MON from SO.""" - payload_access_credentials = jsmin( - open(os.path.join(json_path, 'access_credentials.json')).read()) self.publish(key, value=message, diff --git a/osm_mon/core/models/create_alarm.json b/osm_mon/core/models/create_alarm.json index d7fce88..a25ea7b 100644 --- a/osm_mon/core/models/create_alarm.json +++ b/osm_mon/core/models/create_alarm.json @@ -29,8 +29,8 @@ "correlation_id": { "type": "integer" }, "alarm_name": { "type": "string" }, "metric_name": { "type": "string" }, - "tenant_uuid": { "type": "string" }, "resource_uuid": { "type": "string" }, + "vdu_id": { "type": "string"}, "description": { "type": "string" }, "severity": { "type": "string" }, "operation": { "type": "string" }, diff --git a/osm_mon/core/models/create_metric_req.json b/osm_mon/core/models/create_metric_req.json index 3710b43..6fa0972 100644 --- a/osm_mon/core/models/create_metric_req.json +++ b/osm_mon/core/models/create_metric_req.json @@ -23,7 +23,6 @@ { "schema_version": { "type": "string" }, "schema_type": { "type": "string" }, - "tenant_uuid": { "type": "string" }, "correlation_id": { "type": "integer" }, "vim_type": { "type": "string" }, "vim_uuid": { "type": "string" }, @@ -31,7 +30,8 @@ { "metric_name": { "type" : "string" }, "metric_unit": { "type": "string" }, - "resource_uuid": { "type": "string" } + "resource_uuid": { "type": "string" }, + "vdu_id": { "type": "string"} }, "required": [ "schema_version", "schema_type", diff --git a/osm_mon/core/models/delete_alarm_req.json b/osm_mon/core/models/delete_alarm_req.json index 5683b8d..a5b99e6 100644 --- a/osm_mon/core/models/delete_alarm_req.json +++ b/osm_mon/core/models/delete_alarm_req.json @@ -27,7 +27,8 @@ "alarm_delete_request": { "alarm_uuid": { "type": "string" }, - "correlation_id": { "type": "integer" } + "correlation_id": { "type": "integer" }, + "vdu_id": { "type": "string"} }, "required": [ "schema_version", "schema_type", diff --git a/osm_mon/core/models/delete_metric_req.json b/osm_mon/core/models/delete_metric_req.json index c4cfdad..c5788cd 100644 --- a/osm_mon/core/models/delete_metric_req.json +++ b/osm_mon/core/models/delete_metric_req.json @@ -25,11 +25,11 @@ "metric_name": { "type": "string" }, "metric_uuid": { "type": "string" }, "resource_uuid": { "type": "string" }, - "tenant_uuid": { "type": "string" }, + "vdu_id": { "type": "string"}, "correlation_id": { "type": "integer" }, "vim_type": { "type": "string" }, "vim_uuid": { "type": "string" }, - "required": [ "schema_verion", + "required": [ "schema_version", "schema_type", "metric_name", "metric_uuid", diff --git a/osm_mon/core/models/list_alarm_req.json b/osm_mon/core/models/list_alarm_req.json index dd46978..7dd9785 100644 --- a/osm_mon/core/models/list_alarm_req.json +++ b/osm_mon/core/models/list_alarm_req.json @@ -28,6 +28,7 @@ { "correlation_id": { "type": "integer" }, "resource_uuid": { "type": "string" }, + "vdu_id": { "type": "string"}, "alarm_name": { "type": "string" }, "severity": { "type" : "string" } }, diff --git a/osm_mon/core/models/list_metric_req.json b/osm_mon/core/models/list_metric_req.json index fecdde2..c684208 100644 --- a/osm_mon/core/models/list_metric_req.json +++ b/osm_mon/core/models/list_metric_req.json @@ -28,7 +28,8 @@ { "metric_name": { "type": "string" }, "correlation_id": { "type": "integer" }, - "resource_uuid": { "type": "string" } + "resource_uuid": { "type": "string" }, + "vdu_id": { "type": "string"} }, "required": [ "schema_version", "schema_type", diff --git a/osm_mon/core/models/notify_alarm.json b/osm_mon/core/models/notify_alarm.json index 9497b7f..0430d6a 100644 --- a/osm_mon/core/models/notify_alarm.json +++ b/osm_mon/core/models/notify_alarm.json @@ -28,8 +28,8 @@ { "alarm_uuid": { "type": "string" }, "resource_uuid": { "type": "string" }, + "vdu_id": { "type": "string"}, "description": { "type": "string" }, - "tenant_uuid": { "type": "string" }, "vim_type": { "type": "string" }, "vim_uuid": { "type": "string" }, "severity": { "type" : "string" }, diff --git a/osm_mon/core/models/read_metric_data_req.json b/osm_mon/core/models/read_metric_data_req.json index 922b91e..2554be8 100644 --- a/osm_mon/core/models/read_metric_data_req.json +++ b/osm_mon/core/models/read_metric_data_req.json @@ -25,7 +25,7 @@ "metric_name": { "type": "string" }, "metric_uuid": { "type": "string" }, "resource_uuid": { "type": "string" }, - "tenant_uuid": { "type": "string" }, + "vdu_id": { "type": "string"}, "correlation_id": { "type": "integer" }, "vim_type": { "type": "string" }, "vim_uuid": { "type": "string" }, diff --git a/osm_mon/core/models/update_alarm_req.json b/osm_mon/core/models/update_alarm_req.json index ab5c312..a8a0f82 100644 --- a/osm_mon/core/models/update_alarm_req.json +++ b/osm_mon/core/models/update_alarm_req.json @@ -29,6 +29,7 @@ "correlation_id": { "type": "integer" }, "alarm_uuid": { "type": "string" }, "metric_uuid": { "type": "string" }, + "vdu_id": { "type": "string"}, "description": { "type": "string" }, "severity": { "type": "string" }, "operation": { "type": "string" }, diff --git a/osm_mon/core/models/update_metric_req.json b/osm_mon/core/models/update_metric_req.json index f0f5b97..4b1c157 100644 --- a/osm_mon/core/models/update_metric_req.json +++ b/osm_mon/core/models/update_metric_req.json @@ -22,7 +22,6 @@ { "schema_version": { "type": "string" }, "schema_type": { "type": "string" }, - "tenant_uuid": { "type": "string" }, "correlation_id": { "type": "integer" }, "vim_type": { "type": "string" }, "vim_uuid": { "type": "string" }, @@ -30,7 +29,8 @@ { "metric_name": { "type": "string" }, "metric_unit": { "type": "string" }, - "resource_uuid": { "type": "string" } + "resource_uuid": { "type": "string" }, + "vdu_id": { "type": "string"} }, "required": [ "schema_version", "schema_type", diff --git a/osm_mon/core/settings.py b/osm_mon/core/settings.py index e40fecd..ae717e0 100644 --- a/osm_mon/core/settings.py +++ b/osm_mon/core/settings.py @@ -60,6 +60,7 @@ class Config(object): _configuration = [ CfgParam('BROKER_URI', "localhost:9092", six.text_type), + CfgParam('DATABASE', "sqlite:///mon_sqlite.db", six.text_type), CfgParam('OS_NOTIFIER_URI', "http://localhost:8662", six.text_type), CfgParam('OS_DEFAULT_GRANULARITY', "300", six.text_type), ] @@ -79,5 +80,5 @@ class Config(object): val = str(os.environ[key]) setattr(self, key, val) except KeyError as exc: - log.warn("Failed to configure plugin: %s", exc) + log.warning("Environment variable not present: %s", exc) return diff --git a/osm_mon/plugins/CloudWatch/connection.py b/osm_mon/plugins/CloudWatch/connection.py index 023071f..5853ae9 100644 --- a/osm_mon/plugins/CloudWatch/connection.py +++ b/osm_mon/plugins/CloudWatch/connection.py @@ -26,7 +26,6 @@ Connecting with AWS services --CloudWatch/EC2 using Required keys __author__ = "Wajeeha Hamid" __date__ = "18-September-2017" -import sys import os try: @@ -50,7 +49,7 @@ class Connection(): """Connection Establishement with AWS -- VPC/EC2/CloudWatch""" #----------------------------------------------------------------------------------------------------------------------------- def setEnvironment(self): - try: + try: """Credentials for connecting to AWS-CloudWatch""" #Reads from the environment variables self.AWS_KEY = os.environ.get("AWS_ACCESS_KEY_ID") diff --git a/osm_mon/plugins/CloudWatch/metric_alarms.py b/osm_mon/plugins/CloudWatch/metric_alarms.py index d8b3715..7b03f73 100644 --- a/osm_mon/plugins/CloudWatch/metric_alarms.py +++ b/osm_mon/plugins/CloudWatch/metric_alarms.py @@ -24,16 +24,7 @@ __author__ = "Wajeeha Hamid" __date__ = "18-September-2017" -import sys -import os -import re -import datetime -import random -import json import logging -from random import randint -from operator import itemgetter -from connection import Connection log = logging.getLogger(__name__) @@ -67,7 +58,7 @@ class MetricAlarm(): self.del_resp = dict() def config_alarm(self,cloudwatch_conn,create_info): - """Configure or Create a new alarm""" + """Configure or Create a new alarm""" inner_dict = dict() """ Alarm Name to ID Mapping """ alarm_info = create_info['alarm_create_request'] @@ -128,7 +119,7 @@ class MetricAlarm(): #----------------------------------------------------------------------------------------------------------------------------- def update_alarm(self,cloudwatch_conn,update_info): - """Update or reconfigure an alarm""" + """Update or reconfigure an alarm""" inner_dict = dict() alarm_info = update_info['alarm_update_request'] @@ -188,7 +179,7 @@ class MetricAlarm(): #----------------------------------------------------------------------------------------------------------------------------- def delete_Alarm(self,cloudwatch_conn,del_info_all): - """Deletes an Alarm with specified alarm_id""" + """Deletes an Alarm with specified alarm_id""" inner_dict = dict() del_info = del_info_all['alarm_delete_request'] status = self.is_present(cloudwatch_conn,del_info['alarm_uuid']) @@ -261,7 +252,7 @@ class MetricAlarm(): #----------------------------------------------------------------------------------------------------------------------------- def alarm_details(self,cloudwatch_conn,ack_info): - """Get an individual alarm details specified by alarm_name""" + """Get an individual alarm details specified by alarm_name""" try: alarms_details=cloudwatch_conn.describe_alarm_history() alarm_details_all = dict() @@ -306,10 +297,10 @@ class MetricAlarm(): return alarm_details_dict except Exception as e: - log.error("Error getting alarm details: %s",str(e)) + log.error("Error getting alarm details: %s",str(e)) #----------------------------------------------------------------------------------------------------------------------------- def is_present(self,cloudwatch_conn,alarm_id): - """Finding alarm from already configured alarms""" + """Finding alarm from already configured alarms""" alarm_info = dict() try: alarms = cloudwatch_conn.describe_alarms() diff --git a/osm_mon/plugins/CloudWatch/metrics.py b/osm_mon/plugins/CloudWatch/metrics.py index 5c6c976..1586359 100644 --- a/osm_mon/plugins/CloudWatch/metrics.py +++ b/osm_mon/plugins/CloudWatch/metrics.py @@ -26,9 +26,7 @@ AWS-Plugin implements all the methods of MON to interact with AWS using the BOTO __author__ = "Wajeeha Hamid" __date__ = "18-Sept-2017" -import sys import datetime -import json import logging try: @@ -71,7 +69,7 @@ class Metrics(): def metricsData(self,cloudwatch_conn,data_info): - """Getting Metrics Stats for an Hour.The datapoints are + """Getting Metrics Stats for an Hour.The datapoints are received after every one minute. Time interval can be modified using Timedelta value""" @@ -182,7 +180,7 @@ class Metrics(): metrics_info['resource_uuid'] = instance_id metrics_list.insert(itr,metrics_info) itr += 1 - print metrics_list + log.info(metrics_list) return metrics_list else: for alarm in alarms: @@ -246,7 +244,7 @@ class Metrics(): if metric_status == True: check_resp['status'] = True else: - check_resp['status'] = False + check_resp['status'] = False return check_resp diff --git a/osm_mon/plugins/CloudWatch/plugin_alarm.py b/osm_mon/plugins/CloudWatch/plugin_alarm.py index c8ca955..c2ac6a7 100644 --- a/osm_mon/plugins/CloudWatch/plugin_alarm.py +++ b/osm_mon/plugins/CloudWatch/plugin_alarm.py @@ -22,19 +22,16 @@ ''' AWS-Plugin implements all the methods of MON to interact with AWS using the BOTO client ''' +from io import open +from osm_mon.core.message_bus.producer import KafkaProducer +from osm_mon.plugins.CloudWatch.metric_alarms import MetricAlarm +from osm_mon.plugins.CloudWatch.metrics import Metrics __author__ = "Wajeeha Hamid" __date__ = "18-September-2017" -import sys import json import logging -from jsmin import jsmin -from connection import Connection -from metric_alarms import MetricAlarm -from metrics import Metrics -sys.path.append("../../core/message_bus") -from producer import KafkaProducer log = logging.getLogger(__name__) @@ -90,12 +87,12 @@ class plugin_alarms(): log.debug("Alarm Already exists") payload = json.dumps(config_resp) file = open('../../core/models/create_alarm_resp.json','wb').write((payload)) - self.producer.create_alarm_response(key='create_alarm_response',message=payload,topic = 'alarm_response') + self.producer.create_alarm_response(key='create_alarm_response',message=payload) else: payload = json.dumps(config_resp) file = open('../../core/models/create_alarm_resp.json','wb').write((payload)) - self.producer.create_alarm_response(key='create_alarm_response',message=payload,topic = 'alarm_response') + self.producer.create_alarm_response(key='create_alarm_response',message=payload) log.info("New alarm created with alarm info: %s", config_resp) else: diff --git a/osm_mon/plugins/CloudWatch/plugin_metric.py b/osm_mon/plugins/CloudWatch/plugin_metric.py index b6508a5..3b7029f 100644 --- a/osm_mon/plugins/CloudWatch/plugin_metric.py +++ b/osm_mon/plugins/CloudWatch/plugin_metric.py @@ -22,17 +22,13 @@ ''' AWS-Plugin implements all the methods of MON to interact with AWS using the BOTO client ''' +from osm_mon.core.message_bus.producer import KafkaProducer +from osm_mon.plugins.CloudWatch.metrics import Metrics __author__ = "Wajeeha Hamid" __date__ = "18-September-2017" -import sys import json -from connection import Connection -from metric_alarms import MetricAlarm -from metrics import Metrics -sys.path.append("../../core/message_bus") -from producer import KafkaProducer import logging log = logging.getLogger(__name__) diff --git a/osm_mon/plugins/OpenStack/Aodh/alarming.py b/osm_mon/plugins/OpenStack/Aodh/alarming.py index 09dc5f6..2c145ee 100644 --- a/osm_mon/plugins/OpenStack/Aodh/alarming.py +++ b/osm_mon/plugins/OpenStack/Aodh/alarming.py @@ -102,7 +102,7 @@ class Alarming(object): resource_id = values['resource_uuid'] if metric_name not in METRIC_MAPPINGS.keys(): - log.warn("This metric is not supported.") + log.warning("This metric is not supported.") return None, False # Check for the required metric @@ -119,11 +119,11 @@ class Alarming(object): url, auth_token, req_type="post", payload=payload) return json.loads(new_alarm.text)['alarm_id'], True else: - log.warn("The required Gnocchi metric does not exist.") + log.warning("The required Gnocchi metric does not exist.") return None, False except Exception as exc: - log.warn("Failed to create the alarm: %s", exc) + log.warning("Failed to create the alarm: %s", exc) return None, False def alarming(self, message): @@ -163,8 +163,7 @@ class Alarming(object): cor_id=alarm_details['correlation_id']) log.info("Response Message: %s", resp_message) self._producer.create_alarm_response( - 'create_alarm_response', resp_message, - 'alarm_response') + 'create_alarm_response', resp_message) except Exception: log.exception("Response creation failed:") @@ -183,8 +182,7 @@ class Alarming(object): cor_id=list_details['correlation_id']) log.info("Response Message: %s", resp_message) self._producer.list_alarm_response( - 'list_alarm_response', resp_message, - 'alarm_response') + 'list_alarm_response', resp_message) except Exception: log.exception("Failed to send a valid response back.") @@ -203,8 +201,7 @@ class Alarming(object): cor_id=request_details['correlation_id']) log.info("Response message: %s", resp_message) self._producer.delete_alarm_response( - 'delete_alarm_response', resp_message, - 'alarm_response') + 'delete_alarm_response', resp_message) except Exception: log.exception("Failed to create delete response: ") @@ -219,7 +216,7 @@ class Alarming(object): if response is True: log.info("Acknowledged the alarm and cleared it.") else: - log.warn("Failed to acknowledge/clear the alarm.") + log.warning("Failed to acknowledge/clear the alarm.") elif message.key == "update_alarm_request": # Update alarm configurations @@ -236,8 +233,7 @@ class Alarming(object): status=status) log.info("Response message: %s", resp_message) self._producer.update_alarm_response( - 'update_alarm_response', resp_message, - 'alarm_response') + 'update_alarm_response', resp_message) except Exception: log.exception("Failed to send an update response: ") @@ -274,14 +270,14 @@ class Alarming(object): try: resource = list_details['resource_uuid'] except KeyError as exc: - log.warn("Resource id not specified for list request: %s", exc) + log.warning("Resource id not specified for list request: %s", exc) return None # Checking what fields are specified for a list request try: name = list_details['alarm_name'].lower() if name not in ALARM_NAMES.keys(): - log.warn("This alarm is not supported, won't be used!") + log.warning("This alarm is not supported, won't be used!") name = None except KeyError as exc: log.info("Alarm name isn't specified.") @@ -373,7 +369,7 @@ class Alarming(object): resource_id = rule['resource_id'] metric_name = [key for key, value in six.iteritems(METRIC_MAPPINGS) if value == rule['metric']][0] except Exception as exc: - log.warn("Failed to retrieve existing alarm info: %s.\ + log.warning("Failed to retrieve existing alarm info: %s.\ Can only update OSM alarms.", exc) return None, False @@ -391,7 +387,7 @@ class Alarming(object): return json.loads(update_alarm.text)['alarm_id'], True except Exception as exc: - log.warn("Alarm update could not be performed: %s", exc) + log.warning("Alarm update could not be performed: %s", exc) return None, False return None, False @@ -439,7 +435,7 @@ class Alarming(object): 'alarm_actions': [cfg.OS_NOTIFIER_URI], }) return payload except KeyError as exc: - log.warn("Alarm is not configured correctly: %s", exc) + log.warning("Alarm is not configured correctly: %s", exc) return None def get_alarm_state(self, endpoint, auth_token, alarm_id): @@ -451,7 +447,7 @@ class Alarming(object): url, auth_token, req_type="get") return json.loads(alarm_state.text) except Exception as exc: - log.warn("Failed to get the state of the alarm:%s", exc) + log.warning("Failed to get the state of the alarm:%s", exc) return None def check_for_metric(self, auth_token, metric_endpoint, m_name, r_id): diff --git a/osm_mon/plugins/OpenStack/Aodh/notifier.py b/osm_mon/plugins/OpenStack/Aodh/notifier.py index c09ad9e..55178fd 100644 --- a/osm_mon/plugins/OpenStack/Aodh/notifier.py +++ b/osm_mon/plugins/OpenStack/Aodh/notifier.py @@ -70,6 +70,10 @@ class NotifierHandler(BaseHTTPRequestHandler): # Gets the size of data content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) + try: + post_data = post_data.decode() + except AttributeError: + pass self.wfile.write("

POST!

") log.info("This alarm was triggered: %s", json.loads(post_data)) @@ -122,9 +126,9 @@ class NotifierHandler(BaseHTTPRequestHandler): except Exception as exc: log.exception("Couldn't notify SO of the alarm:") else: - log.warn("No resource_id for alarm; no SO response sent.") + log.warning("No resource_id for alarm; no SO response sent.") else: - log.warn("Authentication failure; SO notification not sent.") + log.warning("Authentication failure; SO notification not sent.") except: log.exception("Could not notify alarm.") @@ -138,7 +142,7 @@ def run(server_class=HTTPServer, handler_class=NotifierHandler, port=8662): log.info("Starting alarm notifier server on port: %s", port) httpd.serve_forever() except Exception as exc: - log.warn("Failed to start webserver, %s", exc) + log.warning("Failed to start webserver, %s", exc) if __name__ == "__main__": diff --git a/osm_mon/plugins/OpenStack/Gnocchi/metrics.py b/osm_mon/plugins/OpenStack/Gnocchi/metrics.py index b41b5c0..9e69ee7 100644 --- a/osm_mon/plugins/OpenStack/Gnocchi/metrics.py +++ b/osm_mon/plugins/OpenStack/Gnocchi/metrics.py @@ -87,6 +87,9 @@ class Metrics(object): endpoint = Common.get_endpoint("metric", values['vim_uuid']) + if 'metric_name' in values and values['metric_name'] not in METRIC_MAPPINGS.keys(): + raise ValueError('Metric ' + values['metric_name'] + ' is not supported.') + if message.key == "create_metric_request": # Configure metric metric_details = values['metric_create'] @@ -101,10 +104,9 @@ class Metrics(object): metric_id=metric_id, r_id=resource_id) log.info("Response messages: %s", resp_message) self._producer.create_metrics_resp( - 'create_metric_response', resp_message, - 'metric_response') + 'create_metric_response', resp_message) except Exception as exc: - log.warn("Failed to create response: %s", exc) + log.warning("Failed to create response: %s", exc) elif message.key == "read_metric_data_request": # Read all metric data related to a specified metric @@ -115,7 +117,7 @@ class Metrics(object): try: metric_id = self.get_metric_id(endpoint, auth_token, METRIC_MAPPINGS[values['metric_name']], - values['resource_uuid']) + values['resource_uuid']) resp_message = self._response.generate_response( 'read_metric_data_response', m_id=metric_id, @@ -125,10 +127,9 @@ class Metrics(object): times=timestamps, metrics=metric_data) log.info("Response message: %s", resp_message) self._producer.read_metric_data_response( - 'read_metric_data_response', resp_message, - 'metric_response') + 'read_metric_data_response', resp_message) except Exception as exc: - log.warn("Failed to send read metric response:%s", exc) + log.warning("Failed to send read metric response:%s", exc) elif message.key == "delete_metric_request": # delete the specified metric in the request @@ -146,15 +147,14 @@ class Metrics(object): cor_id=values['correlation_id']) log.info("Response message: %s", resp_message) self._producer.delete_metric_response( - 'delete_metric_response', resp_message, - 'metric_response') + 'delete_metric_response', resp_message) except Exception as exc: - log.warn("Failed to send delete response:%s", exc) + log.warning("Failed to send delete response:%s", exc) elif message.key == "update_metric_request": # Gnocchi doesn't support configuration updates # Log and send a response back to this effect - log.warn("Gnocchi doesn't support metric configuration\ + log.warning("Gnocchi doesn't support metric configuration\ updates.") req_details = values['metric_create'] metric_name = req_details['metric_name'] @@ -170,10 +170,9 @@ class Metrics(object): r_id=resource_id, m_id=metric_id) log.info("Response message: %s", resp_message) self._producer.update_metric_response( - 'update_metric_response', resp_message, - 'metric_response') + 'update_metric_response', resp_message) except Exception as exc: - log.warn("Failed to send an update response:%s", exc) + log.warning("Failed to send an update response:%s", exc) elif message.key == "list_metric_request": list_details = values['metrics_list_request'] @@ -188,13 +187,12 @@ class Metrics(object): cor_id=list_details['correlation_id']) log.info("Response message: %s", resp_message) self._producer.list_metric_response( - 'list_metric_response', resp_message, - 'metric_response') + 'list_metric_response', resp_message) except Exception as exc: - log.warn("Failed to send a list response:%s", exc) + log.warning("Failed to send a list response:%s", exc) else: - log.warn("Unknown key, no action will be performed.") + log.warning("Unknown key, no action will be performed.") return @@ -203,13 +201,13 @@ class Metrics(object): try: resource_id = values['resource_uuid'] except KeyError: - log.warn("Resource is not defined correctly.") + log.warning("Resource is not defined correctly.") return None, None, False # Check/Normalize metric name norm_name, metric_name = self.get_metric_name(values) if metric_name is None: - log.warn("This metric is not supported by this plugin.") + log.warning("This metric is not supported by this plugin.") return None, resource_id, False # Check for an existing metric for this resource @@ -261,7 +259,7 @@ class Metrics(object): return metric_id, new_resource_id, True except Exception as exc: - log.warn("Failed to create a new resource:%s", exc) + log.warning("Failed to create a new resource:%s", exc) return None, None, False else: @@ -277,12 +275,12 @@ class Metrics(object): result = Common.perform_request( url, auth_token, req_type="delete") if str(result.status_code) == "404": - log.warn("Failed to delete the metric.") + log.warning("Failed to delete the metric.") return False else: return True except Exception as exc: - log.warn("Failed to carry out delete metric request:%s", exc) + log.warning("Failed to carry out delete metric request:%s", exc) return False def list_metrics(self, endpoint, auth_token, values): @@ -293,7 +291,7 @@ class Metrics(object): # Check if the metric_name was specified for the list metric_name = values['metric_name'].lower() if metric_name not in METRIC_MAPPINGS.keys(): - log.warn("This metric is not supported, won't be listed.") + log.warning("This metric is not supported, won't be listed.") metric_name = None except KeyError as exc: log.info("Metric name is not specified: %s", exc) @@ -348,7 +346,7 @@ class Metrics(object): log.info("There are no metrics available") return [] except Exception as exc: - log.warn("Failed to generate any metric list. %s", exc) + log.warning("Failed to generate any metric list. %s", exc) return None def get_metric_id(self, endpoint, auth_token, metric_name, resource_id): @@ -379,8 +377,9 @@ class Metrics(object): timestamps = [] data = [] try: - #get metric_id - metric_id = self.get_metric_id(endpoint, auth_token, METRIC_MAPPINGS[values['metric_name']], values['resource_uuid']) + # get metric_id + metric_id = self.get_metric_id(endpoint, auth_token, METRIC_MAPPINGS[values['metric_name']], + values['resource_uuid']) # Try and collect measures collection_unit = values['collection_unit'].upper() collection_period = values['collection_period'] @@ -412,7 +411,7 @@ class Metrics(object): return timestamps, data except Exception as exc: - log.warn("Failed to gather specified measures: %s", exc) + log.warning("Failed to gather specified measures: %s", exc) return timestamps, data def response_list(self, metric_list, metric_name=None, resource=None): @@ -424,7 +423,7 @@ class Metrics(object): # Only list OSM metrics name = None if row['name'] in METRIC_MAPPINGS.values(): - for k,v in six.iteritems(METRIC_MAPPINGS): + for k, v in six.iteritems(METRIC_MAPPINGS): if row['name'] == v: name = k metric = {"metric_name": name, diff --git a/osm_mon/plugins/OpenStack/response.py b/osm_mon/plugins/OpenStack/response.py index 75d907e..bd1133e 100644 --- a/osm_mon/plugins/OpenStack/response.py +++ b/osm_mon/plugins/OpenStack/response.py @@ -58,7 +58,7 @@ class OpenStack_Response(object): elif key == "notify_alarm": message = self.notify_alarm(**kwargs) else: - log.warn("Failed to generate a valid response message.") + log.warning("Failed to generate a valid response message.") message = None return message diff --git a/osm_mon/plugins/vRealiseOps/plugin_receiver.py b/osm_mon/plugins/vRealiseOps/plugin_receiver.py index af56372..9526e64 100644 --- a/osm_mon/plugins/vRealiseOps/plugin_receiver.py +++ b/osm_mon/plugins/vRealiseOps/plugin_receiver.py @@ -26,14 +26,16 @@ Montoring plugin receiver that consumes the request messages & responds using producer for vROPs """ -import sys -import os import json import logging +import os +import sys import traceback -from mon_plugin_vrops import MonPlugin -from kafka_consumer_vrops import vROP_KafkaConsumer + + #Core producer +from osm_mon.plugins.vRealiseOps.mon_plugin_vrops import MonPlugin + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..')) from osm_mon.core.message_bus.producer import KafkaProducer #from core.message_bus.producer import KafkaProducer diff --git a/osm_mon/test/CloudWatch/unit_tests_alarms.py b/osm_mon/test/CloudWatch/unit_tests_alarms.py index e34586b..ae036cf 100644 --- a/osm_mon/test/CloudWatch/unit_tests_alarms.py +++ b/osm_mon/test/CloudWatch/unit_tests_alarms.py @@ -56,7 +56,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info + print(info) time.sleep(1) self.assertTrue(info['alarm_create_response']['status']) return @@ -73,7 +73,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info + print(info) time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid_delete1.json",'delete_alarm_request','','alarm_request') self.assertTrue(info['alarm_create_response']['status']) @@ -91,7 +91,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info + print(info) time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid_delete2.json",'delete_alarm_request', '','alarm_request') self.assertTrue(info['alarm_create_response']['status']) @@ -109,7 +109,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info,"---" + print(info, "---") time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid.json",'delete_alarm_request', '','alarm_request') self.assertEqual(info, None) @@ -127,7 +127,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info + print(info) time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid_delete3.json",'delete_alarm_request', '','alarm_request') self.assertTrue(info['alarm_create_response']['status']) @@ -145,7 +145,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info,"---" + print(info, "---") time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid_delete3.json",'delete_alarm_request', '','alarm_request') self.assertEqual(info, None) @@ -163,7 +163,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info + print(info) time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid_delete3.json",'delete_alarm_request', '','alarm_request') self.assertTrue(info['alarm_create_response']['status']) @@ -181,7 +181,7 @@ class config_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "create_alarm_response": info = json.loads(json.loads(message.value)) - print info + print(info) time.sleep(1) self.assertEqual(info,None) return @@ -203,7 +203,7 @@ class update_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "update_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid_delete4.json",'delete_alarm_request', '','alarm_request') self.assertTrue(info['alarm_update_response']['status']) @@ -221,7 +221,7 @@ class update_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "update_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertEqual(info,None) return @@ -239,7 +239,7 @@ class update_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "update_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid.json",'delete_alarm_request', '','alarm_request') self.assertTrue(info['alarm_update_response']['status']) @@ -257,7 +257,7 @@ class update_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "update_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertEqual(info,None) return @@ -275,7 +275,7 @@ class update_alarm_name_test(unittest.TestCase): for message in _consumer: if message.key == "update_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) producer.request("test_schemas/delete_alarm/name_valid.json",'delete_alarm_request', '','alarm_request') self.assertTrue(info['alarm_update_response']['status']) @@ -297,7 +297,7 @@ class delete_alarm_test(unittest.TestCase): for message in _consumer: if message.key == "delete_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertTrue(info['alarm_deletion_response']['status']) return @@ -314,7 +314,7 @@ class delete_alarm_test(unittest.TestCase): for message in _consumer: if message.key == "delete_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertEqual(info,None) return @@ -334,7 +334,7 @@ class list_alarm_test(unittest.TestCase): for message in _consumer: if message.key == "list_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertEqual(type(info),dict) return @@ -351,7 +351,7 @@ class list_alarm_test(unittest.TestCase): for message in _consumer: if message.key == "list_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertEqual(type(info),dict) return @@ -368,7 +368,7 @@ class list_alarm_test(unittest.TestCase): for message in _consumer: if message.key == "list_alarm_response": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertEqual(type(info),dict) return @@ -389,7 +389,7 @@ class alarm_details_test(unittest.TestCase): for message in _consumer: if message.key == "notify_alarm": info = json.loads(json.loads(json.loads(message.value))) - print info + print(info) time.sleep(1) self.assertEqual(type(info),dict) return diff --git a/osm_mon/test/OpenStack/integration/__init__.py b/osm_mon/test/OpenStack/integration/__init__.py new file mode 100644 index 0000000..d81308a --- /dev/null +++ b/osm_mon/test/OpenStack/integration/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Whitestack, LLC +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Whitestack, LLC + +# 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: bdiaz@whitestack.com or glavado@whitestack.com +## diff --git a/osm_mon/test/OpenStack/integration/test_alarm_integration.py b/osm_mon/test/OpenStack/integration/test_alarm_integration.py new file mode 100644 index 0000000..b0cfd32 --- /dev/null +++ b/osm_mon/test/OpenStack/integration/test_alarm_integration.py @@ -0,0 +1,241 @@ +# Copyright 2017 Intel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com + +# __author__ = "Helena McGough" +"""Test an end to end Openstack alarm requests.""" + +import json +import logging +import unittest + +import mock +from kafka import KafkaConsumer +from kafka import KafkaProducer +from kafka.errors import KafkaError + +from osm_mon.core.auth import AuthManager +from osm_mon.core.database import DatabaseManager, VimCredentials +from osm_mon.core.message_bus.producer import KafkaProducer as prod +from osm_mon.plugins.OpenStack import response +from osm_mon.plugins.OpenStack.Aodh import alarming +from osm_mon.plugins.OpenStack.common import Common + +log = logging.getLogger(__name__) + +mock_creds = VimCredentials() +mock_creds.config = '{}' + + +class AlarmIntegrationTest(unittest.TestCase): + def setUp(self): + try: + self.producer = KafkaProducer(bootstrap_servers='localhost:9092', + key_serializer=str.encode, + value_serializer=str.encode + ) + self.req_consumer = KafkaConsumer(bootstrap_servers='localhost:9092', + key_deserializer=bytes.decode, + value_deserializer=bytes.decode, + auto_offset_reset='earliest', + consumer_timeout_ms=60000) + self.req_consumer.subscribe(['alarm_request']) + except KafkaError: + self.skipTest('Kafka server not present.') + # Set up common and alarming class instances + self.alarms = alarming.Alarming() + self.openstack_auth = Common() + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(prod, "update_alarm_response") + @mock.patch.object(alarming.Alarming, "update_alarm") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_update_alarm_req(self, resp, update_alarm, update_resp, get_creds): + """Test Aodh update alarm request message from KafkaProducer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "test_id", + "alarm_update_request": + {"correlation_id": 123, + "alarm_uuid": "alarm_id", + "metric_uuid": "metric_id"}} + + get_creds.return_value = mock_creds + + self.producer.send('alarm_request', key="update_alarm_request", + value=json.dumps(payload)) + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "update_alarm_request": + # Mock a valid alarm update + update_alarm.return_value = "alarm_id", True + self.alarms.alarming(message) + + # A response message is generated and sent via MON's producer + resp.assert_called_with( + 'update_alarm_response', alarm_id="alarm_id", cor_id=123, + status=True) + update_resp.assert_called_with( + 'update_alarm_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(DatabaseManager, "save_alarm", mock.Mock()) + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(prod, "create_alarm_response") + @mock.patch.object(alarming.Alarming, "configure_alarm") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_create_alarm_req(self, resp, config_alarm, create_resp, get_creds): + """Test Aodh create alarm request message from KafkaProducer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "test_id", + "alarm_create_request": + {"correlation_id": 123, + "alarm_name": "my_alarm", + "metric_name": "my_metric", + "resource_uuid": "my_resource", + "severity": "WARNING"}} + + get_creds.return_value = mock_creds + + self.producer.send('alarm_request', key="create_alarm_request", + value=json.dumps(payload)) + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "create_alarm_request": + # Mock a valid alarm creation + config_alarm.return_value = "alarm_id", True + self.alarms.alarming(message) + + # A response message is generated and sent via MON's produce + resp.assert_called_with( + 'create_alarm_response', status=True, alarm_id="alarm_id", + cor_id=123) + create_resp.assert_called_with( + 'create_alarm_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(prod, "list_alarm_response") + @mock.patch.object(alarming.Alarming, "list_alarms") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_list_alarm_req(self, resp, list_alarm, list_resp, get_creds): + """Test Aodh list alarm request message from KafkaProducer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "test_id", + "alarm_list_request": + {"correlation_id": 123, + "resource_uuid": "resource_id", }} + + self.producer.send('alarm_request', key="list_alarm_request", + value=json.dumps(payload)) + + get_creds.return_value = mock_creds + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "list_alarm_request": + # Mock an empty list generated by the request + list_alarm.return_value = [] + self.alarms.alarming(message) + + # Response message is generated + resp.assert_called_with( + 'list_alarm_response', alarm_list=[], + cor_id=123) + # Producer attempts to send the response message back to the SO + list_resp.assert_called_with( + 'list_alarm_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(alarming.Alarming, "delete_alarm") + @mock.patch.object(prod, "delete_alarm_response") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_delete_alarm_req(self, resp, del_resp, del_alarm, get_creds): + """Test Aodh delete alarm request message from KafkaProducer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "test_id", + "alarm_delete_request": + {"correlation_id": 123, + "alarm_uuid": "alarm_id", }} + + self.producer.send('alarm_request', key="delete_alarm_request", + value=json.dumps(payload)) + + get_creds.return_value = mock_creds + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "delete_alarm_request": + self.alarms.alarming(message) + + # Response message is generated and sent by MON's producer + resp.assert_called_with( + 'delete_alarm_response', alarm_id="alarm_id", + status=del_alarm.return_value, cor_id=123) + del_resp.assert_called_with( + 'delete_alarm_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(alarming.Alarming, "update_alarm_state") + def test_ack_alarm_req(self, ack_alarm, get_creds): + """Test Aodh acknowledge alarm request message from KafkaProducer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "test_id", + "ack_details": + {"alarm_uuid": "alarm_id", }} + + self.producer.send('alarm_request', key="acknowledge_alarm", + value=json.dumps(payload)) + + get_creds.return_value = mock_creds + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "acknowledge_alarm": + self.alarms.alarming(message) + return + + self.fail("No message received in consumer") diff --git a/osm_mon/test/OpenStack/integration/test_metric_integration.py b/osm_mon/test/OpenStack/integration/test_metric_integration.py new file mode 100644 index 0000000..c130973 --- /dev/null +++ b/osm_mon/test/OpenStack/integration/test_metric_integration.py @@ -0,0 +1,239 @@ +# Copyright 2017 Intel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com + +# __author__ = "Helena McGough" +"""Test an end to end Openstack metric requests.""" + +import json + +import logging +import unittest + +from kafka.errors import KafkaError + +from osm_mon.core.message_bus.producer import KafkaProducer as prod + +from kafka import KafkaConsumer +from kafka import KafkaProducer + +import mock + +from osm_mon.plugins.OpenStack import response + +from osm_mon.plugins.OpenStack.Gnocchi import metrics + +from osm_mon.plugins.OpenStack.common import Common + +log = logging.getLogger(__name__) + + +class MetricIntegrationTest(unittest.TestCase): + def setUp(self): + # Set up common and alarming class instances + self.metric_req = metrics.Metrics() + self.openstack_auth = Common() + + try: + self.producer = KafkaProducer(bootstrap_servers='localhost:9092', + key_serializer=str.encode, + value_serializer=str.encode + ) + self.req_consumer = KafkaConsumer(bootstrap_servers='localhost:9092', + key_deserializer=bytes.decode, + value_deserializer=bytes.decode, + auto_offset_reset='earliest', + consumer_timeout_ms=60000) + self.req_consumer.subscribe(['metric_request']) + except KafkaError: + self.skipTest('Kafka server not present.') + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(metrics.Metrics, "configure_metric") + @mock.patch.object(prod, "create_metrics_resp") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_create_metric_req(self, resp, create_resp, config_metric): + """Test Gnocchi create metric request message from producer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "1", + "correlation_id": 123, + "metric_create": + {"metric_name": "cpu_utilization", + "resource_uuid": "resource_id"}} + + self.producer.send('metric_request', key="create_metric_request", + value=json.dumps(payload)) + + for message in self.req_consumer: + # Check the vim desired by the message + vim_type = json.loads(message.value)["vim_type"].lower() + if vim_type == "openstack": + # A valid metric is created + config_metric.return_value = "metric_id", "resource_id", True + self.metric_req.metric_calls(message) + + # A response message is generated and sent by MON's producer + resp.assert_called_with( + 'create_metric_response', status=True, cor_id=123, + metric_id="metric_id", r_id="resource_id") + create_resp.assert_called_with( + 'create_metric_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(metrics.Metrics, "delete_metric") + @mock.patch.object(prod, "delete_metric_response") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_delete_metric_req(self, resp, del_resp, del_metric): + """Test Gnocchi delete metric request message from producer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "1", + "correlation_id": 123, + "metric_name": "cpu_utilization", + "resource_uuid": "resource_id"} + + self.producer.send('metric_request', key="delete_metric_request", + value=json.dumps(payload)) + + for message in self.req_consumer: + if message.key == "delete_metric_request": + # Metric has been deleted + del_metric.return_value = True + self.metric_req.metric_calls(message) + + # A response message is generated and sent by MON's producer + resp.assert_called_with( + 'delete_metric_response', m_id=None, + m_name="cpu_utilization", status=True, r_id="resource_id", + cor_id=123) + del_resp.assert_called_with( + 'delete_metric_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(metrics.Metrics, "read_metric_data") + @mock.patch.object(prod, "read_metric_data_response") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_read_metric_data_req(self, resp, read_resp, read_data): + """Test Gnocchi read metric data request message from producer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "test_id", + "correlation_id": 123, + "metric_name": "cpu_utilization", + "resource_uuid": "resource_id"} + + self.producer.send('metric_request', key="read_metric_data_request", + value=json.dumps(payload)) + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "read_metric_data_request": + # Mock empty lists generated by the request message + read_data.return_value = [], [] + self.metric_req.metric_calls(message) + + # A response message is generated and sent by MON's producer + resp.assert_called_with( + 'read_metric_data_response', m_id=None, + m_name="cpu_utilization", r_id="resource_id", cor_id=123, times=[], + metrics=[]) + read_resp.assert_called_with( + 'read_metric_data_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(metrics.Metrics, "list_metrics") + @mock.patch.object(prod, "list_metric_response") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_list_metrics_req(self, resp, list_resp, list_metrics): + """Test Gnocchi list metrics request message from producer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "1", + "metrics_list_request": + {"correlation_id": 123, }} + + self.producer.send('metric_request', key="list_metric_request", + value=json.dumps(payload)) + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "list_metric_request": + # Mock an empty list generated by the request + list_metrics.return_value = [] + self.metric_req.metric_calls(message) + + # A response message is generated and sent by MON's producer + resp.assert_called_with( + 'list_metric_response', m_list=[], cor_id=123) + list_resp.assert_called_with( + 'list_metric_response', resp.return_value) + + return + self.fail("No message received in consumer") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, "get_endpoint", mock.Mock()) + @mock.patch.object(metrics.Metrics, "get_metric_id") + @mock.patch.object(prod, "update_metric_response") + @mock.patch.object(response.OpenStack_Response, "generate_response") + def test_update_metrics_req(self, resp, update_resp, get_id): + """Test Gnocchi update metric request message from KafkaProducer.""" + # Set-up message, producer and consumer for tests + payload = {"vim_type": "OpenSTACK", + "vim_uuid": "test_id", + "correlation_id": 123, + "metric_create": + {"metric_name": "my_metric", + "resource_uuid": "resource_id", }} + + self.producer.send('metric_request', key="update_metric_request", + value=json.dumps(payload)) + + for message in self.req_consumer: + # Check the vim desired by the message + if message.key == "update_metric_request": + # Gnocchi doesn't support metric updates + get_id.return_value = "metric_id" + self.metric_req.metric_calls(message) + + # Response message is generated and sent via MON's producer + # No metric update has taken place + resp.assert_called_with( + 'update_metric_response', status=False, cor_id=123, + r_id="resource_id", m_id="metric_id") + update_resp.assert_called_with( + 'update_metric_response', resp.return_value) + + return + self.fail("No message received in consumer") diff --git a/osm_mon/test/OpenStack/integration/test_notify_alarm.py b/osm_mon/test/OpenStack/integration/test_notify_alarm.py new file mode 100644 index 0000000..1b2c64c --- /dev/null +++ b/osm_mon/test/OpenStack/integration/test_notify_alarm.py @@ -0,0 +1,191 @@ +# Copyright 2017 Intel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for all common OpenStack methods.""" + + +from __future__ import unicode_literals +import json +import logging +import socket +import unittest +from threading import Thread + +import mock +import requests +from six.moves.BaseHTTPServer import BaseHTTPRequestHandler +from six.moves.BaseHTTPServer import HTTPServer + +from osm_mon.core.message_bus.producer import KafkaProducer +from osm_mon.core.settings import Config +from osm_mon.plugins.OpenStack.Aodh.alarming import Alarming +from osm_mon.plugins.OpenStack.common import Common +from osm_mon.plugins.OpenStack.response import OpenStack_Response + +log = logging.getLogger(__name__) + +# Create an instance of the common openstack class, producer and consumer +openstack_auth = Common() + +# Mock a valid get_response for alarm details +valid_get_resp = '{"gnocchi_resources_threshold_rule":\ + {"resource_id": "my_resource_id"}}' + + +class MockResponse(object): + """Mock a response class for generating responses.""" + + def __init__(self, text): + """Initialise a mock response with a text attribute.""" + self.text = text + + +class MockNotifierHandler(BaseHTTPRequestHandler): + """Mock the NotifierHandler class for testing purposes.""" + + def _set_headers(self): + """Set the headers for a request.""" + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.end_headers() + + def do_GET(self): + """Mock functionality for GET request.""" + # self.send_response(requests.codes.ok) + self._set_headers() + pass + + def do_POST(self): + """Mock functionality for a POST request.""" + self._set_headers() + content_length = int(self.headers['Content-Length']) + post_data = self.rfile.read(content_length) + try: + post_data = post_data.decode() + except AttributeError: + pass + self.notify_alarm(json.loads(post_data)) + + def notify_alarm(self, values): + """Mock the notify_alarm functionality to generate a valid response.""" + config = Config.instance() + config.read_environ() + self._alarming = Alarming() + self._common = Common() + self._response = OpenStack_Response() + self._producer = KafkaProducer('alarm_response') + alarm_id = values['alarm_id'] + + auth_token = Common.get_auth_token('test_id') + endpoint = Common.get_endpoint('alarming', 'test_id') + + # If authenticated generate and send response message + if auth_token is not None and endpoint is not None: + url = "{}/v2/alarms/%s".format(endpoint) % alarm_id + + # Get the resource_id of the triggered alarm and the date + result = Common.perform_request( + url, auth_token, req_type="get") + alarm_details = json.loads(result.text) + gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule'] + resource_id = gnocchi_rule['resource_id'] + # Mock a date for testing purposes + a_date = "dd-mm-yyyy 00:00" + + # Process an alarm notification if resource_id is valid + if resource_id is not None: + # Try generate and send response + try: + resp_message = self._response.generate_response( + 'notify_alarm', a_id=alarm_id, + r_id=resource_id, + sev=values['severity'], date=a_date, + state=values['current'], vim_type="OpenStack") + self._producer.notify_alarm( + 'notify_alarm', resp_message, 'alarm_response') + except Exception: + pass + + +def get_free_port(): + """Function to get a free port to run the test webserver on.""" + s = socket.socket(socket.AF_INET, type=socket.SOCK_STREAM) + s.bind(('localhost', 0)) + address, port = s.getsockname() + s.close() + return port + + +# Create the webserver, port and run it on its own thread +mock_server_port = get_free_port() +mock_server = HTTPServer(('localhost', mock_server_port), MockNotifierHandler) +mock_server_thread = Thread(target=mock_server.serve_forever) +mock_server_thread.setDaemon(True) +mock_server_thread.start() + + +def test_do_get(): + """Integration test for get request on notifier webserver.""" + url = 'http://localhost:{port}/users'.format(port=mock_server_port) + + # Send a request to the mock API server and store the response. + response = requests.get(url) + + # Confirm that the request-response cycle completed successfully. + assert response.ok + + +class AlarmNotificationTest(unittest.TestCase): + @mock.patch.object(KafkaProducer, "notify_alarm") + @mock.patch.object(OpenStack_Response, "generate_response") + @mock.patch.object(Common, "perform_request") + @mock.patch.object(Common, "get_endpoint") + @mock.patch.object(Common, "get_auth_token") + def test_post_notify_alarm(self, auth, endpoint, perf_req, resp, notify): + """Integration test for notify_alarm.""" + url = 'http://localhost:{port}/users'.format(port=mock_server_port) + payload = {"severity": "critical", + "alarm_name": "my_alarm", + "current": "current_state", + "alarm_id": "my_alarm_id", + "reason": "Threshold has been broken", + "reason_data": {"count": 1, + "most_recent": "null", + "type": "threshold", + "disposition": "unknown"}, + "previous": "previous_state"} + + # Mock authenticate and request response for testing + auth.return_value = "my_auth_token" + endpoint.return_value = "my_endpoint" + perf_req.return_value = MockResponse(valid_get_resp) + + # Generate a post request for testing + response = requests.post(url, json.dumps(payload)) + self.assertEqual(response.status_code, 200) + # A response message is generated with the following details + resp.assert_called_with( + "notify_alarm", a_id="my_alarm_id", r_id="my_resource_id", + sev="critical", date='dd-mm-yyyy 00:00', state="current_state", + vim_type="OpenStack") + + # Response message is sent back to the SO via MON's producer + notify.assert_called_with("notify_alarm", mock.ANY, "alarm_response") diff --git a/osm_mon/test/OpenStack/integration/test_vim_account.py b/osm_mon/test/OpenStack/integration/test_vim_account.py new file mode 100644 index 0000000..da34bb2 --- /dev/null +++ b/osm_mon/test/OpenStack/integration/test_vim_account.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Whitestack, LLC +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Whitestack, LLC + +# 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: bdiaz@whitestack.com or glavado@whitestack.com +## + +"""Test an end to end Openstack vim_account requests.""" + +import json +import logging +import unittest + +from osm_mon.core.auth import AuthManager +from osm_mon.core.database import DatabaseManager + +log = logging.getLogger(__name__) + + +class VimAccountTest(unittest.TestCase): + def setUp(self): + self.auth_manager = AuthManager() + self.database_manager = DatabaseManager() + self.database_manager.create_tables() + + def test_create_edit_delete_vim_account(self): + """Test vim_account creation message from KafkaProducer.""" + # Set-up message, producer and consumer for tests + create_payload = { + "_id": "test_id", + "name": "test_name", + "vim_type": "openstack", + "vim_url": "auth_url", + "vim_user": "user", + "vim_password": "password", + "vim_tenant_name": "tenant", + "config": + { + "foo": "bar" + } + } + self.auth_manager.store_auth_credentials(create_payload) + + creds = self.auth_manager.get_credentials('test_id') + + self.assertIsNotNone(creds) + self.assertEqual(creds.name, create_payload['name']) + self.assertEqual(json.loads(creds.config), create_payload['config']) + + # Set-up message, producer and consumer for tests + edit_payload = { + "_id": "test_id", + "name": "test_name_edited", + "vim_type": "openstack", + "vim_url": "auth_url", + "vim_user": "user", + "vim_password": "password", + "vim_tenant_name": "tenant", + "config": + { + "foo_edited": "bar_edited" + } + } + + self.auth_manager.store_auth_credentials(edit_payload) + + creds = self.auth_manager.get_credentials('test_id') + + self.assertEqual(creds.name, edit_payload['name']) + self.assertEqual(json.loads(creds.config), edit_payload['config']) + + delete_payload = { + "_id": "test_id" + } + + self.auth_manager.delete_auth_credentials(delete_payload) + + creds = self.auth_manager.get_credentials('test_id') + self.assertIsNone(creds) diff --git a/osm_mon/test/OpenStack/test_alarm_req.py b/osm_mon/test/OpenStack/test_alarm_req.py deleted file mode 100644 index 15cf63b..0000000 --- a/osm_mon/test/OpenStack/test_alarm_req.py +++ /dev/null @@ -1,148 +0,0 @@ -# Copyright 2017 iIntel Research and Development Ireland Limited -# ************************************************************** - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for all alarm request message keys.""" - -import json - -import logging - -import unittest - -import mock - -from osm_mon.core.auth import AuthManager -from osm_mon.core.database import VimCredentials -from osm_mon.plugins.OpenStack.Aodh import alarming as alarm_req -from osm_mon.plugins.OpenStack.common import Common - -log = logging.getLogger(__name__) - -mock_creds = VimCredentials() -mock_creds.config = '{}' - - -class Message(object): - """A class to mock a message object value for alarm requests.""" - - def __init__(self): - """Initialize a mocked message instance.""" - self.topic = 'alarm_request' - self.key = None - self.value = json.dumps({'vim_uuid': 'test_id', 'mock_value': 'mock_details'}) - - -class TestAlarmKeys(unittest.TestCase): - """Integration test for alarm request keys.""" - - def setUp(self): - """Setup the tests for alarm request keys.""" - super(TestAlarmKeys, self).setUp() - self.alarming = alarm_req.Alarming() - self.alarming.common = Common() - - @mock.patch.object(AuthManager, 'get_credentials') - @mock.patch.object(Common, 'get_endpoint') - @mock.patch.object(Common, 'get_auth_token') - def test_alarming_authentication(self, get_token, get_endpoint, get_creds): - """Test getting an auth_token and endpoint for alarm requests.""" - # if auth_token is None environment variables are used to authenticate - message = Message() - - get_creds.return_value = mock_creds - - self.alarming.alarming(message) - - get_token.assert_called_with('test_id') - get_endpoint.assert_any_call('alarming', 'test_id') - - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(Common, 'get_auth_token', mock.Mock()) - @mock.patch.object(AuthManager, 'get_credentials') - @mock.patch.object(alarm_req.Alarming, 'delete_alarm') - def test_delete_alarm_key(self, del_alarm, get_creds): - """Test the functionality for a create alarm request.""" - # Mock a message value and key - message = Message() - message.key = 'delete_alarm_request' - message.value = json.dumps({'vim_uuid': 'test_id', - 'alarm_delete_request': - {'alarm_uuid': 'my_alarm_id'}}) - - get_creds.return_value = mock_creds - - # Call the alarming functionality and check delete request - self.alarming.alarming(message) - del_alarm.assert_called_with(mock.ANY, mock.ANY, 'my_alarm_id') - - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(Common, 'get_auth_token', mock.Mock()) - @mock.patch.object(AuthManager, 'get_credentials') - @mock.patch.object(alarm_req.Alarming, 'list_alarms') - def test_list_alarm_key(self, list_alarm, get_creds): - """Test the functionality for a list alarm request.""" - # Mock a message with list alarm key and value - message = Message() - message.key = 'list_alarm_request' - message.value = json.dumps({'vim_uuid': 'test_id', 'alarm_list_request': 'my_alarm_details'}) - - get_creds.return_value = mock_creds - - # Call the alarming functionality and check list functionality - self.alarming.alarming(message) - list_alarm.assert_called_with(mock.ANY, mock.ANY, 'my_alarm_details') - - @mock.patch.object(Common, 'get_auth_token', mock.Mock()) - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(AuthManager, 'get_credentials') - @mock.patch.object(alarm_req.Alarming, 'update_alarm_state') - def test_ack_alarm_key(self, ack_alarm, get_creds): - """Test the functionality for an acknowledge alarm request.""" - # Mock a message with acknowledge alarm key and value - message = Message() - message.key = 'acknowledge_alarm' - message.value = json.dumps({'vim_uuid': 'test_id', - 'ack_details': - {'alarm_uuid': 'my_alarm_id'}}) - - get_creds.return_value = mock_creds - - # Call alarming functionality and check acknowledge functionality - self.alarming.alarming(message) - ack_alarm.assert_called_with(mock.ANY, mock.ANY, 'my_alarm_id') - - @mock.patch.object(Common, 'get_auth_token', mock.Mock()) - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(AuthManager, 'get_credentials') - @mock.patch.object(alarm_req.Alarming, 'configure_alarm') - def test_config_alarm_key(self, config_alarm, get_creds): - """Test the functionality for a create alarm request.""" - # Mock a message with config alarm key and value - message = Message() - message.key = 'create_alarm_request' - message.value = json.dumps({'vim_uuid': 'test_id', 'alarm_create_request': 'alarm_details'}) - - get_creds.return_value = mock_creds - - # Call alarming functionality and check config alarm call - config_alarm.return_value = 'my_alarm_id', True - self.alarming.alarming(message) - config_alarm.assert_called_with(mock.ANY, mock.ANY, mock.ANY, 'alarm_details', {}) diff --git a/osm_mon/test/OpenStack/test_alarming.py b/osm_mon/test/OpenStack/test_alarming.py deleted file mode 100644 index 5726f69..0000000 --- a/osm_mon/test/OpenStack/test_alarming.py +++ /dev/null @@ -1,283 +0,0 @@ -# Copyright 2017 iIntel Research and Development Ireland Limited -# ************************************************************** - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for all alarm request message keys.""" - -import json -import logging -import unittest - -import mock - -from osm_mon.core.settings import Config -from osm_mon.plugins.OpenStack.Aodh import alarming as alarm_req -from osm_mon.plugins.OpenStack.common import Common - -log = logging.getLogger(__name__) - -auth_token = mock.ANY -alarm_endpoint = "alarm_endpoint" -metric_endpoint = "metric_endpoint" - - -class Response(object): - """Mock a response message class.""" - - def __init__(self, result): - """Initialise the response text and status code.""" - self.text = json.dumps(result) - self.status_code = "MOCK_STATUS_CODE" - - -class TestAlarming(unittest.TestCase): - """Tests for alarming class functions.""" - - maxDiff = None - - def setUp(self): - """Setup for tests.""" - super(TestAlarming, self).setUp() - self.alarming = alarm_req.Alarming() - - @mock.patch.object(alarm_req.Alarming, "check_payload") - @mock.patch.object(alarm_req.Alarming, "check_for_metric") - @mock.patch.object(Common, "perform_request") - def test_config_invalid_alarm_req(self, perf_req, check_metric, check_pay): - """Test configure an invalid alarm request.""" - # Configuring with invalid alarm name results in failure - values = {"alarm_name": "my_alarm", - "metric_name": "my_metric", - "resource_uuid": "my_r_id"} - self.alarming.configure_alarm(alarm_endpoint, metric_endpoint, auth_token, values, {}) - perf_req.assert_not_called() - perf_req.reset_mock() - - # Correct alarm_name will check for metric in Gnocchi - # If there isn't one an alarm won;t be created - values = {"alarm_name": "disk_write_ops", - "metric_name": "disk_write_ops", - "resource_uuid": "my_r_id"} - - check_metric.return_value = None - - self.alarming.configure_alarm(alarm_endpoint, metric_endpoint, auth_token, values, {}) - perf_req.assert_not_called() - - @mock.patch.object(alarm_req.Alarming, "check_payload") - @mock.patch.object(alarm_req.Alarming, "check_for_metric") - @mock.patch.object(Common, "perform_request") - def test_config_valid_alarm_req(self, perf_req, check_metric, check_pay): - """Test config a valid alarm.""" - # Correct alarm_name will check for metric in Gnocchi - # And conform that the payload is configured correctly - values = {"alarm_name": "disk_write_ops", - "metric_name": "disk_write_ops", - "resource_uuid": "my_r_id"} - - check_metric.return_value = "my_metric_id" - check_pay.return_value = "my_payload" - - self.alarming.configure_alarm(alarm_endpoint, metric_endpoint, auth_token, values, {}) - perf_req.assert_called_with( - "alarm_endpoint/v2/alarms/", auth_token, - req_type="post", payload="my_payload") - - @mock.patch.object(Common, "perform_request") - def test_delete_alarm_req(self, perf_req): - """Test delete alarm request.""" - self.alarming.delete_alarm(alarm_endpoint, auth_token, "my_alarm_id") - - perf_req.assert_called_with( - "alarm_endpoint/v2/alarms/my_alarm_id", auth_token, req_type="delete") - - @mock.patch.object(Common, "perform_request") - def test_invalid_list_alarm_req(self, perf_req): - """Test invalid list alarm_req.""" - # Request will not be performed with out a resoure_id - list_details = {"mock_details": "invalid_details"} - self.alarming.list_alarms(alarm_endpoint, auth_token, list_details) - - perf_req.assert_not_called() - - @mock.patch.object(Common, "perform_request") - def test_valid_list_alarm_req(self, perf_req): - """Test valid list alarm request.""" - # Minimum requirement for an alarm list is resource_id - list_details = {"resource_uuid": "mock_r_id"} - self.alarming.list_alarms(alarm_endpoint, auth_token, list_details) - - perf_req.assert_called_with( - "alarm_endpoint/v2/alarms/", auth_token, req_type="get") - perf_req.reset_mock() - - # Check list with alarm_name defined - list_details = {"resource_uuid": "mock_r_id", - "alarm_name": "my_alarm", - "severity": "critical"} - self.alarming.list_alarms(alarm_endpoint, auth_token, list_details) - - perf_req.assert_called_with( - "alarm_endpoint/v2/alarms/", auth_token, req_type="get") - - @mock.patch.object(Common, "perform_request") - def test_ack_alarm_req(self, perf_req): - """Test update alarm state for acknowledge alarm request.""" - self.alarming.update_alarm_state(alarm_endpoint, auth_token, "my_alarm_id") - - perf_req.assert_called_with( - "alarm_endpoint/v2/alarms/my_alarm_id/state", auth_token, req_type="put", - payload=json.dumps("ok")) - - @mock.patch.object(alarm_req.Alarming, "check_payload") - @mock.patch.object(Common, "perform_request") - def test_update_alarm_invalid(self, perf_req, check_pay): - """Test update alarm with invalid get response.""" - values = {"alarm_uuid": "my_alarm_id"} - - self.alarming.update_alarm(alarm_endpoint, auth_token, values, {}) - - perf_req.assert_called_with(mock.ANY, auth_token, req_type="get") - check_pay.assert_not_called() - - @mock.patch.object(alarm_req.Alarming, "check_payload") - @mock.patch.object(Common, "perform_request") - def test_update_alarm_invalid_payload(self, perf_req, check_pay): - """Test update alarm with invalid payload.""" - resp = Response({"name": "my_alarm", - "state": "alarm", - "gnocchi_resources_threshold_rule": - {"resource_id": "my_resource_id", - "metric": "my_metric"}}) - perf_req.return_value = resp - check_pay.return_value = None - values = {"alarm_uuid": "my_alarm_id"} - - self.alarming.update_alarm(alarm_endpoint, auth_token, values, {}) - - perf_req.assert_called_with(mock.ANY, auth_token, req_type="get") - self.assertEqual(perf_req.call_count, 1) - - @mock.patch.object(alarm_req.Alarming, "check_payload") - @mock.patch.object(Common, "perform_request") - def test_update_alarm_valid(self, perf_req, check_pay): - """Test valid update alarm request.""" - resp = Response({"name": "my_alarm", - "state": "alarm", - "gnocchi_resources_threshold_rule": - {"resource_id": "my_resource_id", - "metric": "disk.write.requests"}}) - perf_req.return_value = resp - values = {"alarm_uuid": "my_alarm_id"} - - self.alarming.update_alarm(alarm_endpoint, auth_token, values, {}) - - check_pay.assert_called_with(values, "disk_write_ops", "my_resource_id", - "my_alarm", alarm_state="alarm") - - self.assertEqual(perf_req.call_count, 2) - # Second call is the update request - perf_req.assert_called_with( - 'alarm_endpoint/v2/alarms/my_alarm_id', auth_token, - req_type="put", payload=check_pay.return_value) - - @mock.patch.object(Config, "instance") - def test_check_valid_payload(self, cfg): - """Test the check payload function for a valid payload.""" - values = {"severity": "warning", - "statistic": "COUNT", - "threshold_value": 12, - "operation": "GT", - "granularity": 300, - "resource_type": "generic"} - cfg.return_value.OS_NOTIFIER_URI = "http://localhost:8662" - payload = self.alarming.check_payload( - values, "disk_write_ops", "r_id", "alarm_name") - - self.assertDictEqual( - json.loads(payload), {"name": "alarm_name", - "gnocchi_resources_threshold_rule": - {"resource_id": "r_id", - "metric": "disk.write.requests", - "comparison_operator": "gt", - "aggregation_method": "count", - "threshold": 12, - "granularity": 300, - "resource_type": "generic"}, - "severity": "low", - "state": "ok", - "type": "gnocchi_resources_threshold", - "alarm_actions": ["http://localhost:8662"]}) - - @mock.patch.object(Config, "instance") - @mock.patch.object(Common, "perform_request") - def test_check_valid_state_payload(self, perform_req, cfg): - """Test the check payload function for a valid payload with state.""" - values = {"severity": "warning", - "statistic": "COUNT", - "threshold_value": 12, - "operation": "GT", - "granularity": 300, - "resource_type": "generic"} - cfg.return_value.OS_NOTIFIER_URI = "http://localhost:8662" - payload = self.alarming.check_payload( - values, "disk_write_ops", "r_id", "alarm_name", alarm_state="alarm") - - self.assertEqual( - json.loads(payload), {"name": "alarm_name", - "gnocchi_resources_threshold_rule": - {"resource_id": "r_id", - "metric": "disk.write.requests", - "comparison_operator": "gt", - "aggregation_method": "count", - "threshold": 12, - "granularity": 300, - "resource_type": "generic"}, - "severity": "low", - "state": "alarm", - "type": "gnocchi_resources_threshold", - "alarm_actions": ["http://localhost:8662"]}) - - def test_check_invalid_payload(self): - """Test the check payload function for an invalid payload.""" - values = {"alarm_values": "mock_invalid_details"} - payload = self.alarming.check_payload( - values, "my_metric", "r_id", "alarm_name") - - self.assertEqual(payload, None) - - @mock.patch.object(Common, "perform_request") - def test_get_alarm_state(self, perf_req): - """Test the get alarm state function.""" - self.alarming.get_alarm_state(alarm_endpoint, auth_token, "alarm_id") - - perf_req.assert_called_with( - "alarm_endpoint/v2/alarms/alarm_id/state", auth_token, req_type="get") - - @mock.patch.object(Common, "get_endpoint") - @mock.patch.object(Common, "perform_request") - def test_check_for_metric(self, perf_req, get_endpoint): - """Test the check for metric function.""" - get_endpoint.return_value = "gnocchi_endpoint" - - self.alarming.check_for_metric(auth_token, metric_endpoint, "metric_name", "r_id") - - perf_req.assert_called_with( - "metric_endpoint/v1/metric?sort=name:asc", auth_token, req_type="get") diff --git a/osm_mon/test/OpenStack/test_common.py b/osm_mon/test/OpenStack/test_common.py deleted file mode 100644 index 042d15b..0000000 --- a/osm_mon/test/OpenStack/test_common.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2017 Intel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for all common OpenStack methods.""" - -import json -import logging -import unittest - -import mock -import requests -from keystoneclient.v3 import client - -from osm_mon.core.auth import AuthManager -from osm_mon.core.database import VimCredentials -from osm_mon.core.settings import Config -from osm_mon.plugins.OpenStack.common import Common - -__author__ = "Helena McGough" - -log = logging.getLogger(__name__) - - -class Message(object): - """Mock a message for an access credentials request.""" - - def __init__(self): - """Initialise the topic and value of access_cred message.""" - self.topic = "access_credentials" - self.value = json.dumps({"mock_value": "mock_details", - "vim_type": "OPENSTACK", - "access_config": - {"openstack_site": "my_site", - "user": "my_user", - "password": "my_password", - "vim_tenant_name": "my_tenant"}}) - - -class TestCommon(unittest.TestCase): - """Test the common class for OpenStack plugins.""" - - def setUp(self): - """Test Setup.""" - super(TestCommon, self).setUp() - self.common = Common() - self.creds = VimCredentials() - self.creds.id = 'test_id' - self.creds.user = 'user' - self.creds.url = 'url' - self.creds.password = 'password' - self.creds.tenant_name = 'tenant_name' - - @mock.patch.object(AuthManager, "get_credentials") - @mock.patch.object(Config, "instance") - @mock.patch.object(client, "Client") - def test_get_auth_token(self, key_client, cfg, get_creds): - """Test generating a new authentication token.""" - get_creds.return_value = self.creds - Common.get_auth_token('test_id') - get_creds.assert_called_with('test_id') - key_client.assert_called_with(auth_url='url', password='password', tenant_name='tenant_name', username='user') - - @mock.patch.object(requests, 'post') - def test_post_req(self, post): - """Testing a post request.""" - Common.perform_request("url", "auth_token", req_type="post", - payload="payload") - - post.assert_called_with("url", data="payload", headers=mock.ANY, - timeout=mock.ANY) - - @mock.patch.object(requests, 'get') - def test_get_req(self, get): - """Testing a get request.""" - # Run the defualt get request without any parameters - Common.perform_request("url", "auth_token", req_type="get") - - get.assert_called_with("url", params=None, headers=mock.ANY, - timeout=mock.ANY) - - # Test with some parameters specified - get.reset_mock() - Common.perform_request("url", "auth_token", req_type="get", - params="some parameters") - - get.assert_called_with("url", params="some parameters", - headers=mock.ANY, timeout=mock.ANY) - - @mock.patch.object(requests, 'put') - def test_put_req(self, put): - """Testing a put request.""" - Common.perform_request("url", "auth_token", req_type="put", - payload="payload") - put.assert_called_with("url", data="payload", headers=mock.ANY, - timeout=mock.ANY) - - @mock.patch.object(requests, 'delete') - def test_delete_req(self, delete): - """Testing a delete request.""" - Common.perform_request("url", "auth_token", req_type="delete") - - delete.assert_called_with("url", headers=mock.ANY, timeout=mock.ANY) diff --git a/osm_mon/test/OpenStack/test_metric_calls.py b/osm_mon/test/OpenStack/test_metric_calls.py deleted file mode 100644 index 51282b1..0000000 --- a/osm_mon/test/OpenStack/test_metric_calls.py +++ /dev/null @@ -1,337 +0,0 @@ -# Copyright 2017 iIntel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for all metric request message keys.""" - -import json - -import logging - -import unittest - -import mock - -from osm_mon.plugins.OpenStack.Gnocchi import metrics as metric_req - -from osm_mon.plugins.OpenStack.common import Common - -log = logging.getLogger(__name__) - -# Mock auth_token and endpoint -endpoint = mock.ANY -auth_token = mock.ANY - -# Mock a valid metric list for some tests, and a resultant list -metric_list = [{"name": "disk.write.requests", - "id": "metric_id", - "unit": "units", - "resource_id": "r_id"}] -result_list = ["metric_id", "r_id", "units", "disk_write_ops"] - - -class Response(object): - """Mock a response object for requests.""" - - def __init__(self): - """Initialise test and status code values.""" - self.text = json.dumps([{"id": "test_id"}]) - self.status_code = "STATUS_CODE" - - -def perform_request_side_effect(*args, **kwargs): - resp = Response() - if 'marker' in args[0]: - resp.text = json.dumps([]) - return resp - - -class TestMetricCalls(unittest.TestCase): - """Integration test for metric request keys.""" - - def setUp(self): - """Setup the tests for metric request keys.""" - super(TestMetricCalls, self).setUp() - self.metrics = metric_req.Metrics() - self.metrics._common = Common() - - @mock.patch.object(metric_req.Metrics, "get_metric_name") - @mock.patch.object(metric_req.Metrics, "get_metric_id") - @mock.patch.object(Common, "perform_request") - def test_invalid_config_metric_req( - self, perf_req, get_metric, get_metric_name): - """Test the configure metric function, for an invalid metric.""" - # Test invalid configuration for creating a metric - values = {"metric_details": "invalid_metric"} - - m_id, r_id, status = self.metrics.configure_metric( - endpoint, auth_token, values) - - perf_req.assert_not_called() - self.assertEqual(m_id, None) - self.assertEqual(r_id, None) - self.assertEqual(status, False) - - # Test with an invalid metric name, will not perform request - values = {"resource_uuid": "r_id"} - get_metric_name.return_value = "metric_name", None - - m_id, r_id, status = self.metrics.configure_metric( - endpoint, auth_token, values) - - perf_req.assert_not_called() - self.assertEqual(m_id, None) - self.assertEqual(r_id, "r_id") - self.assertEqual(status, False) - get_metric_name.reset_mock() - - # If metric exists, it won't be recreated - get_metric_name.return_value = "metric_name", "norm_name" - get_metric.return_value = "metric_id" - - m_id, r_id, status = self.metrics.configure_metric( - endpoint, auth_token, values) - - perf_req.assert_not_called() - self.assertEqual(m_id, "metric_id") - self.assertEqual(r_id, "r_id") - self.assertEqual(status, False) - - @mock.patch.object(metric_req.Metrics, "get_metric_name") - @mock.patch.object(metric_req.Metrics, "get_metric_id") - @mock.patch.object(Common, "perform_request") - def test_valid_config_metric_req( - self, perf_req, get_metric, get_metric_name): - """Test the configure metric function, for a valid metric.""" - # Test valid configuration and payload for creating a metric - values = {"resource_uuid": "r_id", - "metric_unit": "units"} - get_metric_name.return_value = "norm_name", "metric_name" - get_metric.return_value = None - payload = {"id": "r_id", - "metrics": {"metric_name": - {"archive_policy_name": "high", - "name": "metric_name", - "unit": "units"}}} - - self.metrics.configure_metric(endpoint, auth_token, values) - - perf_req.assert_called_with( - "/v1/resource/generic", auth_token, req_type="post", - payload=json.dumps(payload)) - - @mock.patch.object(Common, "perform_request") - def test_delete_metric_req(self, perf_req): - """Test the delete metric function.""" - self.metrics.delete_metric(endpoint, auth_token, "metric_id") - - perf_req.assert_called_with( - "/v1/metric/metric_id", auth_token, req_type="delete") - - @mock.patch.object(Common, "perform_request") - def test_delete_metric_invalid_status(self, perf_req): - """Test invalid response for delete request.""" - perf_req.return_value = "404" - - status = self.metrics.delete_metric(endpoint, auth_token, "metric_id") - - self.assertEqual(status, False) - - @mock.patch.object(metric_req.Metrics, "response_list") - @mock.patch.object(Common, "perform_request") - def test_complete_list_metric_req(self, perf_req, resp_list): - """Test the complete list metric function.""" - # Test listing metrics without any configuration options - values = {} - perf_req.side_effect = perform_request_side_effect - self.metrics.list_metrics(endpoint, auth_token, values) - - perf_req.assert_any_call( - "/v1/metric?sort=name:asc", auth_token, req_type="get") - resp_list.assert_called_with([{u'id': u'test_id'}]) - - @mock.patch.object(metric_req.Metrics, "response_list") - @mock.patch.object(Common, "perform_request") - def test_resource_list_metric_req(self, perf_req, resp_list): - """Test the resource list metric function.""" - # Test listing metrics with a resource id specified - values = {"resource_uuid": "resource_id"} - perf_req.side_effect = perform_request_side_effect - self.metrics.list_metrics(endpoint, auth_token, values) - - perf_req.assert_any_call( - "/v1/metric?sort=name:asc", auth_token, req_type="get") - resp_list.assert_called_with( - [{u'id': u'test_id'}], resource="resource_id") - - @mock.patch.object(metric_req.Metrics, "response_list") - @mock.patch.object(Common, "perform_request") - def test_name_list_metric_req(self, perf_req, resp_list): - """Test the metric_name list metric function.""" - # Test listing metrics with a metric_name specified - values = {"metric_name": "disk_write_bytes"} - perf_req.side_effect = perform_request_side_effect - self.metrics.list_metrics(endpoint, auth_token, values) - - perf_req.assert_any_call( - "/v1/metric?sort=name:asc", auth_token, req_type="get") - resp_list.assert_called_with( - [{u'id': u'test_id'}], metric_name="disk_write_bytes") - - @mock.patch.object(metric_req.Metrics, "response_list") - @mock.patch.object(Common, "perform_request") - def test_combined_list_metric_req(self, perf_req, resp_list): - """Test the combined resource and metric list metric function.""" - # Test listing metrics with a resource id and metric name specified - - values = {"resource_uuid": "resource_id", - "metric_name": "packets_sent"} - perf_req.side_effect = perform_request_side_effect - self.metrics.list_metrics(endpoint, auth_token, values) - - perf_req.assert_any_call( - "/v1/metric?sort=name:asc", auth_token, req_type="get") - resp_list.assert_called_with( - [{u'id': u'test_id'}], resource="resource_id", - metric_name="packets_sent") - - @mock.patch.object(Common, "perform_request") - def test_get_metric_id(self, perf_req): - """Test get_metric_id function.""" - self.metrics.get_metric_id(endpoint, auth_token, "my_metric", "r_id") - - perf_req.assert_called_with( - "/v1/resource/generic/r_id", auth_token, req_type="get") - - def test_get_metric_name(self): - """Test the result from the get_metric_name function.""" - # test with a valid metric_name - values = {"metric_name": "disk_write_ops"} - - metric_name, norm_name = self.metrics.get_metric_name(values) - - self.assertEqual(metric_name, "disk_write_ops") - self.assertEqual(norm_name, "disk.write.requests") - - # test with an invalid metric name - values = {"metric_name": "my_invalid_metric"} - - metric_name, norm_name = self.metrics.get_metric_name(values) - - self.assertEqual(metric_name, "my_invalid_metric") - self.assertEqual(norm_name, None) - - @mock.patch.object(metric_req.Metrics, "get_metric_id") - @mock.patch.object(Common, "perform_request") - def test_valid_read_data_req(self, perf_req, get_metric): - """Test the read metric data function, for a valid call.""" - values = {"metric_name": "disk_write_ops", - "resource_uuid": "resource_id", - "collection_unit": "DAY", - "collection_period": 1} - - get_metric.return_value = "metric_id" - self.metrics.read_metric_data(endpoint, auth_token, values) - - perf_req.assert_called_once() - - @mock.patch.object(Common, "perform_request") - def test_invalid_read_data_req(self, perf_req): - """Test the read metric data function, for an invalid call.""" - # Teo empty lists wil be returned because the values are invalid - values = {} - - times, data = self.metrics.read_metric_data( - endpoint, auth_token, values) - - self.assertEqual(times, []) - self.assertEqual(data, []) - - def test_complete_response_list(self): - """Test the response list function for formating metric lists.""" - # Mock a list for testing purposes, with valid OSM metric - resp_list = self.metrics.response_list(metric_list) - - # Check for the expected values in the resulting list - for l in result_list: - self.assertIn(l, resp_list[0].values()) - - def test_name_response_list(self): - """Test the response list with metric name configured.""" - # Mock the metric name to test a metric name list - # Test with a name that is not in the list - invalid_name = "my_metric" - resp_list = self.metrics.response_list( - metric_list, metric_name=invalid_name) - - self.assertEqual(resp_list, []) - - # Test with a name on the list - valid_name = "disk_write_ops" - resp_list = self.metrics.response_list( - metric_list, metric_name=valid_name) - - # Check for the expected values in the resulting list - for l in result_list: - self.assertIn(l, resp_list[0].values()) - - def test_resource_response_list(self): - """Test the response list with resource_id configured.""" - # Mock a resource_id to test a resource list - # Test with resource not on the list - invalid_id = "mock_resource" - resp_list = self.metrics.response_list(metric_list, resource=invalid_id) - - self.assertEqual(resp_list, []) - - # Test with a resource on the list - valid_id = "r_id" - resp_list = self.metrics.response_list(metric_list, resource=valid_id) - - # Check for the expected values in the resulting list - for l in result_list: - self.assertIn(l, resp_list[0].values()) - - def test_combined_response_list(self): - """Test the response list function with resource_id and metric_name.""" - # Test for a combined resource and name list - # resource and name are on the list - valid_name = "disk_write_ops" - valid_id = "r_id" - resp_list = self.metrics.response_list( - metric_list, metric_name=valid_name, resource=valid_id) - - # Check for the expected values in the resulting list - for l in result_list: - self.assertIn(l, resp_list[0].values()) - - # resource not on list - invalid_id = "mock_resource" - resp_list = self.metrics.response_list( - metric_list, metric_name=valid_name, resource=invalid_id) - - self.assertEqual(resp_list, []) - - # metric name not on list - invalid_name = "mock_metric" - resp_list = self.metrics.response_list( - metric_list, metric_name=invalid_name, resource=valid_id) - - self.assertEqual(resp_list, []) diff --git a/osm_mon/test/OpenStack/test_metric_req.py b/osm_mon/test/OpenStack/test_metric_req.py deleted file mode 100644 index 0869b56..0000000 --- a/osm_mon/test/OpenStack/test_metric_req.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2017 iIntel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for all metric request message keys.""" - -import json - -import logging - -import unittest - -import mock - -from osm_mon.plugins.OpenStack.Gnocchi import metrics as metric_req - -from osm_mon.plugins.OpenStack.common import Common - -log = logging.getLogger(__name__) - - -class Message(object): - """A class to mock a message object value for metric requests.""" - - def __init__(self): - """Initialize a mocked message instance.""" - self.topic = "metric_request" - self.key = None - self.value = json.dumps({"vim_uuid": "test_id", "mock_message": "message_details"}) - - -class TestMetricReq(unittest.TestCase): - """Integration test for metric request keys.""" - - def setUp(self): - """Setup the tests for metric request keys.""" - super(TestMetricReq, self).setUp() - self.metrics = metric_req.Metrics() - - @mock.patch.object(Common, 'get_endpoint') - @mock.patch.object(Common, "get_auth_token") - def test_access_cred_metric_auth(self, get_token, get_endpoint): - """Test authentication with access credentials.""" - message = Message() - - self.metrics.metric_calls(message) - - get_token.assert_called_with('test_id') - get_endpoint.assert_any_call('metric', 'test_id') - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(metric_req.Metrics, "delete_metric") - @mock.patch.object(metric_req.Metrics, "get_metric_id") - def test_delete_metric_key(self, get_metric_id, del_metric): - """Test the functionality for a delete metric request.""" - # Mock a message value and key - message = Message() - message.key = "delete_metric_request" - message.value = json.dumps({"vim_uuid": "test_id", "metric_name": "disk_write_ops", "resource_uuid": "my_r_id"}) - - # Call the metric functionality and check delete request - get_metric_id.return_value = "my_metric_id" - self.metrics.metric_calls(message) - del_metric.assert_called_with(mock.ANY, mock.ANY, "my_metric_id") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(metric_req.Metrics, "list_metrics") - def test_list_metric_key(self, list_metrics): - """Test the functionality for a list metric request.""" - # Mock a message with list metric key and value - message = Message() - message.key = "list_metric_request" - message.value = json.dumps({"vim_uuid": "test_id", "metrics_list_request": "metric_details"}) - - # Call the metric functionality and check list functionality - self.metrics.metric_calls(message) - list_metrics.assert_called_with(mock.ANY, mock.ANY, "metric_details") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(metric_req.Metrics, "read_metric_data") - @mock.patch.object(metric_req.Metrics, "list_metrics") - @mock.patch.object(metric_req.Metrics, "delete_metric") - @mock.patch.object(metric_req.Metrics, "configure_metric") - def test_update_metric_key(self, config_metric, delete_metric, list_metrics, - read_data): - """Test the functionality for an update metric request.""" - # Mock a message with update metric key and value - message = Message() - message.key = "update_metric_request" - message.value = json.dumps({"vim_uuid": "test_id", - "metric_create": - {"metric_name": "my_metric", - "resource_uuid": "my_r_id"}}) - - # Call metric functionality and confirm no function is called - # Gnocchi does not support updating a metric configuration - self.metrics.metric_calls(message) - config_metric.assert_not_called() - list_metrics.assert_not_called() - delete_metric.assert_not_called() - read_data.assert_not_called() - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(metric_req.Metrics, "configure_metric") - def test_config_metric_key(self, config_metric): - """Test the functionality for a create metric request.""" - # Mock a message with create metric key and value - message = Message() - message.key = "create_metric_request" - message.value = json.dumps({"vim_uuid": "test_id", "metric_create": "metric_details"}) - - # Call metric functionality and check config metric - config_metric.return_value = "metric_id", "resource_id", True - self.metrics.metric_calls(message) - config_metric.assert_called_with(mock.ANY, mock.ANY, "metric_details") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, 'get_endpoint', mock.Mock()) - @mock.patch.object(metric_req.Metrics, "read_metric_data") - def test_read_data_key(self, read_data): - """Test the functionality for a read metric data request.""" - # Mock a message with a read data key and value - message = Message() - message.key = "read_metric_data_request" - message.value = json.dumps({"vim_uuid": "test_id", "alarm_uuid": "alarm_id"}) - - # Call metric functionality and check read data metrics - read_data.return_value = "time_stamps", "data_values" - self.metrics.metric_calls(message) - read_data.assert_called_with( - mock.ANY, mock.ANY, json.loads(message.value)) diff --git a/osm_mon/test/OpenStack/test_notifier.py b/osm_mon/test/OpenStack/test_notifier.py deleted file mode 100644 index 0f96e71..0000000 --- a/osm_mon/test/OpenStack/test_notifier.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright 2017 Intel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for all common OpenStack methods.""" - -import json -import unittest -from BaseHTTPServer import BaseHTTPRequestHandler - -import mock - -from osm_mon.core.message_bus.producer import KafkaProducer -from osm_mon.core.settings import Config -from osm_mon.plugins.OpenStack.Aodh.alarming import Alarming -from osm_mon.plugins.OpenStack.common import Common -from osm_mon.plugins.OpenStack.response import OpenStack_Response - -# Mock data from post request -post_data = json.dumps({"severity": "critical", - "alarm_name": "my_alarm", - "current": "current_state", - "alarm_id": "my_alarm_id", - "reason": "Threshold has been broken", - "reason_data": {"count": 1, - "most_recent": "null", - "type": "threshold", - "disposition": "unknown"}, - "previous": "previous_state"}) - -valid_get_resp = '{"gnocchi_resources_threshold_rule":\ - {"resource_id": "my_resource_id"}}' - -invalid_get_resp = '{"gnocchi_resources_threshold_rule":\ - {"resource_id": null}}' - -valid_notify_resp = '{"notify_details": {"status": "current_state",\ - "severity": "critical",\ - "resource_uuid": "my_resource_id",\ - "alarm_uuid": "my_alarm_id",\ - "vim_type": "OpenStack",\ - "start_date": "dd-mm-yyyy 00:00"},\ - "schema_version": "1.0",\ - "schema_type": "notify_alarm"}' - -invalid_notify_resp = '{"notify_details": {"invalid":"mock_details"}' - - -class Response(object): - """Mock a response class for generating responses.""" - - def __init__(self, text): - """Initialise a mock response with a text attribute.""" - self.text = text - - -class NotifierHandler(BaseHTTPRequestHandler): - """Mock the NotifierHandler class for testing purposes.""" - - def __init__(self, request, client_address, server): - """Initilase mock NotifierHandler.""" - self.request = request - self.client_address = client_address - self.server = server - self.setup() - try: - self.handle() - finally: - self.finish() - - def setup(self): - """Mock setup function.""" - pass - - def handle(self): - """Mock handle function.""" - pass - - def finish(self): - """Mock finish function.""" - pass - - def _set_headers(self): - """Mock getting the request headers.""" - pass - - def do_GET(self): - """Mock functionality for GET request.""" - self._set_headers() - pass - - def do_POST(self): - """Mock functionality for a POST request.""" - self._set_headers() - self.notify_alarm(json.loads(post_data)) - - def notify_alarm(self, values): - """Mock the notify_alarm functionality to generate a valid response.""" - config = Config.instance() - config.read_environ() - self._alarming = Alarming() - self._common = Common() - self._response = OpenStack_Response() - self._producer = KafkaProducer('alarm_response') - alarm_id = values['alarm_id'] - - vim_uuid = 'test_id' - - auth_token = Common.get_auth_token(vim_uuid) - endpoint = Common.get_endpoint("alarming", vim_uuid) - - # If authenticated generate and send response message - if auth_token is not None and endpoint is not None: - url = "{}/v2/alarms/%s".format(endpoint) % alarm_id - - # Get the resource_id of the triggered alarm and the date - result = Common.perform_request( - url, auth_token, req_type="get") - alarm_details = json.loads(result.text) - gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule'] - resource_id = gnocchi_rule['resource_id'] - a_date = "dd-mm-yyyy 00:00" - - # Process an alarm notification if resource_id is valid - if resource_id is not None: - # Try generate and send response - try: - resp_message = self._response.generate_response( - 'notify_alarm', a_id=alarm_id, - r_id=resource_id, - sev=values['severity'], date=a_date, - state=values['current'], vim_type="OpenStack") - self._producer.notify_alarm( - 'notify_alarm', resp_message, 'alarm_response') - except Exception: - pass - - -class TestNotifier(unittest.TestCase): - """Test the NotifierHandler class for requests from aodh.""" - - def setUp(self): - """Setup tests.""" - super(TestNotifier, self).setUp() - self.handler = NotifierHandler( - "mock_request", "mock_address", "mock_server") - - @mock.patch.object(NotifierHandler, "_set_headers") - def test_do_GET(self, set_head): - """Test do_GET, generates headers for get request.""" - self.handler.do_GET() - - set_head.assert_called_once() - - @mock.patch.object(NotifierHandler, "notify_alarm") - @mock.patch.object(NotifierHandler, "_set_headers") - def test_do_POST(self, set_head, notify): - """Test do_POST functionality for a POST request.""" - self.handler.do_POST() - - set_head.assert_called_once() - notify.assert_called_with(json.loads(post_data)) - - @mock.patch.object(Common, "get_endpoint") - @mock.patch.object(Common, "get_auth_token") - @mock.patch.object(Common, "perform_request") - def test_notify_alarm_unauth(self, perf_req, auth, endpoint): - """Test notify alarm when not authenticated with keystone.""" - # Response request will not be performed unless there is a valid - # auth_token and endpoint - # Invalid auth_token and endpoint - auth.return_value = None - endpoint.return_value = None - self.handler.notify_alarm(json.loads(post_data)) - - perf_req.assert_not_called() - - # Valid endpoint - auth.return_value = None - endpoint.return_value = "my_endpoint" - self.handler.notify_alarm(json.loads(post_data)) - - perf_req.assert_not_called() - - # Valid auth_token - auth.return_value = "my_auth_token" - endpoint.return_value = None - self.handler.notify_alarm(json.loads(post_data)) - - perf_req.assert_not_called() - - @mock.patch.object(Common, "get_endpoint") - @mock.patch.object(OpenStack_Response, "generate_response") - @mock.patch.object(Common, "get_auth_token") - @mock.patch.object(Common, "perform_request") - def test_notify_alarm_invalid_alarm(self, perf_req, auth, resp, endpoint): - """Test valid authentication, invalid alarm details.""" - # Mock valid auth_token and endpoint - auth.return_value = "my_auth_token" - endpoint.return_value = "my_endpoint" - perf_req.return_value = Response(invalid_get_resp) - - self.handler.notify_alarm(json.loads(post_data)) - - # Response is not generated - resp.assert_not_called() - - @mock.patch.object(KafkaProducer, "notify_alarm") - @mock.patch.object(Common, "get_endpoint") - @mock.patch.object(OpenStack_Response, "generate_response") - @mock.patch.object(Common, "get_auth_token") - @mock.patch.object(Common, "perform_request") - def test_notify_alarm_resp_call(self, perf_req, auth, response, endpoint, notify): - """Test notify_alarm tries to generate a response for SO.""" - # Mock valid auth token and endpoint, valid response from aodh - auth.return_value = "my_auth_token" - endpoint.returm_value = "my_endpoint" - perf_req.return_value = Response(valid_get_resp) - self.handler.notify_alarm(json.loads(post_data)) - - notify.assert_called() - response.assert_called_with('notify_alarm', a_id="my_alarm_id", - r_id="my_resource_id", sev="critical", - date="dd-mm-yyyy 00:00", - state="current_state", - vim_type="OpenStack") - - @mock.patch.object(Common, "get_endpoint") - @mock.patch.object(KafkaProducer, "notify_alarm") - @mock.patch.object(OpenStack_Response, "generate_response") - @mock.patch.object(Common, "get_auth_token") - @mock.patch.object(Common, "perform_request") - @unittest.skip("Schema validation not implemented yet.") - def test_notify_alarm_invalid_resp( - self, perf_req, auth, response, notify, endpoint): - """Test the notify_alarm function, sends response to the producer.""" - # Generate return values for valid notify_alarm operation - auth.return_value = "my_auth_token" - endpoint.return_value = "my_endpoint" - perf_req.return_value = Response(valid_get_resp) - response.return_value = invalid_notify_resp - - self.handler.notify_alarm(json.loads(post_data)) - - notify.assert_not_called() - - @mock.patch.object(Common, "get_endpoint") - @mock.patch.object(KafkaProducer, "notify_alarm") - @mock.patch.object(OpenStack_Response, "generate_response") - @mock.patch.object(Common, "get_auth_token") - @mock.patch.object(Common, "perform_request") - def test_notify_alarm_valid_resp( - self, perf_req, auth, response, notify, endpoint): - """Test the notify_alarm function, sends response to the producer.""" - # Generate return values for valid notify_alarm operation - auth.return_value = "my_auth_token" - endpoint.return_value = "my_endpoint" - perf_req.return_value = Response(valid_get_resp) - response.return_value = valid_notify_resp - - self.handler.notify_alarm(json.loads(post_data)) - - notify.assert_called_with( - "notify_alarm", valid_notify_resp, "alarm_response") diff --git a/osm_mon/test/OpenStack/test_responses.py b/osm_mon/test/OpenStack/test_responses.py deleted file mode 100644 index 6cf4e3f..0000000 --- a/osm_mon/test/OpenStack/test_responses.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright 2017 iIntel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Test that the correct responses are generated for each message.""" - -import logging - -import unittest - -import mock - -from osm_mon.plugins.OpenStack import response as resp - -log = logging.getLogger(__name__) - - -class TestOpenStackResponse(unittest.TestCase): - """Tests for responses generated by the OpenStack plugins.""" - - def setUp(self): - """Setup for testing OpenStack plugin responses.""" - super(TestOpenStackResponse, self).setUp() - self.plugin_resp = resp.OpenStack_Response() - - def test_invalid_key(self): - """Test if an invalid key is entered for a response.""" - message = self.plugin_resp.generate_response("mock_invalid_key") - self.assertEqual(message, None) - - @mock.patch.object( - resp.OpenStack_Response, "alarm_list_response") - def test_list_alarm_resp(self, alarm_list_resp): - """Test out a function call for a list alarm response.""" - message = self.plugin_resp.generate_response("list_alarm_response") - self.assertEqual(alarm_list_resp.return_value, message) - - @mock.patch.object( - resp.OpenStack_Response, "list_metric_response") - def test_list_metric_resp(self, metric_list_resp): - """Test list metric response function call.""" - message = self.plugin_resp.generate_response("list_metric_response") - self.assertEqual(message, metric_list_resp.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "delete_alarm_response") - def test_delete_alarm_resp(self, del_alarm_resp): - """Test delete alarm response function call.""" - message = self.plugin_resp.generate_response("delete_alarm_response") - self.assertEqual(message, del_alarm_resp.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "delete_metric_response") - def test_delete_metric_resp(self, del_metric_resp): - """Test the response functionality of delete metric response.""" - message = self.plugin_resp.generate_response("delete_metric_response") - self.assertEqual(message, del_metric_resp.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "create_alarm_response") - def test_create_alarm_resp(self, config_alarm_resp): - """Test create alarm response function call.""" - message = self.plugin_resp.generate_response("create_alarm_response") - self.assertEqual(message, config_alarm_resp.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "metric_create_response") - def test_create_metric_resp(self, config_metric_resp): - """Test create metric response function call.""" - message = self.plugin_resp.generate_response("create_metric_response") - self.assertEqual(message, config_metric_resp.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "update_alarm_response") - def test_update_alarm_resp(self, up_alarm_resp): - """Test update alarm response function call.""" - message = self.plugin_resp.generate_response("update_alarm_response") - self.assertEqual(message, up_alarm_resp.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "update_metric_response") - def test_update_metric_resp(self, up_metric_resp): - """Test update metric response function call.""" - message = self.plugin_resp.generate_response("update_metric_response") - self.assertEqual(message, up_metric_resp.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "notify_alarm") - def test_notify_alarm(self, notify_alarm): - """Test notify alarm response function call.""" - message = self.plugin_resp.generate_response("notify_alarm") - self.assertEqual(message, notify_alarm.return_value) - - @mock.patch.object( - resp.OpenStack_Response, "read_metric_data_response") - def test_read_metric_data_resp(self, read_data_resp): - """Test read metric data response function call.""" - message = self.plugin_resp.generate_response( - "read_metric_data_response") - self.assertEqual(message, read_data_resp.return_value) diff --git a/osm_mon/test/OpenStack/test_settings.py b/osm_mon/test/OpenStack/test_settings.py deleted file mode 100644 index 42619f8..0000000 --- a/osm_mon/test/OpenStack/test_settings.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2017 Intel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for settings for OpenStack plugins configurations.""" - -import logging -import os -import unittest - -from osm_mon.core.settings import Config - -log = logging.getLogger(__name__) - - -class TestSettings(unittest.TestCase): - """Test the settings class for OpenStack plugin configuration.""" - - def setUp(self): - """Test Setup.""" - super(TestSettings, self).setUp() - self.cfg = Config.instance() - - def test_set_os_username(self): - """Test reading the environment for OpenStack plugin configuration.""" - os.environ["OS_NOTIFIER_URI"] = "test" - self.cfg.read_environ() - - self.assertEqual(self.cfg.OS_NOTIFIER_URI, "test") diff --git a/osm_mon/test/OpenStack/unit/__init__.py b/osm_mon/test/OpenStack/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/osm_mon/test/OpenStack/unit/test_alarm_req.py b/osm_mon/test/OpenStack/unit/test_alarm_req.py new file mode 100644 index 0000000..15cf63b --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_alarm_req.py @@ -0,0 +1,148 @@ +# Copyright 2017 iIntel Research and Development Ireland Limited +# ************************************************************** + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for all alarm request message keys.""" + +import json + +import logging + +import unittest + +import mock + +from osm_mon.core.auth import AuthManager +from osm_mon.core.database import VimCredentials +from osm_mon.plugins.OpenStack.Aodh import alarming as alarm_req +from osm_mon.plugins.OpenStack.common import Common + +log = logging.getLogger(__name__) + +mock_creds = VimCredentials() +mock_creds.config = '{}' + + +class Message(object): + """A class to mock a message object value for alarm requests.""" + + def __init__(self): + """Initialize a mocked message instance.""" + self.topic = 'alarm_request' + self.key = None + self.value = json.dumps({'vim_uuid': 'test_id', 'mock_value': 'mock_details'}) + + +class TestAlarmKeys(unittest.TestCase): + """Integration test for alarm request keys.""" + + def setUp(self): + """Setup the tests for alarm request keys.""" + super(TestAlarmKeys, self).setUp() + self.alarming = alarm_req.Alarming() + self.alarming.common = Common() + + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(Common, 'get_endpoint') + @mock.patch.object(Common, 'get_auth_token') + def test_alarming_authentication(self, get_token, get_endpoint, get_creds): + """Test getting an auth_token and endpoint for alarm requests.""" + # if auth_token is None environment variables are used to authenticate + message = Message() + + get_creds.return_value = mock_creds + + self.alarming.alarming(message) + + get_token.assert_called_with('test_id') + get_endpoint.assert_any_call('alarming', 'test_id') + + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(Common, 'get_auth_token', mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(alarm_req.Alarming, 'delete_alarm') + def test_delete_alarm_key(self, del_alarm, get_creds): + """Test the functionality for a create alarm request.""" + # Mock a message value and key + message = Message() + message.key = 'delete_alarm_request' + message.value = json.dumps({'vim_uuid': 'test_id', + 'alarm_delete_request': + {'alarm_uuid': 'my_alarm_id'}}) + + get_creds.return_value = mock_creds + + # Call the alarming functionality and check delete request + self.alarming.alarming(message) + del_alarm.assert_called_with(mock.ANY, mock.ANY, 'my_alarm_id') + + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(Common, 'get_auth_token', mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(alarm_req.Alarming, 'list_alarms') + def test_list_alarm_key(self, list_alarm, get_creds): + """Test the functionality for a list alarm request.""" + # Mock a message with list alarm key and value + message = Message() + message.key = 'list_alarm_request' + message.value = json.dumps({'vim_uuid': 'test_id', 'alarm_list_request': 'my_alarm_details'}) + + get_creds.return_value = mock_creds + + # Call the alarming functionality and check list functionality + self.alarming.alarming(message) + list_alarm.assert_called_with(mock.ANY, mock.ANY, 'my_alarm_details') + + @mock.patch.object(Common, 'get_auth_token', mock.Mock()) + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(alarm_req.Alarming, 'update_alarm_state') + def test_ack_alarm_key(self, ack_alarm, get_creds): + """Test the functionality for an acknowledge alarm request.""" + # Mock a message with acknowledge alarm key and value + message = Message() + message.key = 'acknowledge_alarm' + message.value = json.dumps({'vim_uuid': 'test_id', + 'ack_details': + {'alarm_uuid': 'my_alarm_id'}}) + + get_creds.return_value = mock_creds + + # Call alarming functionality and check acknowledge functionality + self.alarming.alarming(message) + ack_alarm.assert_called_with(mock.ANY, mock.ANY, 'my_alarm_id') + + @mock.patch.object(Common, 'get_auth_token', mock.Mock()) + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(AuthManager, 'get_credentials') + @mock.patch.object(alarm_req.Alarming, 'configure_alarm') + def test_config_alarm_key(self, config_alarm, get_creds): + """Test the functionality for a create alarm request.""" + # Mock a message with config alarm key and value + message = Message() + message.key = 'create_alarm_request' + message.value = json.dumps({'vim_uuid': 'test_id', 'alarm_create_request': 'alarm_details'}) + + get_creds.return_value = mock_creds + + # Call alarming functionality and check config alarm call + config_alarm.return_value = 'my_alarm_id', True + self.alarming.alarming(message) + config_alarm.assert_called_with(mock.ANY, mock.ANY, mock.ANY, 'alarm_details', {}) diff --git a/osm_mon/test/OpenStack/unit/test_alarming.py b/osm_mon/test/OpenStack/unit/test_alarming.py new file mode 100644 index 0000000..5726f69 --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_alarming.py @@ -0,0 +1,283 @@ +# Copyright 2017 iIntel Research and Development Ireland Limited +# ************************************************************** + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for all alarm request message keys.""" + +import json +import logging +import unittest + +import mock + +from osm_mon.core.settings import Config +from osm_mon.plugins.OpenStack.Aodh import alarming as alarm_req +from osm_mon.plugins.OpenStack.common import Common + +log = logging.getLogger(__name__) + +auth_token = mock.ANY +alarm_endpoint = "alarm_endpoint" +metric_endpoint = "metric_endpoint" + + +class Response(object): + """Mock a response message class.""" + + def __init__(self, result): + """Initialise the response text and status code.""" + self.text = json.dumps(result) + self.status_code = "MOCK_STATUS_CODE" + + +class TestAlarming(unittest.TestCase): + """Tests for alarming class functions.""" + + maxDiff = None + + def setUp(self): + """Setup for tests.""" + super(TestAlarming, self).setUp() + self.alarming = alarm_req.Alarming() + + @mock.patch.object(alarm_req.Alarming, "check_payload") + @mock.patch.object(alarm_req.Alarming, "check_for_metric") + @mock.patch.object(Common, "perform_request") + def test_config_invalid_alarm_req(self, perf_req, check_metric, check_pay): + """Test configure an invalid alarm request.""" + # Configuring with invalid alarm name results in failure + values = {"alarm_name": "my_alarm", + "metric_name": "my_metric", + "resource_uuid": "my_r_id"} + self.alarming.configure_alarm(alarm_endpoint, metric_endpoint, auth_token, values, {}) + perf_req.assert_not_called() + perf_req.reset_mock() + + # Correct alarm_name will check for metric in Gnocchi + # If there isn't one an alarm won;t be created + values = {"alarm_name": "disk_write_ops", + "metric_name": "disk_write_ops", + "resource_uuid": "my_r_id"} + + check_metric.return_value = None + + self.alarming.configure_alarm(alarm_endpoint, metric_endpoint, auth_token, values, {}) + perf_req.assert_not_called() + + @mock.patch.object(alarm_req.Alarming, "check_payload") + @mock.patch.object(alarm_req.Alarming, "check_for_metric") + @mock.patch.object(Common, "perform_request") + def test_config_valid_alarm_req(self, perf_req, check_metric, check_pay): + """Test config a valid alarm.""" + # Correct alarm_name will check for metric in Gnocchi + # And conform that the payload is configured correctly + values = {"alarm_name": "disk_write_ops", + "metric_name": "disk_write_ops", + "resource_uuid": "my_r_id"} + + check_metric.return_value = "my_metric_id" + check_pay.return_value = "my_payload" + + self.alarming.configure_alarm(alarm_endpoint, metric_endpoint, auth_token, values, {}) + perf_req.assert_called_with( + "alarm_endpoint/v2/alarms/", auth_token, + req_type="post", payload="my_payload") + + @mock.patch.object(Common, "perform_request") + def test_delete_alarm_req(self, perf_req): + """Test delete alarm request.""" + self.alarming.delete_alarm(alarm_endpoint, auth_token, "my_alarm_id") + + perf_req.assert_called_with( + "alarm_endpoint/v2/alarms/my_alarm_id", auth_token, req_type="delete") + + @mock.patch.object(Common, "perform_request") + def test_invalid_list_alarm_req(self, perf_req): + """Test invalid list alarm_req.""" + # Request will not be performed with out a resoure_id + list_details = {"mock_details": "invalid_details"} + self.alarming.list_alarms(alarm_endpoint, auth_token, list_details) + + perf_req.assert_not_called() + + @mock.patch.object(Common, "perform_request") + def test_valid_list_alarm_req(self, perf_req): + """Test valid list alarm request.""" + # Minimum requirement for an alarm list is resource_id + list_details = {"resource_uuid": "mock_r_id"} + self.alarming.list_alarms(alarm_endpoint, auth_token, list_details) + + perf_req.assert_called_with( + "alarm_endpoint/v2/alarms/", auth_token, req_type="get") + perf_req.reset_mock() + + # Check list with alarm_name defined + list_details = {"resource_uuid": "mock_r_id", + "alarm_name": "my_alarm", + "severity": "critical"} + self.alarming.list_alarms(alarm_endpoint, auth_token, list_details) + + perf_req.assert_called_with( + "alarm_endpoint/v2/alarms/", auth_token, req_type="get") + + @mock.patch.object(Common, "perform_request") + def test_ack_alarm_req(self, perf_req): + """Test update alarm state for acknowledge alarm request.""" + self.alarming.update_alarm_state(alarm_endpoint, auth_token, "my_alarm_id") + + perf_req.assert_called_with( + "alarm_endpoint/v2/alarms/my_alarm_id/state", auth_token, req_type="put", + payload=json.dumps("ok")) + + @mock.patch.object(alarm_req.Alarming, "check_payload") + @mock.patch.object(Common, "perform_request") + def test_update_alarm_invalid(self, perf_req, check_pay): + """Test update alarm with invalid get response.""" + values = {"alarm_uuid": "my_alarm_id"} + + self.alarming.update_alarm(alarm_endpoint, auth_token, values, {}) + + perf_req.assert_called_with(mock.ANY, auth_token, req_type="get") + check_pay.assert_not_called() + + @mock.patch.object(alarm_req.Alarming, "check_payload") + @mock.patch.object(Common, "perform_request") + def test_update_alarm_invalid_payload(self, perf_req, check_pay): + """Test update alarm with invalid payload.""" + resp = Response({"name": "my_alarm", + "state": "alarm", + "gnocchi_resources_threshold_rule": + {"resource_id": "my_resource_id", + "metric": "my_metric"}}) + perf_req.return_value = resp + check_pay.return_value = None + values = {"alarm_uuid": "my_alarm_id"} + + self.alarming.update_alarm(alarm_endpoint, auth_token, values, {}) + + perf_req.assert_called_with(mock.ANY, auth_token, req_type="get") + self.assertEqual(perf_req.call_count, 1) + + @mock.patch.object(alarm_req.Alarming, "check_payload") + @mock.patch.object(Common, "perform_request") + def test_update_alarm_valid(self, perf_req, check_pay): + """Test valid update alarm request.""" + resp = Response({"name": "my_alarm", + "state": "alarm", + "gnocchi_resources_threshold_rule": + {"resource_id": "my_resource_id", + "metric": "disk.write.requests"}}) + perf_req.return_value = resp + values = {"alarm_uuid": "my_alarm_id"} + + self.alarming.update_alarm(alarm_endpoint, auth_token, values, {}) + + check_pay.assert_called_with(values, "disk_write_ops", "my_resource_id", + "my_alarm", alarm_state="alarm") + + self.assertEqual(perf_req.call_count, 2) + # Second call is the update request + perf_req.assert_called_with( + 'alarm_endpoint/v2/alarms/my_alarm_id', auth_token, + req_type="put", payload=check_pay.return_value) + + @mock.patch.object(Config, "instance") + def test_check_valid_payload(self, cfg): + """Test the check payload function for a valid payload.""" + values = {"severity": "warning", + "statistic": "COUNT", + "threshold_value": 12, + "operation": "GT", + "granularity": 300, + "resource_type": "generic"} + cfg.return_value.OS_NOTIFIER_URI = "http://localhost:8662" + payload = self.alarming.check_payload( + values, "disk_write_ops", "r_id", "alarm_name") + + self.assertDictEqual( + json.loads(payload), {"name": "alarm_name", + "gnocchi_resources_threshold_rule": + {"resource_id": "r_id", + "metric": "disk.write.requests", + "comparison_operator": "gt", + "aggregation_method": "count", + "threshold": 12, + "granularity": 300, + "resource_type": "generic"}, + "severity": "low", + "state": "ok", + "type": "gnocchi_resources_threshold", + "alarm_actions": ["http://localhost:8662"]}) + + @mock.patch.object(Config, "instance") + @mock.patch.object(Common, "perform_request") + def test_check_valid_state_payload(self, perform_req, cfg): + """Test the check payload function for a valid payload with state.""" + values = {"severity": "warning", + "statistic": "COUNT", + "threshold_value": 12, + "operation": "GT", + "granularity": 300, + "resource_type": "generic"} + cfg.return_value.OS_NOTIFIER_URI = "http://localhost:8662" + payload = self.alarming.check_payload( + values, "disk_write_ops", "r_id", "alarm_name", alarm_state="alarm") + + self.assertEqual( + json.loads(payload), {"name": "alarm_name", + "gnocchi_resources_threshold_rule": + {"resource_id": "r_id", + "metric": "disk.write.requests", + "comparison_operator": "gt", + "aggregation_method": "count", + "threshold": 12, + "granularity": 300, + "resource_type": "generic"}, + "severity": "low", + "state": "alarm", + "type": "gnocchi_resources_threshold", + "alarm_actions": ["http://localhost:8662"]}) + + def test_check_invalid_payload(self): + """Test the check payload function for an invalid payload.""" + values = {"alarm_values": "mock_invalid_details"} + payload = self.alarming.check_payload( + values, "my_metric", "r_id", "alarm_name") + + self.assertEqual(payload, None) + + @mock.patch.object(Common, "perform_request") + def test_get_alarm_state(self, perf_req): + """Test the get alarm state function.""" + self.alarming.get_alarm_state(alarm_endpoint, auth_token, "alarm_id") + + perf_req.assert_called_with( + "alarm_endpoint/v2/alarms/alarm_id/state", auth_token, req_type="get") + + @mock.patch.object(Common, "get_endpoint") + @mock.patch.object(Common, "perform_request") + def test_check_for_metric(self, perf_req, get_endpoint): + """Test the check for metric function.""" + get_endpoint.return_value = "gnocchi_endpoint" + + self.alarming.check_for_metric(auth_token, metric_endpoint, "metric_name", "r_id") + + perf_req.assert_called_with( + "metric_endpoint/v1/metric?sort=name:asc", auth_token, req_type="get") diff --git a/osm_mon/test/OpenStack/unit/test_common.py b/osm_mon/test/OpenStack/unit/test_common.py new file mode 100644 index 0000000..042d15b --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_common.py @@ -0,0 +1,120 @@ +# Copyright 2017 Intel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for all common OpenStack methods.""" + +import json +import logging +import unittest + +import mock +import requests +from keystoneclient.v3 import client + +from osm_mon.core.auth import AuthManager +from osm_mon.core.database import VimCredentials +from osm_mon.core.settings import Config +from osm_mon.plugins.OpenStack.common import Common + +__author__ = "Helena McGough" + +log = logging.getLogger(__name__) + + +class Message(object): + """Mock a message for an access credentials request.""" + + def __init__(self): + """Initialise the topic and value of access_cred message.""" + self.topic = "access_credentials" + self.value = json.dumps({"mock_value": "mock_details", + "vim_type": "OPENSTACK", + "access_config": + {"openstack_site": "my_site", + "user": "my_user", + "password": "my_password", + "vim_tenant_name": "my_tenant"}}) + + +class TestCommon(unittest.TestCase): + """Test the common class for OpenStack plugins.""" + + def setUp(self): + """Test Setup.""" + super(TestCommon, self).setUp() + self.common = Common() + self.creds = VimCredentials() + self.creds.id = 'test_id' + self.creds.user = 'user' + self.creds.url = 'url' + self.creds.password = 'password' + self.creds.tenant_name = 'tenant_name' + + @mock.patch.object(AuthManager, "get_credentials") + @mock.patch.object(Config, "instance") + @mock.patch.object(client, "Client") + def test_get_auth_token(self, key_client, cfg, get_creds): + """Test generating a new authentication token.""" + get_creds.return_value = self.creds + Common.get_auth_token('test_id') + get_creds.assert_called_with('test_id') + key_client.assert_called_with(auth_url='url', password='password', tenant_name='tenant_name', username='user') + + @mock.patch.object(requests, 'post') + def test_post_req(self, post): + """Testing a post request.""" + Common.perform_request("url", "auth_token", req_type="post", + payload="payload") + + post.assert_called_with("url", data="payload", headers=mock.ANY, + timeout=mock.ANY) + + @mock.patch.object(requests, 'get') + def test_get_req(self, get): + """Testing a get request.""" + # Run the defualt get request without any parameters + Common.perform_request("url", "auth_token", req_type="get") + + get.assert_called_with("url", params=None, headers=mock.ANY, + timeout=mock.ANY) + + # Test with some parameters specified + get.reset_mock() + Common.perform_request("url", "auth_token", req_type="get", + params="some parameters") + + get.assert_called_with("url", params="some parameters", + headers=mock.ANY, timeout=mock.ANY) + + @mock.patch.object(requests, 'put') + def test_put_req(self, put): + """Testing a put request.""" + Common.perform_request("url", "auth_token", req_type="put", + payload="payload") + put.assert_called_with("url", data="payload", headers=mock.ANY, + timeout=mock.ANY) + + @mock.patch.object(requests, 'delete') + def test_delete_req(self, delete): + """Testing a delete request.""" + Common.perform_request("url", "auth_token", req_type="delete") + + delete.assert_called_with("url", headers=mock.ANY, timeout=mock.ANY) diff --git a/osm_mon/test/OpenStack/unit/test_metric_calls.py b/osm_mon/test/OpenStack/unit/test_metric_calls.py new file mode 100644 index 0000000..51282b1 --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_metric_calls.py @@ -0,0 +1,337 @@ +# Copyright 2017 iIntel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for all metric request message keys.""" + +import json + +import logging + +import unittest + +import mock + +from osm_mon.plugins.OpenStack.Gnocchi import metrics as metric_req + +from osm_mon.plugins.OpenStack.common import Common + +log = logging.getLogger(__name__) + +# Mock auth_token and endpoint +endpoint = mock.ANY +auth_token = mock.ANY + +# Mock a valid metric list for some tests, and a resultant list +metric_list = [{"name": "disk.write.requests", + "id": "metric_id", + "unit": "units", + "resource_id": "r_id"}] +result_list = ["metric_id", "r_id", "units", "disk_write_ops"] + + +class Response(object): + """Mock a response object for requests.""" + + def __init__(self): + """Initialise test and status code values.""" + self.text = json.dumps([{"id": "test_id"}]) + self.status_code = "STATUS_CODE" + + +def perform_request_side_effect(*args, **kwargs): + resp = Response() + if 'marker' in args[0]: + resp.text = json.dumps([]) + return resp + + +class TestMetricCalls(unittest.TestCase): + """Integration test for metric request keys.""" + + def setUp(self): + """Setup the tests for metric request keys.""" + super(TestMetricCalls, self).setUp() + self.metrics = metric_req.Metrics() + self.metrics._common = Common() + + @mock.patch.object(metric_req.Metrics, "get_metric_name") + @mock.patch.object(metric_req.Metrics, "get_metric_id") + @mock.patch.object(Common, "perform_request") + def test_invalid_config_metric_req( + self, perf_req, get_metric, get_metric_name): + """Test the configure metric function, for an invalid metric.""" + # Test invalid configuration for creating a metric + values = {"metric_details": "invalid_metric"} + + m_id, r_id, status = self.metrics.configure_metric( + endpoint, auth_token, values) + + perf_req.assert_not_called() + self.assertEqual(m_id, None) + self.assertEqual(r_id, None) + self.assertEqual(status, False) + + # Test with an invalid metric name, will not perform request + values = {"resource_uuid": "r_id"} + get_metric_name.return_value = "metric_name", None + + m_id, r_id, status = self.metrics.configure_metric( + endpoint, auth_token, values) + + perf_req.assert_not_called() + self.assertEqual(m_id, None) + self.assertEqual(r_id, "r_id") + self.assertEqual(status, False) + get_metric_name.reset_mock() + + # If metric exists, it won't be recreated + get_metric_name.return_value = "metric_name", "norm_name" + get_metric.return_value = "metric_id" + + m_id, r_id, status = self.metrics.configure_metric( + endpoint, auth_token, values) + + perf_req.assert_not_called() + self.assertEqual(m_id, "metric_id") + self.assertEqual(r_id, "r_id") + self.assertEqual(status, False) + + @mock.patch.object(metric_req.Metrics, "get_metric_name") + @mock.patch.object(metric_req.Metrics, "get_metric_id") + @mock.patch.object(Common, "perform_request") + def test_valid_config_metric_req( + self, perf_req, get_metric, get_metric_name): + """Test the configure metric function, for a valid metric.""" + # Test valid configuration and payload for creating a metric + values = {"resource_uuid": "r_id", + "metric_unit": "units"} + get_metric_name.return_value = "norm_name", "metric_name" + get_metric.return_value = None + payload = {"id": "r_id", + "metrics": {"metric_name": + {"archive_policy_name": "high", + "name": "metric_name", + "unit": "units"}}} + + self.metrics.configure_metric(endpoint, auth_token, values) + + perf_req.assert_called_with( + "/v1/resource/generic", auth_token, req_type="post", + payload=json.dumps(payload)) + + @mock.patch.object(Common, "perform_request") + def test_delete_metric_req(self, perf_req): + """Test the delete metric function.""" + self.metrics.delete_metric(endpoint, auth_token, "metric_id") + + perf_req.assert_called_with( + "/v1/metric/metric_id", auth_token, req_type="delete") + + @mock.patch.object(Common, "perform_request") + def test_delete_metric_invalid_status(self, perf_req): + """Test invalid response for delete request.""" + perf_req.return_value = "404" + + status = self.metrics.delete_metric(endpoint, auth_token, "metric_id") + + self.assertEqual(status, False) + + @mock.patch.object(metric_req.Metrics, "response_list") + @mock.patch.object(Common, "perform_request") + def test_complete_list_metric_req(self, perf_req, resp_list): + """Test the complete list metric function.""" + # Test listing metrics without any configuration options + values = {} + perf_req.side_effect = perform_request_side_effect + self.metrics.list_metrics(endpoint, auth_token, values) + + perf_req.assert_any_call( + "/v1/metric?sort=name:asc", auth_token, req_type="get") + resp_list.assert_called_with([{u'id': u'test_id'}]) + + @mock.patch.object(metric_req.Metrics, "response_list") + @mock.patch.object(Common, "perform_request") + def test_resource_list_metric_req(self, perf_req, resp_list): + """Test the resource list metric function.""" + # Test listing metrics with a resource id specified + values = {"resource_uuid": "resource_id"} + perf_req.side_effect = perform_request_side_effect + self.metrics.list_metrics(endpoint, auth_token, values) + + perf_req.assert_any_call( + "/v1/metric?sort=name:asc", auth_token, req_type="get") + resp_list.assert_called_with( + [{u'id': u'test_id'}], resource="resource_id") + + @mock.patch.object(metric_req.Metrics, "response_list") + @mock.patch.object(Common, "perform_request") + def test_name_list_metric_req(self, perf_req, resp_list): + """Test the metric_name list metric function.""" + # Test listing metrics with a metric_name specified + values = {"metric_name": "disk_write_bytes"} + perf_req.side_effect = perform_request_side_effect + self.metrics.list_metrics(endpoint, auth_token, values) + + perf_req.assert_any_call( + "/v1/metric?sort=name:asc", auth_token, req_type="get") + resp_list.assert_called_with( + [{u'id': u'test_id'}], metric_name="disk_write_bytes") + + @mock.patch.object(metric_req.Metrics, "response_list") + @mock.patch.object(Common, "perform_request") + def test_combined_list_metric_req(self, perf_req, resp_list): + """Test the combined resource and metric list metric function.""" + # Test listing metrics with a resource id and metric name specified + + values = {"resource_uuid": "resource_id", + "metric_name": "packets_sent"} + perf_req.side_effect = perform_request_side_effect + self.metrics.list_metrics(endpoint, auth_token, values) + + perf_req.assert_any_call( + "/v1/metric?sort=name:asc", auth_token, req_type="get") + resp_list.assert_called_with( + [{u'id': u'test_id'}], resource="resource_id", + metric_name="packets_sent") + + @mock.patch.object(Common, "perform_request") + def test_get_metric_id(self, perf_req): + """Test get_metric_id function.""" + self.metrics.get_metric_id(endpoint, auth_token, "my_metric", "r_id") + + perf_req.assert_called_with( + "/v1/resource/generic/r_id", auth_token, req_type="get") + + def test_get_metric_name(self): + """Test the result from the get_metric_name function.""" + # test with a valid metric_name + values = {"metric_name": "disk_write_ops"} + + metric_name, norm_name = self.metrics.get_metric_name(values) + + self.assertEqual(metric_name, "disk_write_ops") + self.assertEqual(norm_name, "disk.write.requests") + + # test with an invalid metric name + values = {"metric_name": "my_invalid_metric"} + + metric_name, norm_name = self.metrics.get_metric_name(values) + + self.assertEqual(metric_name, "my_invalid_metric") + self.assertEqual(norm_name, None) + + @mock.patch.object(metric_req.Metrics, "get_metric_id") + @mock.patch.object(Common, "perform_request") + def test_valid_read_data_req(self, perf_req, get_metric): + """Test the read metric data function, for a valid call.""" + values = {"metric_name": "disk_write_ops", + "resource_uuid": "resource_id", + "collection_unit": "DAY", + "collection_period": 1} + + get_metric.return_value = "metric_id" + self.metrics.read_metric_data(endpoint, auth_token, values) + + perf_req.assert_called_once() + + @mock.patch.object(Common, "perform_request") + def test_invalid_read_data_req(self, perf_req): + """Test the read metric data function, for an invalid call.""" + # Teo empty lists wil be returned because the values are invalid + values = {} + + times, data = self.metrics.read_metric_data( + endpoint, auth_token, values) + + self.assertEqual(times, []) + self.assertEqual(data, []) + + def test_complete_response_list(self): + """Test the response list function for formating metric lists.""" + # Mock a list for testing purposes, with valid OSM metric + resp_list = self.metrics.response_list(metric_list) + + # Check for the expected values in the resulting list + for l in result_list: + self.assertIn(l, resp_list[0].values()) + + def test_name_response_list(self): + """Test the response list with metric name configured.""" + # Mock the metric name to test a metric name list + # Test with a name that is not in the list + invalid_name = "my_metric" + resp_list = self.metrics.response_list( + metric_list, metric_name=invalid_name) + + self.assertEqual(resp_list, []) + + # Test with a name on the list + valid_name = "disk_write_ops" + resp_list = self.metrics.response_list( + metric_list, metric_name=valid_name) + + # Check for the expected values in the resulting list + for l in result_list: + self.assertIn(l, resp_list[0].values()) + + def test_resource_response_list(self): + """Test the response list with resource_id configured.""" + # Mock a resource_id to test a resource list + # Test with resource not on the list + invalid_id = "mock_resource" + resp_list = self.metrics.response_list(metric_list, resource=invalid_id) + + self.assertEqual(resp_list, []) + + # Test with a resource on the list + valid_id = "r_id" + resp_list = self.metrics.response_list(metric_list, resource=valid_id) + + # Check for the expected values in the resulting list + for l in result_list: + self.assertIn(l, resp_list[0].values()) + + def test_combined_response_list(self): + """Test the response list function with resource_id and metric_name.""" + # Test for a combined resource and name list + # resource and name are on the list + valid_name = "disk_write_ops" + valid_id = "r_id" + resp_list = self.metrics.response_list( + metric_list, metric_name=valid_name, resource=valid_id) + + # Check for the expected values in the resulting list + for l in result_list: + self.assertIn(l, resp_list[0].values()) + + # resource not on list + invalid_id = "mock_resource" + resp_list = self.metrics.response_list( + metric_list, metric_name=valid_name, resource=invalid_id) + + self.assertEqual(resp_list, []) + + # metric name not on list + invalid_name = "mock_metric" + resp_list = self.metrics.response_list( + metric_list, metric_name=invalid_name, resource=valid_id) + + self.assertEqual(resp_list, []) diff --git a/osm_mon/test/OpenStack/unit/test_metric_req.py b/osm_mon/test/OpenStack/unit/test_metric_req.py new file mode 100644 index 0000000..0869b56 --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_metric_req.py @@ -0,0 +1,152 @@ +# Copyright 2017 iIntel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for all metric request message keys.""" + +import json + +import logging + +import unittest + +import mock + +from osm_mon.plugins.OpenStack.Gnocchi import metrics as metric_req + +from osm_mon.plugins.OpenStack.common import Common + +log = logging.getLogger(__name__) + + +class Message(object): + """A class to mock a message object value for metric requests.""" + + def __init__(self): + """Initialize a mocked message instance.""" + self.topic = "metric_request" + self.key = None + self.value = json.dumps({"vim_uuid": "test_id", "mock_message": "message_details"}) + + +class TestMetricReq(unittest.TestCase): + """Integration test for metric request keys.""" + + def setUp(self): + """Setup the tests for metric request keys.""" + super(TestMetricReq, self).setUp() + self.metrics = metric_req.Metrics() + + @mock.patch.object(Common, 'get_endpoint') + @mock.patch.object(Common, "get_auth_token") + def test_access_cred_metric_auth(self, get_token, get_endpoint): + """Test authentication with access credentials.""" + message = Message() + + self.metrics.metric_calls(message) + + get_token.assert_called_with('test_id') + get_endpoint.assert_any_call('metric', 'test_id') + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(metric_req.Metrics, "delete_metric") + @mock.patch.object(metric_req.Metrics, "get_metric_id") + def test_delete_metric_key(self, get_metric_id, del_metric): + """Test the functionality for a delete metric request.""" + # Mock a message value and key + message = Message() + message.key = "delete_metric_request" + message.value = json.dumps({"vim_uuid": "test_id", "metric_name": "disk_write_ops", "resource_uuid": "my_r_id"}) + + # Call the metric functionality and check delete request + get_metric_id.return_value = "my_metric_id" + self.metrics.metric_calls(message) + del_metric.assert_called_with(mock.ANY, mock.ANY, "my_metric_id") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(metric_req.Metrics, "list_metrics") + def test_list_metric_key(self, list_metrics): + """Test the functionality for a list metric request.""" + # Mock a message with list metric key and value + message = Message() + message.key = "list_metric_request" + message.value = json.dumps({"vim_uuid": "test_id", "metrics_list_request": "metric_details"}) + + # Call the metric functionality and check list functionality + self.metrics.metric_calls(message) + list_metrics.assert_called_with(mock.ANY, mock.ANY, "metric_details") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(metric_req.Metrics, "read_metric_data") + @mock.patch.object(metric_req.Metrics, "list_metrics") + @mock.patch.object(metric_req.Metrics, "delete_metric") + @mock.patch.object(metric_req.Metrics, "configure_metric") + def test_update_metric_key(self, config_metric, delete_metric, list_metrics, + read_data): + """Test the functionality for an update metric request.""" + # Mock a message with update metric key and value + message = Message() + message.key = "update_metric_request" + message.value = json.dumps({"vim_uuid": "test_id", + "metric_create": + {"metric_name": "my_metric", + "resource_uuid": "my_r_id"}}) + + # Call metric functionality and confirm no function is called + # Gnocchi does not support updating a metric configuration + self.metrics.metric_calls(message) + config_metric.assert_not_called() + list_metrics.assert_not_called() + delete_metric.assert_not_called() + read_data.assert_not_called() + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(metric_req.Metrics, "configure_metric") + def test_config_metric_key(self, config_metric): + """Test the functionality for a create metric request.""" + # Mock a message with create metric key and value + message = Message() + message.key = "create_metric_request" + message.value = json.dumps({"vim_uuid": "test_id", "metric_create": "metric_details"}) + + # Call metric functionality and check config metric + config_metric.return_value = "metric_id", "resource_id", True + self.metrics.metric_calls(message) + config_metric.assert_called_with(mock.ANY, mock.ANY, "metric_details") + + @mock.patch.object(Common, "get_auth_token", mock.Mock()) + @mock.patch.object(Common, 'get_endpoint', mock.Mock()) + @mock.patch.object(metric_req.Metrics, "read_metric_data") + def test_read_data_key(self, read_data): + """Test the functionality for a read metric data request.""" + # Mock a message with a read data key and value + message = Message() + message.key = "read_metric_data_request" + message.value = json.dumps({"vim_uuid": "test_id", "alarm_uuid": "alarm_id"}) + + # Call metric functionality and check read data metrics + read_data.return_value = "time_stamps", "data_values" + self.metrics.metric_calls(message) + read_data.assert_called_with( + mock.ANY, mock.ANY, json.loads(message.value)) diff --git a/osm_mon/test/OpenStack/unit/test_notifier.py b/osm_mon/test/OpenStack/unit/test_notifier.py new file mode 100644 index 0000000..a1ce1c6 --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_notifier.py @@ -0,0 +1,281 @@ +# Copyright 2017 Intel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for all common OpenStack methods.""" + +import json +import unittest + +import mock +from six.moves.BaseHTTPServer import BaseHTTPRequestHandler + +from osm_mon.core.message_bus.producer import KafkaProducer +from osm_mon.core.settings import Config +from osm_mon.plugins.OpenStack.Aodh.alarming import Alarming +from osm_mon.plugins.OpenStack.common import Common +from osm_mon.plugins.OpenStack.response import OpenStack_Response + +# Mock data from post request +post_data = json.dumps({"severity": "critical", + "alarm_name": "my_alarm", + "current": "current_state", + "alarm_id": "my_alarm_id", + "reason": "Threshold has been broken", + "reason_data": {"count": 1, + "most_recent": "null", + "type": "threshold", + "disposition": "unknown"}, + "previous": "previous_state"}) + +valid_get_resp = '{"gnocchi_resources_threshold_rule":\ + {"resource_id": "my_resource_id"}}' + +invalid_get_resp = '{"gnocchi_resources_threshold_rule":\ + {"resource_id": null}}' + +valid_notify_resp = '{"notify_details": {"status": "current_state",\ + "severity": "critical",\ + "resource_uuid": "my_resource_id",\ + "alarm_uuid": "my_alarm_id",\ + "vim_type": "OpenStack",\ + "start_date": "dd-mm-yyyy 00:00"},\ + "schema_version": "1.0",\ + "schema_type": "notify_alarm"}' + +invalid_notify_resp = '{"notify_details": {"invalid":"mock_details"}' + + +class Response(object): + """Mock a response class for generating responses.""" + + def __init__(self, text): + """Initialise a mock response with a text attribute.""" + self.text = text + + +class NotifierHandler(BaseHTTPRequestHandler): + """Mock the NotifierHandler class for testing purposes.""" + + def __init__(self, request, client_address, server): + """Initilase mock NotifierHandler.""" + self.request = request + self.client_address = client_address + self.server = server + self.setup() + try: + self.handle() + finally: + self.finish() + + def setup(self): + """Mock setup function.""" + pass + + def handle(self): + """Mock handle function.""" + pass + + def finish(self): + """Mock finish function.""" + pass + + def _set_headers(self): + """Mock getting the request headers.""" + pass + + def do_GET(self): + """Mock functionality for GET request.""" + self._set_headers() + pass + + def do_POST(self): + """Mock functionality for a POST request.""" + self._set_headers() + self.notify_alarm(json.loads(post_data)) + + def notify_alarm(self, values): + """Mock the notify_alarm functionality to generate a valid response.""" + config = Config.instance() + config.read_environ() + self._alarming = Alarming() + self._common = Common() + self._response = OpenStack_Response() + self._producer = KafkaProducer('alarm_response') + alarm_id = values['alarm_id'] + + vim_uuid = 'test_id' + + auth_token = Common.get_auth_token(vim_uuid) + endpoint = Common.get_endpoint("alarming", vim_uuid) + + # If authenticated generate and send response message + if auth_token is not None and endpoint is not None: + url = "{}/v2/alarms/%s".format(endpoint) % alarm_id + + # Get the resource_id of the triggered alarm and the date + result = Common.perform_request( + url, auth_token, req_type="get") + alarm_details = json.loads(result.text) + gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule'] + resource_id = gnocchi_rule['resource_id'] + a_date = "dd-mm-yyyy 00:00" + + # Process an alarm notification if resource_id is valid + if resource_id is not None: + # Try generate and send response + try: + resp_message = self._response.generate_response( + 'notify_alarm', a_id=alarm_id, + r_id=resource_id, + sev=values['severity'], date=a_date, + state=values['current'], vim_type="OpenStack") + self._producer.notify_alarm( + 'notify_alarm', resp_message, 'alarm_response') + except Exception: + pass + + +class TestNotifier(unittest.TestCase): + """Test the NotifierHandler class for requests from aodh.""" + + def setUp(self): + """Setup tests.""" + super(TestNotifier, self).setUp() + self.handler = NotifierHandler( + "mock_request", "mock_address", "mock_server") + + @mock.patch.object(NotifierHandler, "_set_headers") + def test_do_GET(self, set_head): + """Test do_GET, generates headers for get request.""" + self.handler.do_GET() + + set_head.assert_called_once() + + @mock.patch.object(NotifierHandler, "notify_alarm") + @mock.patch.object(NotifierHandler, "_set_headers") + def test_do_POST(self, set_head, notify): + """Test do_POST functionality for a POST request.""" + self.handler.do_POST() + + set_head.assert_called_once() + notify.assert_called_with(json.loads(post_data)) + + @mock.patch.object(Common, "get_endpoint") + @mock.patch.object(Common, "get_auth_token") + @mock.patch.object(Common, "perform_request") + def test_notify_alarm_unauth(self, perf_req, auth, endpoint): + """Test notify alarm when not authenticated with keystone.""" + # Response request will not be performed unless there is a valid + # auth_token and endpoint + # Invalid auth_token and endpoint + auth.return_value = None + endpoint.return_value = None + self.handler.notify_alarm(json.loads(post_data)) + + perf_req.assert_not_called() + + # Valid endpoint + auth.return_value = None + endpoint.return_value = "my_endpoint" + self.handler.notify_alarm(json.loads(post_data)) + + perf_req.assert_not_called() + + # Valid auth_token + auth.return_value = "my_auth_token" + endpoint.return_value = None + self.handler.notify_alarm(json.loads(post_data)) + + perf_req.assert_not_called() + + @mock.patch.object(Common, "get_endpoint") + @mock.patch.object(OpenStack_Response, "generate_response") + @mock.patch.object(Common, "get_auth_token") + @mock.patch.object(Common, "perform_request") + def test_notify_alarm_invalid_alarm(self, perf_req, auth, resp, endpoint): + """Test valid authentication, invalid alarm details.""" + # Mock valid auth_token and endpoint + auth.return_value = "my_auth_token" + endpoint.return_value = "my_endpoint" + perf_req.return_value = Response(invalid_get_resp) + + self.handler.notify_alarm(json.loads(post_data)) + + # Response is not generated + resp.assert_not_called() + + @mock.patch.object(KafkaProducer, "notify_alarm") + @mock.patch.object(Common, "get_endpoint") + @mock.patch.object(OpenStack_Response, "generate_response") + @mock.patch.object(Common, "get_auth_token") + @mock.patch.object(Common, "perform_request") + def test_notify_alarm_resp_call(self, perf_req, auth, response, endpoint, notify): + """Test notify_alarm tries to generate a response for SO.""" + # Mock valid auth token and endpoint, valid response from aodh + auth.return_value = "my_auth_token" + endpoint.returm_value = "my_endpoint" + perf_req.return_value = Response(valid_get_resp) + self.handler.notify_alarm(json.loads(post_data)) + + notify.assert_called() + response.assert_called_with('notify_alarm', a_id="my_alarm_id", + r_id="my_resource_id", sev="critical", + date="dd-mm-yyyy 00:00", + state="current_state", + vim_type="OpenStack") + + @mock.patch.object(Common, "get_endpoint") + @mock.patch.object(KafkaProducer, "notify_alarm") + @mock.patch.object(OpenStack_Response, "generate_response") + @mock.patch.object(Common, "get_auth_token") + @mock.patch.object(Common, "perform_request") + @unittest.skip("Schema validation not implemented yet.") + def test_notify_alarm_invalid_resp( + self, perf_req, auth, response, notify, endpoint): + """Test the notify_alarm function, sends response to the producer.""" + # Generate return values for valid notify_alarm operation + auth.return_value = "my_auth_token" + endpoint.return_value = "my_endpoint" + perf_req.return_value = Response(valid_get_resp) + response.return_value = invalid_notify_resp + + self.handler.notify_alarm(json.loads(post_data)) + + notify.assert_not_called() + + @mock.patch.object(Common, "get_endpoint") + @mock.patch.object(KafkaProducer, "notify_alarm") + @mock.patch.object(OpenStack_Response, "generate_response") + @mock.patch.object(Common, "get_auth_token") + @mock.patch.object(Common, "perform_request") + def test_notify_alarm_valid_resp( + self, perf_req, auth, response, notify, endpoint): + """Test the notify_alarm function, sends response to the producer.""" + # Generate return values for valid notify_alarm operation + auth.return_value = "my_auth_token" + endpoint.return_value = "my_endpoint" + perf_req.return_value = Response(valid_get_resp) + response.return_value = valid_notify_resp + + self.handler.notify_alarm(json.loads(post_data)) + + notify.assert_called_with( + "notify_alarm", valid_notify_resp, "alarm_response") diff --git a/osm_mon/test/OpenStack/unit/test_responses.py b/osm_mon/test/OpenStack/unit/test_responses.py new file mode 100644 index 0000000..6cf4e3f --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_responses.py @@ -0,0 +1,117 @@ +# Copyright 2017 iIntel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Test that the correct responses are generated for each message.""" + +import logging + +import unittest + +import mock + +from osm_mon.plugins.OpenStack import response as resp + +log = logging.getLogger(__name__) + + +class TestOpenStackResponse(unittest.TestCase): + """Tests for responses generated by the OpenStack plugins.""" + + def setUp(self): + """Setup for testing OpenStack plugin responses.""" + super(TestOpenStackResponse, self).setUp() + self.plugin_resp = resp.OpenStack_Response() + + def test_invalid_key(self): + """Test if an invalid key is entered for a response.""" + message = self.plugin_resp.generate_response("mock_invalid_key") + self.assertEqual(message, None) + + @mock.patch.object( + resp.OpenStack_Response, "alarm_list_response") + def test_list_alarm_resp(self, alarm_list_resp): + """Test out a function call for a list alarm response.""" + message = self.plugin_resp.generate_response("list_alarm_response") + self.assertEqual(alarm_list_resp.return_value, message) + + @mock.patch.object( + resp.OpenStack_Response, "list_metric_response") + def test_list_metric_resp(self, metric_list_resp): + """Test list metric response function call.""" + message = self.plugin_resp.generate_response("list_metric_response") + self.assertEqual(message, metric_list_resp.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "delete_alarm_response") + def test_delete_alarm_resp(self, del_alarm_resp): + """Test delete alarm response function call.""" + message = self.plugin_resp.generate_response("delete_alarm_response") + self.assertEqual(message, del_alarm_resp.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "delete_metric_response") + def test_delete_metric_resp(self, del_metric_resp): + """Test the response functionality of delete metric response.""" + message = self.plugin_resp.generate_response("delete_metric_response") + self.assertEqual(message, del_metric_resp.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "create_alarm_response") + def test_create_alarm_resp(self, config_alarm_resp): + """Test create alarm response function call.""" + message = self.plugin_resp.generate_response("create_alarm_response") + self.assertEqual(message, config_alarm_resp.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "metric_create_response") + def test_create_metric_resp(self, config_metric_resp): + """Test create metric response function call.""" + message = self.plugin_resp.generate_response("create_metric_response") + self.assertEqual(message, config_metric_resp.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "update_alarm_response") + def test_update_alarm_resp(self, up_alarm_resp): + """Test update alarm response function call.""" + message = self.plugin_resp.generate_response("update_alarm_response") + self.assertEqual(message, up_alarm_resp.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "update_metric_response") + def test_update_metric_resp(self, up_metric_resp): + """Test update metric response function call.""" + message = self.plugin_resp.generate_response("update_metric_response") + self.assertEqual(message, up_metric_resp.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "notify_alarm") + def test_notify_alarm(self, notify_alarm): + """Test notify alarm response function call.""" + message = self.plugin_resp.generate_response("notify_alarm") + self.assertEqual(message, notify_alarm.return_value) + + @mock.patch.object( + resp.OpenStack_Response, "read_metric_data_response") + def test_read_metric_data_resp(self, read_data_resp): + """Test read metric data response function call.""" + message = self.plugin_resp.generate_response( + "read_metric_data_response") + self.assertEqual(message, read_data_resp.return_value) diff --git a/osm_mon/test/OpenStack/unit/test_settings.py b/osm_mon/test/OpenStack/unit/test_settings.py new file mode 100644 index 0000000..42619f8 --- /dev/null +++ b/osm_mon/test/OpenStack/unit/test_settings.py @@ -0,0 +1,46 @@ +# Copyright 2017 Intel Research and Development Ireland Limited +# ************************************************************* + +# This file is part of OSM Monitoring module +# All Rights Reserved to Intel 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. + +# For those usages not covered by the Apache License, Version 2.0 please +# contact: helena.mcgough@intel.com or adrian.hoban@intel.com +## +"""Tests for settings for OpenStack plugins configurations.""" + +import logging +import os +import unittest + +from osm_mon.core.settings import Config + +log = logging.getLogger(__name__) + + +class TestSettings(unittest.TestCase): + """Test the settings class for OpenStack plugin configuration.""" + + def setUp(self): + """Test Setup.""" + super(TestSettings, self).setUp() + self.cfg = Config.instance() + + def test_set_os_username(self): + """Test reading the environment for OpenStack plugin configuration.""" + os.environ["OS_NOTIFIER_URI"] = "test" + self.cfg.read_environ() + + self.assertEqual(self.cfg.OS_NOTIFIER_URI, "test") diff --git a/osm_mon/test/functional/test_vim_account.py b/osm_mon/test/functional/test_vim_account.py deleted file mode 100644 index 2a7a722..0000000 --- a/osm_mon/test/functional/test_vim_account.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 Whitestack, LLC -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Whitestack, LLC - -# 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: bdiaz@whitestack.com or glavado@whitestack.com -## - -"""Test an end to end Openstack vim_account requests.""" - -import json -import logging -import time -import unittest - -from kafka import KafkaConsumer -from kafka import KafkaProducer -from kafka.errors import KafkaError - -from osm_mon.core.auth import AuthManager - -log = logging.getLogger(__name__) - - -class VimAccountTest(unittest.TestCase): - def setUp(self): - try: - self.producer = KafkaProducer(bootstrap_servers='localhost:9092') - self.consumer = KafkaConsumer(bootstrap_servers='localhost:9092', - group_id='osm_mon') - self.consumer.subscribe(['vim_account']) - self.auth_manager = AuthManager() - except KafkaError: - self.skipTest('Kafka server not present.') - - @unittest.skip("Correct support for functional tests is pending.") - # TODO: Refactor - def test_create_edit_delete_vim_account(self): - """Test vim_account creation message from KafkaProducer.""" - # Set-up message, producer and consumer for tests - create_payload = { - "_id": "test_id", - "name": "test_name", - "vim_type": "openstack", - "vim_url": "auth_url", - "vim_user": "user", - "vim_password": "password", - "vim_tenant_name": "tenant", - "config": - { - "foo": "bar" - } - } - - self.producer.send('vim_account', key=b'create', value=json.dumps(create_payload)) - - self.producer.flush() - - time.sleep(1) - creds = self.auth_manager.get_credentials('test_id') - self.assertIsNotNone(creds) - self.assertEqual(creds.name, create_payload['name']) - self.assertEqual(json.loads(creds.config), create_payload['config']) - - # Set-up message, producer and consumer for tests - edit_payload = { - "_id": "test_id", - "name": "test_name_edited", - "vim_type": "openstack", - "vim_url": "auth_url", - "vim_user": "user", - "vim_password": "password", - "vim_tenant_name": "tenant", - "config": - { - "foo_edited": "bar_edited" - } - } - - self.producer.send('vim_account', key=b'edit', value=json.dumps(edit_payload)) - - self.producer.flush() - - time.sleep(1) - creds = self.auth_manager.get_credentials('test_id') - self.assertEqual(creds.name, edit_payload['name']) - self.assertEqual(json.loads(creds.config), edit_payload['config']) - - delete_payload = { - "_id": "test_id" - } - - self.producer.send('vim_account', key=b'delete', value=json.dumps(delete_payload)) - - self.producer.flush() - - time.sleep(1) - creds = self.auth_manager.get_credentials('test_id') - self.assertIsNone(creds) diff --git a/osm_mon/test/integration/__init__.py b/osm_mon/test/integration/__init__.py deleted file mode 100644 index d81308a..0000000 --- a/osm_mon/test/integration/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 Whitestack, LLC -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Whitestack, LLC - -# 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: bdiaz@whitestack.com or glavado@whitestack.com -## diff --git a/osm_mon/test/integration/test_alarm_integration.py b/osm_mon/test/integration/test_alarm_integration.py deleted file mode 100644 index b443d6a..0000000 --- a/osm_mon/test/integration/test_alarm_integration.py +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright 2017 Intel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com - -# __author__ = "Helena McGough" -"""Test an end to end Openstack alarm requests.""" - -import json -import logging -import unittest - -import mock -from kafka import KafkaConsumer -from kafka import KafkaProducer -from kafka.errors import KafkaError - -from osm_mon.core.auth import AuthManager -from osm_mon.core.database import DatabaseManager -from osm_mon.core.message_bus.producer import KafkaProducer as prod -from osm_mon.plugins.OpenStack import response -from osm_mon.plugins.OpenStack.Aodh import alarming -from osm_mon.plugins.OpenStack.common import Common -from keystoneclient.v3 import client - -log = logging.getLogger(__name__) - - -class AlarmIntegrationTest(unittest.TestCase): - def setUp(self): - try: - self.producer = KafkaProducer(bootstrap_servers='localhost:9092') - self.req_consumer = KafkaConsumer(bootstrap_servers='localhost:9092', - auto_offset_reset='earliest', - consumer_timeout_ms=60000) - self.req_consumer.subscribe(['alarm_request']) - except KafkaError: - self.skipTest('Kafka server not present.') - # Set up common and alarming class instances - self.alarms = alarming.Alarming() - self.openstack_auth = Common() - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(prod, "update_alarm_response") - @mock.patch.object(alarming.Alarming, "update_alarm") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_update_alarm_req(self, resp, update_alarm, update_resp): - """Test Aodh update alarm request message from KafkaProducer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "test_id", - "alarm_update_request": - {"correlation_id": 123, - "alarm_uuid": "alarm_id", - "metric_uuid": "metric_id"}} - - self.producer.send('alarm_request', key="update_alarm_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "update_alarm_request": - # Mock a valid alarm update - update_alarm.return_value = "alarm_id", True - self.alarms.alarming(message) - - # A response message is generated and sent via MON's producer - resp.assert_called_with( - 'update_alarm_response', alarm_id="alarm_id", cor_id=123, - status=True) - update_resp.assert_called_with( - 'update_alarm_response', resp.return_value, 'alarm_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(DatabaseManager, "save_alarm", mock.Mock()) - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(prod, "create_alarm_response") - @mock.patch.object(alarming.Alarming, "configure_alarm") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_create_alarm_req(self, resp, config_alarm, create_resp): - """Test Aodh create alarm request message from KafkaProducer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "test_id", - "alarm_create_request": - {"correlation_id": 123, - "alarm_name": "my_alarm", - "metric_name": "my_metric", - "resource_uuid": "my_resource", - "severity": "WARNING"}} - - self.producer.send('alarm_request', key="create_alarm_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "create_alarm_request": - # Mock a valid alarm creation - config_alarm.return_value = "alarm_id", True - self.alarms.alarming(message) - - # A response message is generated and sent via MON's produce - resp.assert_called_with( - 'create_alarm_response', status=True, alarm_id="alarm_id", - cor_id=123) - create_resp.assert_called_with( - 'create_alarm_response', resp.return_value, 'alarm_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(prod, "list_alarm_response") - @mock.patch.object(alarming.Alarming, "list_alarms") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_list_alarm_req(self, resp, list_alarm, list_resp): - """Test Aodh list alarm request message from KafkaProducer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "test_id", - "alarm_list_request": - {"correlation_id": 123, - "resource_uuid": "resource_id", }} - - self.producer.send('alarm_request', key="list_alarm_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "list_alarm_request": - # Mock an empty list generated by the request - list_alarm.return_value = [] - self.alarms.alarming(message) - - # Response message is generated - resp.assert_called_with( - 'list_alarm_response', alarm_list=[], - cor_id=123) - # Producer attempts to send the response message back to the SO - list_resp.assert_called_with( - 'list_alarm_response', resp.return_value, 'alarm_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(alarming.Alarming, "delete_alarm") - @mock.patch.object(prod, "delete_alarm_response") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_delete_alarm_req(self, resp, del_resp, del_alarm): - """Test Aodh delete alarm request message from KafkaProducer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "test_id", - "alarm_delete_request": - {"correlation_id": 123, - "alarm_uuid": "alarm_id", }} - - self.producer.send('alarm_request', key="delete_alarm_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "delete_alarm_request": - self.alarms.alarming(message) - - # Response message is generated and sent by MON's producer - resp.assert_called_with( - 'delete_alarm_response', alarm_id="alarm_id", - status=del_alarm.return_value, cor_id=123) - del_resp.assert_called_with( - 'delete_alarm_response', resp.return_value, 'alarm_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(alarming.Alarming, "update_alarm_state") - def test_ack_alarm_req(self, ack_alarm): - """Test Aodh acknowledge alarm request message from KafkaProducer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "test_id", - "ack_details": - {"alarm_uuid": "alarm_id", }} - - self.producer.send('alarm_request', key="acknowledge_alarm", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "acknowledge_alarm": - self.alarms.alarming(message) - return - - self.fail("No message received in consumer") \ No newline at end of file diff --git a/osm_mon/test/integration/test_metric_integration.py b/osm_mon/test/integration/test_metric_integration.py deleted file mode 100644 index 66f4f0a..0000000 --- a/osm_mon/test/integration/test_metric_integration.py +++ /dev/null @@ -1,238 +0,0 @@ -# Copyright 2017 Intel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com - -# __author__ = "Helena McGough" -"""Test an end to end Openstack metric requests.""" - -import json - -import logging -import unittest - -from kafka.errors import KafkaError - -from osm_mon.core.message_bus.producer import KafkaProducer as prod - -from kafka import KafkaConsumer -from kafka import KafkaProducer - -import mock - -from osm_mon.plugins.OpenStack import response - -from osm_mon.plugins.OpenStack.Gnocchi import metrics - -from osm_mon.plugins.OpenStack.common import Common - -log = logging.getLogger(__name__) - - -class MetricIntegrationTest(unittest.TestCase): - def setUp(self): - # Set up common and alarming class instances - self.metric_req = metrics.Metrics() - self.openstack_auth = Common() - - try: - self.producer = KafkaProducer(bootstrap_servers='localhost:9092') - self.req_consumer = KafkaConsumer(bootstrap_servers='localhost:9092', - auto_offset_reset='earliest', - consumer_timeout_ms=60000) - self.req_consumer.subscribe(['metric_request']) - except KafkaError: - self.skipTest('Kafka server not present.') - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(metrics.Metrics, "configure_metric") - @mock.patch.object(prod, "create_metrics_resp") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_create_metric_req(self, resp, create_resp, config_metric): - """Test Gnocchi create metric request message from producer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "1", - "correlation_id": 123, - "metric_create": - {"metric_name": "my_metric", - "resource_uuid": "resource_id"}} - - self.producer.send('metric_request', key="create_metric_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - print(message) - # Check the vim desired by the message - vim_type = json.loads(message.value)["vim_type"].lower() - if vim_type == "openstack": - # A valid metric is created - config_metric.return_value = "metric_id", "resource_id", True - self.metric_req.metric_calls(message) - - # A response message is generated and sent by MON's producer - resp.assert_called_with( - 'create_metric_response', status=True, cor_id=123, - metric_id="metric_id", r_id="resource_id") - create_resp.assert_called_with( - 'create_metric_response', resp.return_value, 'metric_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(metrics.Metrics, "delete_metric") - @mock.patch.object(prod, "delete_metric_response") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_delete_metric_req(self, resp, del_resp, del_metric): - """Test Gnocchi delete metric request message from producer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "1", - "correlation_id": 123, - "metric_uuid": "metric_id", - "metric_name": "metric_name", - "resource_uuid": "resource_id"} - - self.producer.send('metric_request', key="delete_metric_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - if message.key == "delete_metric_request": - # Metric has been deleted - del_metric.return_value = True - self.metric_req.metric_calls(message) - - # A response message is generated and sent by MON's producer - resp.assert_called_with( - 'delete_metric_response', m_id="metric_id", - m_name="metric_name", status=True, r_id="resource_id", - cor_id=123) - del_resp.assert_called_with( - 'delete_metric_response', resp.return_value, 'metric_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(metrics.Metrics, "read_metric_data") - @mock.patch.object(prod, "read_metric_data_response") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_read_metric_data_req(self, resp, read_resp, read_data): - """Test Gnocchi read metric data request message from producer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "test_id", - "correlation_id": 123, - "metric_uuid": "metric_id", - "metric_name": "metric_name", - "resource_uuid": "resource_id"} - - self.producer.send('metric_request', key="read_metric_data_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "read_metric_data_request": - # Mock empty lists generated by the request message - read_data.return_value = [], [] - self.metric_req.metric_calls(message) - - # A response message is generated and sent by MON's producer - resp.assert_called_with( - 'read_metric_data_response', m_id="metric_id", - m_name="metric_name", r_id="resource_id", cor_id=123, times=[], - metrics=[]) - read_resp.assert_called_with( - 'read_metric_data_response', resp.return_value, - 'metric_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(metrics.Metrics, "list_metrics") - @mock.patch.object(prod, "list_metric_response") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_list_metrics_req(self, resp, list_resp, list_metrics): - """Test Gnocchi list metrics request message from producer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "1", - "metrics_list_request": - {"correlation_id": 123, }} - - self.producer.send('metric_request', key="list_metric_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "list_metric_request": - # Mock an empty list generated by the request - list_metrics.return_value = [] - self.metric_req.metric_calls(message) - - # A response message is generated and sent by MON's producer - resp.assert_called_with( - 'list_metric_response', m_list=[], cor_id=123) - list_resp.assert_called_with( - 'list_metric_response', resp.return_value, 'metric_response') - - return - self.fail("No message received in consumer") - - @mock.patch.object(Common, "get_auth_token", mock.Mock()) - @mock.patch.object(Common, "get_endpoint", mock.Mock()) - @mock.patch.object(metrics.Metrics, "get_metric_id") - @mock.patch.object(prod, "update_metric_response") - @mock.patch.object(response.OpenStack_Response, "generate_response") - def test_update_metrics_req(self, resp, update_resp, get_id): - """Test Gnocchi update metric request message from KafkaProducer.""" - # Set-up message, producer and consumer for tests - payload = {"vim_type": "OpenSTACK", - "vim_uuid": "test_id", - "correlation_id": 123, - "metric_create": - {"metric_name": "my_metric", - "resource_uuid": "resource_id", }} - - self.producer.send('metric_request', key="update_metric_request", - value=json.dumps(payload)) - - for message in self.req_consumer: - # Check the vim desired by the message - if message.key == "update_metric_request": - # Gnocchi doesn't support metric updates - get_id.return_value = "metric_id" - self.metric_req.metric_calls(message) - - # Response message is generated and sent via MON's producer - # No metric update has taken place - resp.assert_called_with( - 'update_metric_response', status=False, cor_id=123, - r_id="resource_id", m_id="metric_id") - update_resp.assert_called_with( - 'update_metric_response', resp.return_value, 'metric_response') - - return - self.fail("No message received in consumer") diff --git a/osm_mon/test/integration/test_notify_alarm.py b/osm_mon/test/integration/test_notify_alarm.py deleted file mode 100644 index 4f44572..0000000 --- a/osm_mon/test/integration/test_notify_alarm.py +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright 2017 Intel Research and Development Ireland Limited -# ************************************************************* - -# This file is part of OSM Monitoring module -# All Rights Reserved to Intel 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. - -# For those usages not covered by the Apache License, Version 2.0 please -# contact: helena.mcgough@intel.com or adrian.hoban@intel.com -## -"""Tests for all common OpenStack methods.""" - -import json -import logging -import socket -import unittest -from threading import Thread - -import mock -import requests -from six.moves.BaseHTTPServer import BaseHTTPRequestHandler -from six.moves.BaseHTTPServer import HTTPServer - -from osm_mon.core.message_bus.producer import KafkaProducer -from osm_mon.core.settings import Config -from osm_mon.plugins.OpenStack.Aodh.alarming import Alarming -from osm_mon.plugins.OpenStack.common import Common -from osm_mon.plugins.OpenStack.response import OpenStack_Response - -log = logging.getLogger(__name__) - -# Create an instance of the common openstack class, producer and consumer -openstack_auth = Common() - -# Mock a valid get_response for alarm details -valid_get_resp = '{"gnocchi_resources_threshold_rule":\ - {"resource_id": "my_resource_id"}}' - - -class MockResponse(object): - """Mock a response class for generating responses.""" - - def __init__(self, text): - """Initialise a mock response with a text attribute.""" - self.text = text - - -class MockNotifierHandler(BaseHTTPRequestHandler): - """Mock the NotifierHandler class for testing purposes.""" - - def _set_headers(self): - """Set the headers for a request.""" - self.send_response(200) - self.send_header('Content-type', 'text/html') - self.end_headers() - - def do_GET(self): - """Mock functionality for GET request.""" - # self.send_response(requests.codes.ok) - self._set_headers() - pass - - def do_POST(self): - """Mock functionality for a POST request.""" - self._set_headers() - content_length = int(self.headers['Content-Length']) - post_data = self.rfile.read(content_length) - self.notify_alarm(json.loads(post_data)) - - def notify_alarm(self, values): - """Mock the notify_alarm functionality to generate a valid response.""" - config = Config.instance() - config.read_environ() - self._alarming = Alarming() - self._common = Common() - self._response = OpenStack_Response() - self._producer = KafkaProducer('alarm_response') - alarm_id = values['alarm_id'] - - auth_token = Common.get_auth_token('test_id') - endpoint = Common.get_endpoint('alarming', 'test_id') - - # If authenticated generate and send response message - if auth_token is not None and endpoint is not None: - url = "{}/v2/alarms/%s".format(endpoint) % alarm_id - - # Get the resource_id of the triggered alarm and the date - result = Common.perform_request( - url, auth_token, req_type="get") - alarm_details = json.loads(result.text) - gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule'] - resource_id = gnocchi_rule['resource_id'] - # Mock a date for testing purposes - a_date = "dd-mm-yyyy 00:00" - - # Process an alarm notification if resource_id is valid - if resource_id is not None: - # Try generate and send response - try: - resp_message = self._response.generate_response( - 'notify_alarm', a_id=alarm_id, - r_id=resource_id, - sev=values['severity'], date=a_date, - state=values['current'], vim_type="OpenStack") - self._producer.notify_alarm( - 'notify_alarm', resp_message, 'alarm_response') - except Exception: - pass - - -def get_free_port(): - """Function to get a free port to run the test webserver on.""" - s = socket.socket(socket.AF_INET, type=socket.SOCK_STREAM) - s.bind(('localhost', 0)) - address, port = s.getsockname() - s.close() - return port - - -# Create the webserver, port and run it on its own thread -mock_server_port = get_free_port() -mock_server = HTTPServer(('localhost', mock_server_port), MockNotifierHandler) -mock_server_thread = Thread(target=mock_server.serve_forever) -mock_server_thread.setDaemon(True) -mock_server_thread.start() - - -def test_do_get(): - """Integration test for get request on notifier webserver.""" - url = 'http://localhost:{port}/users'.format(port=mock_server_port) - - # Send a request to the mock API server and store the response. - response = requests.get(url) - - # Confirm that the request-response cycle completed successfully. - assert response.ok - - -class AlarmNotificationTest(unittest.TestCase): - @mock.patch.object(KafkaProducer, "notify_alarm") - @mock.patch.object(OpenStack_Response, "generate_response") - @mock.patch.object(Common, "perform_request") - @mock.patch.object(Common, "get_endpoint") - @mock.patch.object(Common, "get_auth_token") - def test_post_notify_alarm(self, auth, endpoint, perf_req, resp, notify): - """Integration test for notify_alarm.""" - url = 'http://localhost:{port}/users'.format(port=mock_server_port) - payload = {"severity": "critical", - "alarm_name": "my_alarm", - "current": "current_state", - "alarm_id": "my_alarm_id", - "reason": "Threshold has been broken", - "reason_data": {"count": 1, - "most_recent": "null", - "type": "threshold", - "disposition": "unknown"}, - "previous": "previous_state"} - - # Mock authenticate and request response for testing - auth.return_value = "my_auth_token" - endpoint.return_value = "my_endpoint" - perf_req.return_value = MockResponse(valid_get_resp) - - # Generate a post request for testing - response = requests.post(url, json.dumps(payload)) - self.assertEqual(response.status_code, 200) - # A response message is generated with the following details - resp.assert_called_with( - "notify_alarm", a_id="my_alarm_id", r_id="my_resource_id", - sev="critical", date='dd-mm-yyyy 00:00', state="current_state", - vim_type="OpenStack") - - # Response message is sent back to the SO via MON's producer - notify.assert_called_with("notify_alarm", mock.ANY, "alarm_response") diff --git a/requirements.txt b/requirements.txt index be103aa..98752ea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,6 @@ # For those usages not covered by the Apache License, Version 2.0 please # contact: prithiv.mohan@intel.com or adrian.hoban@intel.com stdeb==0.8.* -MySQL-python==1.2.* kafka==1.3.* lxml==4.2.* requests==2.18.* @@ -38,4 +37,5 @@ pyopenssl==17.5.* six==1.11.* bottle==0.12.* peewee==3.1.* -pyyaml==3.* \ No newline at end of file +pyyaml==3.* +git+https://osm.etsi.org/gerrit/osm/common.git@857731b#egg=osm-common \ No newline at end of file