Newer
Older
#!/usr/bin/python3
"""
## © University of Southampton IT Innovation Centre, 2018
##
## Copyright in this software belongs to University of Southampton
## IT Innovation Centre of Gamma House, Enterprise Road,
## Chilworth Science Park, Southampton, SO16 7NS, UK.
##
## This software may not be used, sold, licensed, transferred, copied
## or reproduced in whole or in part in any manner or form or in or
## on any media by any person other than in accordance with the terms
## of the Licence Agreement supplied with the software, or otherwise
## without the prior written consent of the copyright owners.
##
## This software is distributed WITHOUT ANY WARRANTY, without even the
## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE, except where stated in the Licence Agreement supplied with
## the software.
##
## Created By : Nikolay Stanchev
## Created Date : 22-08-2018
## Created for Project : FLAME
"""
from requests import post, get, delete
from os import listdir
from os.path import join, dirname
from json import load
from schema import Schema, And, Or, Optional, SchemaError
from clmctest.alerts.alert_handler_server import LOG_TEST_FOLDER_PATH
NGINX_PORT = 80
def is_valid_timestamp(str_timestamp):
try:
strptime(str_timestamp, "%Y-%m-%dT%H:%M:%SZ")
return True
except ValueError:
return False
def is_valid_details_string(details):
Nikolay Stanchev
committed
try:
details_dict = {key.strip(): value.strip() for key,value in [item.split("=") for item in details.split(",")]}
return len(details_dict) == 4 and "db" in details_dict and "sfc" in details_dict and "sfci" in details_dict and "policy" in details_dict
except Exception:
return False
JSON_BODY_SCHEMA = Schema({
"message": "TRUE",
"id": str,
"level": "CRITICAL",
"duration": int,
"previousLevel": str,
"details": And(str, is_valid_details_string),
"time": And(str, is_valid_timestamp),
"data": {
"series": [
{
"name": str,
Optional("tags"): {
str: str
},
"columns": [
str
],
"values": [
[
Or(str, int)
]
]
}
]
}
})
class TestAlerts(object):
Nikolay Stanchev
committed
def test_alert_triggers(self, rspec_config, set_up_tear_down_fixture):
"""
Test is implemented using the following steps:
* Send to clmc service a POST request with TOSCA alert spec. and resource spec. files
* Wait 10 seconds for Kapacitor to configure and start executing the defined tasks
* Send some test requests to nginx to increase the load
* Check that 4 log files have been created - one for each alert defined in the alert spec.
* Send to clmc service a DELETE request with TOSCA alert spec. file
* Check that the returned lists of deleted handlers and alerts are correct
:param rspec_config: fixture from conftest.py
"""
global NGINX_PORT, JSON_BODY_SCHEMA
clmc_service_host, nginx_host = None, None
for host in rspec_config:
if host["name"] == "clmc-service":
clmc_service_host = host["ip_address"]
elif host["name"] == "nginx":
nginx_host = host["ip_address"]
if clmc_service_host is not None and nginx_host is not None:
break
print("Sending alerts specification to clmc service...")
alerts_spec = join(dirname(__file__), "alerts_test_config.yaml")
resources_spec = join(dirname(__file__), "resources_test_config.yaml")
with open(alerts_spec, 'rb') as alerts:
with open(resources_spec, 'rb') as resources:
files = {'alert-spec': alerts, 'resource-spec': resources}
response = post("http://{0}/clmc-service/alerts".format(clmc_service_host), files=files)
assert response.status_code == 200
clmc_service_response = response.json()
assert "triggers_specification_errors" not in clmc_service_response, "Unexpected error was returned for triggers specification"
assert "triggers_action_errors" not in clmc_service_response, "Unexpected error was returned for handlers specification"
print("Alert spec sent successfully")
print("Wait 10 seconds for Kapacitor stream/batch tasks to start working...")
sleep(10)
print("Sending test requests to nginx...")
response = get("http://{0}:{1}/".format(nginx_host, NGINX_PORT))
assert response.status_code == 200
print("Wait 15 seconds for Kapacitor to trigger alerts...")
sleep(15)
alert_logs = listdir(LOG_TEST_FOLDER_PATH)
assert len(alert_logs) == 4, "4 log files must have been created - one for each alert defined in the specification."
for alert_log in alert_logs:
alert_log_path = join(LOG_TEST_FOLDER_PATH, alert_log)
with open(alert_log_path) as fh:
alert_json = load(fh)
try:
JSON_BODY_SCHEMA.validate(alert_json)
valid = True
except SchemaError:
valid = False
assert valid, "Alert log content is invalid - {0}".format(alert_log_path)
with open(alerts_spec, 'rb') as alerts:
files = {'alert-spec': alerts}
response = delete("http://{0}/clmc-service/alerts".format(clmc_service_host), files=files)
assert response.status_code == 200, "Incorrect status code returned after deleting the alert specification"
json_response = response.json()
# sort by trigger to ensure comparison order is correct
assert sorted(json_response["deleted_alerts"], key=lambda x: x['trigger']) == [{"policy": "scale_nginx_policy", "trigger": "high_requests"}, {"policy": "scale_nginx_policy", "trigger": "increase_in_active_requests"},
{"policy": "scale_nginx_policy", "trigger": "increase_in_running_processes"}, {"policy": "deadman_policy", "trigger": "no_measurements"}], \
"Incorrect list of deleted alerts"
# sort by handler and trigger to ensure comparison order is correct
assert sorted(json_response["deleted_handlers"], key=lambda x: (x['handler'], x['trigger'])) == [{"policy": "scale_nginx_policy", "trigger": "increase_in_active_requests", "handler": "flame_sfemc"},
{"policy": "scale_nginx_policy", "trigger": "increase_in_running_processes", "handler": "flame_sfemc"},
{"policy": "deadman_policy", "trigger": "no_measurements", "handler": "flame_sfemc"},
{"policy": "scale_nginx_policy", "trigger": "high_requests", "handler": "http://172.40.231.200:9999/"},
{"policy": "scale_nginx_policy", "trigger": "increase_in_active_requests", "handler": "http://172.40.231.200:9999/"},
{"policy": "scale_nginx_policy", "trigger": "increase_in_running_processes", "handler": "http://172.40.231.200:9999/"},
{"policy": "deadman_policy", "trigger": "no_measurements", "handler": "http://172.40.231.200:9999/"}], \
"Incorrect list of deleted handlers"