diff --git a/tests/alarm.py b/tests/alarm.py new file mode 100644 index 0000000..92a69ed --- /dev/null +++ b/tests/alarm.py @@ -0,0 +1,53 @@ +from __future__ import print_function +import sys + + +def get_state(mon_client, alarm_id): + result = get(mon_client, alarm_id) + return result['state'] + + +def get(mon_client, alarm_id): + result = mon_client.alarms.get(**{'alarm_id': alarm_id}) + return result + + +def disable(mon_client, alarm_id): + patch(mon_client, alarm_id, {'enabled': False}) + + +def enable(mon_client, alarm_id): + patch(mon_client, alarm_id, {'enabled': True}) + + +def set_state(mon_client, alarm_id, state): + patch(mon_client, alarm_id, {'state': state}) + new_state = get_state(mon_client, alarm_id) + if new_state != state: + print('Expected new state %s but found %s' % + (state, new_state), file=sys.stderr) + return False + return True + + +def patch(mon_client, alarm_id, fields): + fields['alarm_id'] = alarm_id + mon_client.alarms.patch(**fields) + + +def set_optional_field(name, value, fields): + if value is not None: + fields[name] = value + + +def create(mon_client, name, description, expression, ok_actions, + alarm_actions, undetermined_actions): + fields = {} + fields['name'] = name + fields['expression'] = expression + set_optional_field('description', description, fields) + set_optional_field('ok_actions', ok_actions, fields) + set_optional_field('alarm_actions', alarm_actions, fields) + set_optional_field('undetermined_actions', undetermined_actions, fields) + result = mon_client.alarms.create(**fields) + return result['id'] diff --git a/tests/notification.py b/tests/notification.py index f443b66..79b21e7 100644 --- a/tests/notification.py +++ b/tests/notification.py @@ -8,8 +8,8 @@ import json import subprocess -def find_notifications(alarm_id): - args = ['sudo', 'cat', '/var/mail/root'] +def find_notifications(alarm_id, user): + args = ['sudo', 'cat', '/var/mail/' + user] result = [] try: stdout = subprocess.check_output(args) @@ -20,3 +20,30 @@ def find_notifications(alarm_id): if alarm_id in line: result.append(json.loads(line)['state']) return result + + +def create(mon_client, name, email): + kwargs = {'name': name, 'address': email, 'type': 'EMAIL'} + result = mon_client.notifications.create(**kwargs) + return result['id'] + + +def update(mon_client, notification_id, name, email): + kwargs = {'id': notification_id, 'name': name, 'address': email, + 'type': 'EMAIL'} + result = mon_client.notifications.update(**kwargs) + return result['id'] + + +def get(mon_client, notification_id): + kwargs = {'notification_id': notification_id} + result = mon_client.notifications.get(**kwargs) + return result + + +def find_by_name(mon_client, name): + result = mon_client.notifications.list(**{}) + for notification in result: + if notification['name'] == name: + return notification + return None diff --git a/tests/notification_crud.py b/tests/notification_crud.py new file mode 100644 index 0000000..55b20b7 --- /dev/null +++ b/tests/notification_crud.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# +"""Notification Engine Test + CRUD test +""" +from __future__ import print_function +import sys +import platform +import os +import time +from monclient import client +import notification +import monclient.exc as exc +import alarm + + +def call_mon_api(method, fields): + + try: + resp = method(**fields) + except exc.HTTPException as he: + print(he.code) + print(he.message) + sys.exit(1) + else: + return resp + + +def cycle_states(mon_client, alarm_id, states): + print('Cycling alarm states through %s' % (states)) + for state in states: + alarm.set_state(mon_client, alarm_id, state) + + +def check_notification(alarm_id, user, expected_state, existing): + for i in range(0, 20): + notifications = notification.find_notifications(alarm_id, user) + if len(notifications) > existing: + break + time.sleep(1) + + if len(notifications) <= existing: + print('Did not receive new notification in %d seconds for user %s' % + (i+1, user), file=sys.stderr) + return False + + if (len(notifications) - existing) > 1: + print('Received %d new notifications instead of 1 for user %s' % + (len(notifications) - existing, user), file=sys.stderr) + return False + + new_state = notifications[existing] + if new_state != expected_state: + print('Expected state %s for user %s but found state %s' % + (expected_state, user, new_state), file=sys.stderr) + return False + print('Found notification for state %s for user %s in %d seconds' % + (expected_state, user, i), file=sys.stderr) + return True + + +def find_or_create_notification(mon_client, name, email): + notif = notification.find_by_name(mon_client, name) + if notif is not None: + if notif['address'] != email: + print('Notification named %s exists but address is %s not %s' % + (name, notif['address'], email), file=sys.stderr) + return None + return notif['id'] + else: + return notification.create(mon_client, name, email) + + +def check_notifications(alarm_id, email1, email2, email3, state1, state2, + state3, existing): + if not check_notification(alarm_id, email1, state1, existing): + return False + if not check_notification(alarm_id, email2, state2, existing): + return False + if not check_notification(alarm_id, email3, state3, existing): + return False + return True + + +def print_actions(state, action_ids): + addresses = [] + for action_id in action_ids: + action_notification = notification.get(mon_client, action_id) + addresses.append(action_notification['address']) + print("Notification for %s state sent to %s" % (state, addresses)) + + +def print_notification_setup(mon_client, alarm_id): + alarm_data = alarm.get(mon_client, alarm_id) + print_actions('ALARM', alarm_data['alarm_actions']) + print_actions('OK', alarm_data['ok_actions']) + print_actions('UNDETERMINED', alarm_data['undetermined_actions']) + + +def main(): + hostname = platform.node() + + if hostname == 'mini-mon': + api_host = '192.168.10.4' + elif hostname == 'kafka': + api_host = 'localhost' + else: + print('This test must be run on the kafka or mini-mon VM, aborting', + file=sys.stderr) + return 1 + + # Delete notification for OK.Cycle OK, ALARM, UNDETERMINED + # Ensure proper notifications got written for ALARM, UNDETERMINED + + states = ['OK', 'ALARM', 'UNDETERMINED'] + api_version = '2_0' + endpoint = 'http://' + api_host + ':8080/v2.0' + kwargs = {'token': '82510970543135'} + global mon_client + mon_client = client.Client(api_version, endpoint, **kwargs) + + try: + # Create 3 notifications with different emails, root, kafka, mon-agent + email1 = "root" + email2 = "kafka" + email3 = "mon-agent" + notification_id_1 = find_or_create_notification(mon_client, email1, + email1 + "@localhost") + notification_id_2 = find_or_create_notification(mon_client, email2, + email2 + "@localhost") + notification_id_3 = find_or_create_notification(mon_client, email3, + email3 + "@localhost") + + # Create an alarm. Cycle OK, ALARM, UNDETERMINED, + alarm_name = "Test Notifications-" + str(os.getpid()) + expr = 'max(not_real_metric{}) > 10' + alarm_id = alarm.create(mon_client, alarm_name, None, expr, + notification_id_1, notification_id_2, + notification_id_3) + print('Created Alarm %s' % alarm_id) + print_notification_setup(mon_client, alarm_id) + print('Test initial cycle of Alarms') + cycle_states(mon_client, alarm_id, states) + + # Ensure proper notifications got written to each + if not check_notifications(alarm_id, email1, email2, email3, + states[0], states[1], states[2], 0): + return 1 + + # Disable alarm. Cycle OK, ALARM, UNDETERMINED, + print('Disable Alarm') + alarm.disable(mon_client, alarm_id) + cycle_states(mon_client, alarm_id, states) + + # Ensure no new notifications + if not check_notifications(alarm_id, email1, email2, email3, + states[0], states[1], states[2], 0): + return 1 + + # Enable alarm. Cycle OK, ALARM, UNDETERMINED + print('Enable Alarm') + alarm.enable(mon_client, alarm_id) + cycle_states(mon_client, alarm_id, states) + + # Ensure proper notifications got written to each + if not check_notifications(alarm_id, email1, email2, email3, + states[0], states[1], states[2], 1): + return 1 + + # Switch Alarm notifications around. Cycle OK, ALARM, UNDETERMINED, + print("Switch around Alarm notifications") + alarm.patch(mon_client, alarm_id, + {'ok_actions': [notification_id_2], + 'alarm_actions': [notification_id_3], + 'undetermined_actions': [notification_id_1]}) + print_notification_setup(mon_client, alarm_id) + cycle_states(mon_client, alarm_id, states) + + # Ensure proper notifications got written to each + if not check_notifications(alarm_id, email2, email3, email1, + states[0], states[1], states[2], 2): + return 1 + + # Switch the email addresses around. Cycle OK, ALARM, UNDETERMINED, + # Ensure proper notifications got written to each + return 0 + except exc.HTTPException as he: + print(he.code) + print(he.message) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/notification_cycleTest.py b/tests/notification_cycleTest.py index 542020d..fcad619 100644 --- a/tests/notification_cycleTest.py +++ b/tests/notification_cycleTest.py @@ -8,34 +8,17 @@ import sys import time from monclient import client from notification import find_notifications -import monclient.exc as exc - - -def call_mon_api(method, fields): - - try: - resp = method(**fields) - except exc.HTTPException as he: - print(he.code) - print(he.message) - sys.exit(1) - else: - return resp +import alarm def find_alarm_id(mon_client): - result = call_mon_api(mon_client.alarms.list, {}) + result = mon_client.alarms.list(**{}) if len(result) == 0: print('No existing alarms, create one and rerun test', file=sys.stderr) return None return result[0]['id'] -def get_alarm_state(mon_client, alarm_id): - result = call_mon_api(mon_client.alarms.get, {'alarm_id': alarm_id}) - return result['state'] - - def main(): if len(sys.argv) == 1: print('usage: %s count [alarm-id]' % sys.argv[0], file=sys.stderr) @@ -55,32 +38,26 @@ def main(): if alarm_id is None: return 1 + user = 'root' start_time = time.time() - initial_state = get_alarm_state(mon_client, alarm_id) + initial_state = alarm.get_state(mon_client, alarm_id) state = initial_state - fields = {'alarm_id': alarm_id} - existing_notifications = find_notifications(alarm_id) + existing_notifications = find_notifications(alarm_id, user) notifications_sent = num_cycles * 2 for _ in range(0, notifications_sent): if state == 'OK': state = 'ALARM' else: state = 'OK' - fields['state'] = state - call_mon_api(mon_client.alarms.patch, fields) - new_state = get_alarm_state(mon_client, alarm_id) - if new_state != state: - print('Expected new state %s but found %s' % - (state, new_state), file=sys.stderr) + if not alarm.set_state(mon_client, alarm_id, state): return 1 - # time.sleep(1) print("Took %d seconds to send %d alarm state changes" % ((time.time() - start_time), num_cycles * 2)) for i in range(0, 30): - notifications = find_notifications(alarm_id) + notifications = find_notifications(alarm_id, user) notifications_found = len(notifications) - len(existing_notifications) if notifications_found >= notifications_sent: break