From 3c0775570ae26f6351652be5882ed5f406cf16b6 Mon Sep 17 00:00:00 2001 From: Tim Kuhlman Date: Fri, 26 Jun 2015 16:21:36 -0600 Subject: [PATCH] Moved the smoke test to the ci repo and cleaned up old tests. Change-Id: Ic6e24dc1166b8bf7461103b5ebe2d47c14ccf4fa --- devstack.yml | 2 +- tests/env.sh => env.sh | 0 mini-mon.yml | 3 +- smoke.yml | 36 +++- smoke2.yml | 33 --- tests/README.md | 3 - tests/alarm.py | 65 ------ tests/alarm_crud.py | 158 -------------- tests/cli_wrapper.py | 110 ---------- tests/measurement_test.py | 94 --------- tests/notification.py | 32 --- tests/notification_crud.py | 171 --------------- tests/notification_cycleTest.py | 78 ------- tests/smoke.py | 357 -------------------------------- tests/smoke_configs.py | 74 ------- tests/utils.py | 157 -------------- 16 files changed, 35 insertions(+), 1338 deletions(-) rename tests/env.sh => env.sh (100%) delete mode 100644 smoke2.yml delete mode 100644 tests/README.md delete mode 100644 tests/alarm.py delete mode 100755 tests/alarm_crud.py delete mode 100644 tests/cli_wrapper.py delete mode 100644 tests/measurement_test.py delete mode 100644 tests/notification.py delete mode 100755 tests/notification_crud.py delete mode 100755 tests/notification_cycleTest.py delete mode 100755 tests/smoke.py delete mode 100644 tests/smoke_configs.py delete mode 100644 tests/utils.py diff --git a/devstack.yml b/devstack.yml index 77cbccf..c8c5b4f 100644 --- a/devstack.yml +++ b/devstack.yml @@ -19,7 +19,7 @@ apt: name=python-virtualenv tasks: - name: Setup the monasca cli credentials in the default environment - copy: src=tests/env.sh dest=/etc/profile.d/monasca_cli.sh owner=root group=root mode=0644 + copy: src=env.sh dest=/etc/profile.d/monasca_cli.sh owner=root group=root mode=0644 tags: - cli - name: Update cli diff --git a/tests/env.sh b/env.sh similarity index 100% rename from tests/env.sh rename to env.sh diff --git a/mini-mon.yml b/mini-mon.yml index 6bc4e21..c284593 100644 --- a/mini-mon.yml +++ b/mini-mon.yml @@ -46,7 +46,7 @@ alive_test: ssh tasks: - name: Setup the monasca cli credentials in the default environment - copy: src=tests/env.sh dest=/etc/profile.d/monasca_cli.sh owner=root group=root mode=0644 + copy: src=env.sh dest=/etc/profile.d/monasca_cli.sh owner=root group=root mode=0644 tags: - cli - name: Update cli @@ -82,5 +82,4 @@ roles: - {role: monasca-default-alarms, tags: [alarms]} -- include: smoke2.yml - include: smoke.yml diff --git a/smoke.yml b/smoke.yml index b082530..ac2a2c2 100644 --- a/smoke.yml +++ b/smoke.yml @@ -1,8 +1,38 @@ - hosts: mini-mon + sudo: yes + vars: + host_ip: "{{mini_mon}}" + test_base: /opt/monasca/ + test_url: https://api.github.com/repos/hpcloud-mon/monasca-ci/tarball/master tasks: + - name: Fetch the monasca-ci tests + get_url: dest="{{test_base}}/monasca-ci.tar.gz" url="{{test_url}}" + register: download + + - name: UI - Uncompress the monasca-ci tar + unarchive: copy=no dest="{{test_base}}" src="{{test_base}}/monasca-ci.tar.gz" + when: download | changed + # In Ansible 1.8 this was in the unarchive output, in 2.0 there is list_files option you can add to unarchive but in 1.9 we must use this + # command to discover the tar dir. This method will work for the other versions also. + - name: Discover the tar path + command: tar -tzf "{{test_base}}/monasca-ci.tar.gz" + register: tarpath + + - name: Install the influxdb python library + pip: name=influxdb virtualenv="{{monasca_virtualenv_dir}}" + when: database_type == 'influxdb' + + - name: Copy the template locally + fetch: src="{{test_base}}/{{tarpath.stdout_lines[0]}}/tests/smoke/smoke2_configs.py.j2" dest=tests/ flat=yes + - name: Populate config vars + template: src="tests/smoke2_configs.py.j2" dest="{{test_base}}/{{tarpath.stdout_lines[0]}}/tests/smoke/smoke2_configs.py" + + - name: Run the smoke2 test + command: "{{monasca_virtualenv_dir}}/bin/python {{test_base}}/{{tarpath.stdout_lines[0]}}/tests/smoke/smoke2.py" + register: smoke2 + - debug: var=smoke2.stdout_lines + - name: Run the smoke test - command: /vagrant/tests/smoke.py - environment: - PATH: "{{ansible_env.PATH}}:{{monasca_virtualenv_dir}}/bin" + command: "{{monasca_virtualenv_dir}}/bin/python {{test_base}}/{{tarpath.stdout_lines[0]}}/tests/smoke/smoke.py" register: smoke - debug: var=smoke.stdout_lines diff --git a/smoke2.yml b/smoke2.yml deleted file mode 100644 index 3d4d353..0000000 --- a/smoke2.yml +++ /dev/null @@ -1,33 +0,0 @@ -- hosts: mini-mon - sudo: yes - vars: - host_ip: "{{mini_mon}}" - test_base: /opt/monasca/ - test_url: https://api.github.com/repos/hpcloud-mon/monasca-ci/tarball/master - tasks: - - name: Fetch the monasca-ci tests - get_url: dest="{{test_base}}/monasca-ci.tar.gz" url="{{test_url}}" - register: download - - - name: UI - Uncompress the monasca-ci tar - unarchive: copy=no dest="{{test_base}}" src="{{test_base}}/monasca-ci.tar.gz" - when: download | changed - # In Ansible 1.8 this was in the unarchive output, in 2.0 there is list_files option you can add to unarchive but in 1.9 we must use this - # command to discover the tar dir. This method will work for the other versions also. - - name: Discover the tar path - command: tar -tzf "{{test_base}}/monasca-ci.tar.gz" - register: tarpath - - - name: Install the influxdb python library - pip: name=influxdb virtualenv="{{monasca_virtualenv_dir}}" - when: database_type == 'influxdb' - - - name: Copy the template locally - fetch: src="{{test_base}}/{{tarpath.stdout_lines[0]}}/tests/smoke/smoke2_configs.py.j2" dest=tests/ flat=yes - - name: Populate config vars - template: src="tests/smoke2_configs.py.j2" dest="{{test_base}}/{{tarpath.stdout_lines[0]}}/tests/smoke/smoke2_configs.py" - - - name: Run the smoke2 test - command: "{{monasca_virtualenv_dir}}/bin/python {{test_base}}/{{tarpath.stdout_lines[0]}}/tests/smoke/smoke2.py" - register: smoke2 - - debug: var=smoke2.stdout_lines diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index cf386f8..0000000 --- a/tests/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Test notifications -- run smoke.py from within the mini-mon vm for a full test of Monasca -- env.sh can be sourced to set the proper env for using the python-monascaclient diff --git a/tests/alarm.py b/tests/alarm.py deleted file mode 100644 index d4b58c1..0000000 --- a/tests/alarm.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import print_function -import sys -# -""" - Utility methods for CRUD of alarms -""" - - -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, {'actions_enabled': False}) - - -def enable(mon_client, alarm_id): - patch(mon_client, alarm_id, {'actions_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=None, - alarm_actions=None, undetermined_actions=None): - 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'] - - -def find_alarm_byname(mon_client, alarm_name): - alarms = mon_client.alarms.list(**{}) - for alarm in alarms: - if alarm['name'] == alarm_name: - return alarm - return None diff --git a/tests/alarm_crud.py b/tests/alarm_crud.py deleted file mode 100755 index 8220ca8..0000000 --- a/tests/alarm_crud.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python -# -""" Threshold Engine Test - CRUD test -""" -from __future__ import print_function -import sys -import os -import time -import cli_wrapper -import utils - - -def output_metrics(alarm_id, expected_state, metrics): - print('Generating metrics, waiting for state change to %s' % - expected_state) - hostnames = ['AA', 'BB', 'CC'] - for x in range(0, 90): - for metric in metrics: - metric_name = metric[0] - dimensions = metric[1] - args = ['metric-create', '--dimensions'] - hostname = hostnames[x % len(hostnames)] - args.append(dimensions + ',' + 'hostname=' + hostname) - args.append(metric_name) - args.append('42') - cli_wrapper.run_mon_cli(args, useJson=False) - - state = cli_wrapper.get_alarm_state(alarm_id) - if state == expected_state: - break - time.sleep(1) - - if state != expected_state: - print('Did not change to state %s instead was %s in %d seconds' % - (expected_state, state, x), file=sys.stderr) - return False - - print('Changed to state %s in %d seconds' % (state, x)) - return True - - -def main(): - utils.setup_cli() - - alarm_name = 'alarm_crud' - metric_name = 'alarm_crud' - base_dimension = 'service=alarm_test' - expression = 'max(%s{%s}) > 0' % (metric_name, base_dimension) - description = alarm_name + ' Description' - cli_wrapper.delete_alarm_if_exists(alarm_name) - - # Add Alarm - alarm_id = cli_wrapper.create_alarm(alarm_name, expression, - description=description) - print('Created Alarm with id %s' % alarm_id) - - # Ensure it is created in the right state - initial_state = 'UNDETERMINED' - if not utils.check_alarm_state(alarm_id, initial_state): - return 1 - - states = [] - states.append(initial_state) - - # List Alarms, make sure new one shows up - alarm_json = cli_wrapper.find_alarm_by_name(alarm_name) - if alarm_json is None: - print('Did not find alarm named %s using alarm-list' % - alarm_name, file=sys.stderr) - return 1 - - if alarm_id != alarm_json['id']: - print('Alarm %s has wrong id, expected %s but was %s' % - (alarm_name, alarm_id, alarm_json['id']), file=sys.stderr) - return 1 - - # Output metrics that will cause it to go ALARM - # Wait for it to change to ALARM - if not output_metrics(alarm_id, 'ALARM', [[metric_name, base_dimension]]): - return 1 - - states.append('ALARM') - - # Modify Alarm by adding new expression that will cause it to go OK - print('Modify Alarm expression so it will go to OK') - new_metric_name = 'other_metric' - new_dimension = 'dim=42' - new_expression = '%s and max(%s{%s}) > 100' % (expression, - new_metric_name, - new_dimension) - - alarm_json = cli_wrapper.patch_alarm(alarm_id, '--expression', - new_expression) - if alarm_json['expression'] != new_expression: - print('Did not change expression to %s instead was %s' % - (new_expression, alarm_json['expression']), file=sys.stderr) - return 1 - - # Output metrics that will cause it to go OK - # Wait for it to change to OK - - if not output_metrics(alarm_id, 'OK', [[metric_name, base_dimension], - [new_metric_name, new_dimension]]): - return 1 - - states.append('OK') - - # Modify Alarm by deleting expression that will cause Alarm to go ALARM - print('Delete Alarm sub expression so it will go to ALARM') - cli_wrapper.patch_alarm(alarm_id, '--expression', expression) - - # Output metrics that will cause it to go ALARM - # Wait for it to change to ALARM - print('Output extra dimensions to make sure match occurs') - extra_dimension = base_dimension + ',Extra=More' - if not output_metrics(alarm_id, 'ALARM', - [[metric_name, extra_dimension]]): - return 1 - - states.append('ALARM') - - # Modify Alarm by setting alarm state to OK - print('Set Alarm to OK, wait for transition back to ALARM') - - cli_wrapper.change_alarm_state(alarm_id, 'OK') - states.append('OK') - - # Output metrics that will cause it to go back to ALARM - # Wait for it to change to ALARM - if not output_metrics(alarm_id, 'ALARM', - [[metric_name, base_dimension], - [new_metric_name, new_dimension]]): - return 1 - - states.append('ALARM') - - # Query History - # Delete ALARM - print('Delete alarm') - cli_wrapper.run_mon_cli(['alarm-delete', alarm_id], useJson=False) - - # Ensure it can't be queried - if cli_wrapper.find_alarm_by_name(alarm_name) is not None: - print('Still found alarm %s after it was deleted' % alarm_name, - file=sys.stderr) - return 1 - - # Query History, ensure they still show up - if not utils.check_alarm_history(alarm_id, states): - return 1 - - # Success - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/cli_wrapper.py b/tests/cli_wrapper.py deleted file mode 100644 index 69f12e8..0000000 --- a/tests/cli_wrapper.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -""" Wrapper code for running the CLI as a process. -""" -from __future__ import print_function -import sys -import subprocess -import json -import os - - -def find_obj_for_name(object_json, name): - for obj in object_json: - this_name = obj['name'] - if name == this_name: - return obj - return None - - -def find_alarm_definition_by_name(name): - alarm_json = run_mon_cli(['alarm-definition-list']) - return find_obj_for_name(alarm_json, name) - - -def delete_alarm_definition_if_exists(name): - alarm_json = find_alarm_definition_by_name(name) - if alarm_json: - run_mon_cli(['alarm-definition-delete', alarm_json['id']], - useJson=False) - - -def delete_notification_if_exists(notification_name): - notification_json = run_mon_cli(['notification-list']) - notification = find_obj_for_name(notification_json, notification_name) - if notification: - run_mon_cli(['notification-delete', notification['id']], useJson=False) - - -def run_mon_cli(args, useJson=True): - if useJson: - args.insert(0, '--json') - args.insert(0, 'monasca') - env = os.environ.copy() - env['PYTHONIOENCODING'] = "utf-8" - try: - stdout = subprocess.check_output(args, env=env) - if useJson: - return json.loads(stdout) - else: - return stdout - except subprocess.CalledProcessError as e: - print(e, file=sys.stderr) - sys.exit(1) - - -def create_notification(notification_name, - notification_addr, - notification_type): - print('Creating notification') - result_json = run_mon_cli(['notification-create', notification_name, - notification_type, notification_addr]) - - # Parse out id - notification_id = result_json['id'] - return notification_id - - -def get_alarm_state(alarm_id): - result_json = run_mon_cli(['alarm-show', alarm_id]) - return result_json['state'] - - -def change_alarm_state(alarm_id, new_state): - print('Changing Alarm state to %s' % new_state) - result_json = run_mon_cli(['alarm-patch', alarm_id, "--state", new_state]) - if result_json['state'] != new_state: - print('Alarm patch failed, expected state of %s but was %s' % - (result_json['state'], new_state), file=sys.stderr) - return False - return True - - -def find_alarms_for_definition(alarm_definition_id): - result_json = run_mon_cli(['alarm-list', "--alarm-definition", - alarm_definition_id]) - return [alarm['id'] for alarm in result_json] - - -def create_alarm_definition(name, expression, description=None, - ok_notif_id=None, alarm_notif_id=None, - undetermined_notif_id=None): - args = ['alarm-definition-create'] - add_argument_if_given(args, '--description', description) - add_argument_if_given(args, '--alarm-actions', alarm_notif_id) - add_argument_if_given(args, '--ok-actions', ok_notif_id) - add_argument_if_given(args, '--undetermined-actions', - undetermined_notif_id) - args.append(name) - args.append(expression) - print('Creating alarm definition') - result_json = run_mon_cli(args) - - # Parse out id - return result_json['id'] - - -def add_argument_if_given(args, arg, value): - if value is not None: - args.append(arg) - args.append(value) diff --git a/tests/measurement_test.py b/tests/measurement_test.py deleted file mode 100644 index 89d0adf..0000000 --- a/tests/measurement_test.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python -# -"""measurements -""" -from __future__ import print_function -import sys -import time -import pytz -from datetime import datetime -from monascaclient import client -import monascaclient.exc as exc -import utils - - -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 create_timestamp(seconds): - utcTimestamp = pytz.utc.localize(datetime.utcfromtimestamp(seconds)) - return utcTimestamp.strftime("%Y-%m-%dT%H:%M:%S%z") - - -def main(): - if len(sys.argv) == 1: - print('usage: %s metric_name count' % sys.argv[0], file=sys.stderr) - return 1 - - mon_client = utils.create_mon_client() - - metric_start_time = time.time() - metric_name = sys.argv[1] - num_metrics_to_send = int(sys.argv[2]) - dimensions = {'Test_Send': 'Number_1'} # Should be arg - start_time = time.time() - fields = {'name': metric_name} - fields['dimensions'] = dimensions - for val in range(0, num_metrics_to_send): - fields['value'] = str(val) - fields['timestamp'] = time.time() - call_mon_api(mon_client.metrics.create, fields) - # time.sleep(1) - - print("Took %d seconds to send %d measurements" % - ((time.time() - start_time), num_metrics_to_send)) - metric_end_time = time.time() - # API requires end time to be greater than start time - if (metric_end_time - metric_start_time) < 1: - metric_end_time = metric_start_time + 1 - start_timestamp = create_timestamp(metric_start_time) - end_timestamp = create_timestamp(metric_end_time) - fields = {'name': metric_name} - fields['dimensions'] = dimensions - fields['start_time'] = start_timestamp - fields['end_time'] = end_timestamp - for i in range(0, 30): - result = call_mon_api(mon_client.metrics.list_measurements, fields) - if len(result) > 0: - measurements = result[0]['measurements'] - if len(measurements) >= num_metrics_to_send: - break - print('Found %d of %d metrics so far' % - (len(measurements), num_metrics_to_send)) - time.sleep(1) - - if len(result) == 0: - print('Did not receive any metrics in %d seconds' % i, file=sys.stderr) - return 1 - - if len(measurements) != num_metrics_to_send: - print('Expected %d measurements but found %d' % - (num_metrics_to_send, len(measurements)), file=sys.stderr) - return 1 - print('Took %d seconds for metrics to fully arrive' % i) - expected = num_metrics_to_send - 1 - result = 0 - for index in range(num_metrics_to_send, 0): - value = measurements[index] - if value[2] != expected: - print('Expected %d but found %d for %d' % - (expected, value[2], index), file=sys.stderr) - expected = expected - 1 - return result - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/notification.py b/tests/notification.py deleted file mode 100644 index 7ce16d8..0000000 --- a/tests/notification.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import print_function - -""" - Utility methods for notifications -""" - - -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 deleted file mode 100755 index 8fa9ab3..0000000 --- a/tests/notification_crud.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python -# -"""Notification Engine Test - CRUD test -""" -from __future__ import print_function -import sys -import os -import time -import notification -import monascaclient.exc as exc -import alarm -import utils - - -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 = utils.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(mon_client, 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(mon_client, 'ALARM', alarm_data['alarm_actions']) - print_actions(mon_client, 'OK', alarm_data['ok_actions']) - print_actions(mon_client, 'UNDETERMINED', - alarm_data['undetermined_actions']) - - -def main(): - if not utils.ensure_has_notification_engine(): - return 1 - - # Delete notification for OK.Cycle OK, ALARM, UNDETERMINED - # Ensure proper notifications got written for ALARM, UNDETERMINED - - states = ['OK', 'ALARM', 'UNDETERMINED'] - mon_client = utils.create_mon_client() - - try: - # Create 3 notifications with different emails, root, kafka, - # and monasca-agent - email1 = "root" - email2 = "kafka" - email3 = "monasca-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 deleted file mode 100755 index b041abc..0000000 --- a/tests/notification_cycleTest.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -"""Notification Engine Test - Cycle the state of an Alarm the given number of times -""" -from __future__ import print_function -import sys -import time -import notification -import alarm -import utils - - -def main(): - if len(sys.argv) == 1: - print('usage: %s count [alarm-id]' % sys.argv[0], file=sys.stderr) - return 1 - - if not utils.ensure_has_notification_engine(): - return 1 - - mon_client = utils.create_mon_client() - num_cycles = int(sys.argv[1]) - - alarm_name = 'notification_cycleTest' - alarm_json = alarm.find_alarm_byname(mon_client, alarm_name) - if alarm_json is not None: - alarm_id = alarm_json['id'] - else: - existing = notification.find_by_name(mon_client, alarm_name) - if existing is not None: - notification_id = existing['id'] - else: - notification_id = notification.create(mon_client, alarm_name, - "root@localhost") - alarm_id = alarm.create(mon_client, alarm_name, None, 'max(cc) > 100', - notification_id, notification_id, - notification_id) - - user = 'root' - start_time = time.time() - initial_state = alarm.get_state(mon_client, alarm_id) - state = initial_state - - existing_notifications = utils.find_notifications(alarm_id, user) - notifications_sent = num_cycles * 2 - for _ in range(0, notifications_sent): - if state == 'OK': - state = 'ALARM' - else: - state = 'OK' - if not alarm.set_state(mon_client, alarm_id, state): - return 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 = utils.find_notifications(alarm_id, user) - notifications_found = len(notifications) - len(existing_notifications) - if notifications_found >= notifications_sent: - break - print('Found %d of %d expected notifications so far' % - (notifications_found, notifications_sent)) - time.sleep(1) - - if notifications_found < notifications_sent: - print('Expected %d notifications but found %d' % - (notifications_sent, notifications_found), file=sys.stderr) - return 1 - - print('Took %d seconds for notifications to fully arrive' % i) - result = 0 - return result - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/smoke.py b/tests/smoke.py deleted file mode 100755 index 14aa4bb..0000000 --- a/tests/smoke.py +++ /dev/null @@ -1,357 +0,0 @@ -#!/opt/monasca/bin/python -# -"""smoke - Runs a smoke test of the monitoring installation on mini-mon to ensure - the components (other than the UI) are functioning. The code tests these - components: - 1. Agent - ensures metrics are being sent to API - 2. API - ensures alarm definitions can created, listed, etc. Ensure - metrics and alarms can be queried - 3. CLI - used to talk to the API - 4. Persister - ensures metrics and alarm history has been persisted - in database because API can query them - 5. Threshold Engine - ensures alarms are created and change state - 6. Notification Engine - ensures email notifications are sent to the - local system - This must be run on either the mini-mon VM for the single VM mode or - on the kafka VM in the multi VM mode. - - If the tests are to be run in a different environment other than mini-mon, - the environment variables below can be set and the smoke will use those - instead of the mini-mon credentials and settings: - - OS_USERNAME - OS_PASSWORD - OS_PROJECT_NAME - OS_AUTH_URL - - TODO: - 1. Add more logic to give ideas of why a particular step failed, for - example, alarm did not get created because metrics weren't being - received -""" - -from __future__ import print_function -import argparse -import sys -import os -import time -import cli_wrapper -import utils -import datetime -import psutil -import smoke_configs - -config = smoke_configs.test_config["default"] - - -# parse command line arguments -def parse_commandline_args(): - parser = argparse.ArgumentParser() - parser.add_argument('-c', '--config', nargs='?', default='default', - help='select configuration ') - return parser.parse_args() - - -def set_config(config_name): - global config - try: - config = smoke_configs.test_config[config_name] - print('Using {} Configuration'.format(config_name)) - return True - except KeyError: - print('Could not find config "{}"'.format(config_name), file=sys.stderr) - return False - - -def get_metrics(name, dimensions, since): - dimensions_arg = '' - for key, value in dimensions.iteritems(): - if dimensions_arg != '': - dimensions_arg = dimensions_arg + ',' - dimensions_arg = dimensions_arg + key + '=' + value - return cli_wrapper.run_mon_cli(['measurement-list', '--dimensions', - dimensions_arg, name, since]) - - -def cleanup(notification_name, alarm_definition_name): - cli_wrapper.delete_alarm_definition_if_exists(alarm_definition_name) - cli_wrapper.delete_notification_if_exists(notification_name) - - -def wait_for_alarm_state_change(alarm_id, old_state): - # Wait for it to change state - print('Waiting for alarm to change state from {}'.format(old_state)) - for x in range(0, 250): - time.sleep(1) - state = cli_wrapper.get_alarm_state(alarm_id) - if state != old_state: - print('Alarm state changed to {} in {} seconds'.format(state, x)) - return state - print('State never changed from {} in {} seconds'.format(old_state, x), - file=sys.stderr) - return None - - -def check_notifications(alarm_id, state_changes): - print("Checking Notification Engine") - if not os.path.isfile('/etc/monasca/notification.yaml'): - print('Notification Engine not installed on this VM,' + - ' skipping Notifications test', - file=sys.stderr) - return False - - notifications = utils.find_notifications(alarm_id, "root") - if len(notifications) != len(state_changes): - print('Expected {} notifications but only found {}'.format( - len(state_changes), len(notifications)), file=sys.stderr) - return False - - index = 0 - for expected in state_changes: - actual = notifications[index] - if actual != expected: - print('Expected {} but found {} for state change {}'.format( - expected, actual, index+1), file=sys.stderr) - return False - index = index + 1 - print('Received email notifications as expected') - - return True - - -def count_metrics(metric_name, metric_dimensions, since): - # Query how many metrics there are for the Alarm - metric_json = get_metrics(metric_name, metric_dimensions, since) - if len(metric_json) == 0: - print('No measurements received for metric {}{} '.format( - metric_name, metric_dimensions), file=sys.stderr) - return None - - return len(metric_json[0]['measurements']) - - -def ensure_at_least(actual, desired): - if actual < desired: - time.sleep(desired - actual) - - -def wait_for_alarm_creation(alarm_def_id): - print('Waiting for alarm to be created for Alarm Definition {}'.format(alarm_def_id)) - for x in range(0, 30): - time.sleep(1) - alarms = cli_wrapper.find_alarms_for_definition(alarm_def_id) - if len(alarms) == 1: - print('Alarm was created in {} seconds'.format(x)) - return alarms[0] - elif len(alarms) > 1: - print('{} Alarms were created. Only expected 1'.format(len(alarms)), - file=sys.stderr) - return None - - print('Alarm was not created for Alarm Definition {} in {} seconds'.format( - alarm_def_id, x), file=sys.stderr) - return None - - -def smoke_test(): - notification_name = config['notification']['name'] - notification_addr = config['notification']['addr'] - notification_type = config['notification']['type'] - alarm_definition_name = config['alarm']['name'] - metric_name = config['metric']['name'] - metric_dimensions = config['metric']['dimensions'] - statsd_metric_name = config['statsd_metric']['name'] - statsd_metric_dimensions = config['statsd_metric']['dimensions'] - - cleanup(notification_name, alarm_definition_name) - - # Query how many metrics there are for the Alarm - hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1) - hour_ago_str = hour_ago.strftime('%Y-%m-%dT%H:%M:%S') - print('Getting metrics for {}{} '.format(metric_name, metric_dimensions)) - initial_num_metrics = count_metrics(metric_name, metric_dimensions, - hour_ago_str) - - if initial_num_metrics is None or initial_num_metrics == 0: - msg = ('No metric {} with dimensions {} received in last hour'.format( - metric_name, metric_dimensions)) - return False, msg - - print('Getting metrics for {}{} '.format(statsd_metric_name, statsd_metric_dimensions)) - initial_statsd_num_metrics = count_metrics(statsd_metric_name, statsd_metric_dimensions, hour_ago_str) - - # statsd metrics may not have been sent yet, which will return None from the CLI wrapper - if initial_statsd_num_metrics is None: - initial_statsd_num_metrics = 0 - - start_time = time.time() - - # Create Notification through CLI - notif_id = cli_wrapper.create_notification(notification_name, - notification_addr, - notification_type) - - # Create Alarm through CLI - expression = config['alarm']['expression'] - description = config['alarm']['description'] - alarm_def_id = cli_wrapper.create_alarm_definition( - alarm_definition_name, - expression, - description=description, - ok_notif_id=notif_id, - alarm_notif_id=notif_id, - undetermined_notif_id=notif_id) - - # Wait for an alarm to be created - alarm_id = wait_for_alarm_creation(alarm_def_id) - - if alarm_id is None: - received_num_metrics = count_metrics(metric_name, metric_dimensions, - hour_ago_str) - if received_num_metrics == initial_num_metrics: - print('Did not receive any {}{} metrics while waiting'.format(metric_name,metric_dimensions)) - else: - delta = received_num_metrics - initial_num_metrics - print('Received {} {} metrics while waiting'.format(delta, metric_name)) - return False, 'Alarm creation error' - - # Ensure it is created in the right state - initial_state = 'UNDETERMINED' - if not utils.check_alarm_state(alarm_id, initial_state): - msg = 'Alarm is in an invalid initial state' - return False, msg - states = [] - states.append(initial_state) - state = wait_for_alarm_state_change(alarm_id, initial_state) - if state is None: - msg = 'Alarm is in an invalid state' - return False, msg - - if state != 'ALARM': - print('Wrong final state, expected ALARM but was {}'.format(state), - file=sys.stderr) - msg = 'Alarm is in an invalid final state' - return False, msg - states.append(state) - - new_state = 'OK' - states.append(new_state) - if not cli_wrapper.change_alarm_state(alarm_id, new_state): - msg = 'Unable to change Alarm state' - return False, msg - - # There is a bug in the API which allows this to work. Soon that - # will be fixed and this will fail - if len(sys.argv) > 1: - final_state = 'ALARM' - states.append(final_state) - - state = wait_for_alarm_state_change(alarm_id, new_state) - if state is None: - msg = 'Alarm is in an unknown state' - return False, msg - - if state != final_state: - msg = ('Wrong final state, expected {} but was {}'.format(final_state, state)) - return False, msg - - # If the alarm changes state too fast, then there isn't time for the new - # metric to arrive. Unlikely, but it has been seen - ensure_at_least(time.time() - start_time, 35) - change_time = time.time() - start_time - - final_num_metrics = count_metrics(metric_name, metric_dimensions, - hour_ago_str) - if final_num_metrics <= initial_num_metrics: - msg = ('No new metrics received for {}{} in {} seconds'.format(metric_name, metric_dimensions, change_time)) - return False, msg - print('Received {} metrics in {} seconds'.format((final_num_metrics - initial_num_metrics), change_time)) - if not utils.check_alarm_history(alarm_id, states): - msg = 'Invalid alarm history' - return False, msg - - # Notifications are only sent out for the changes, so omit the first state - if not check_notifications(alarm_id, states[1:]): - msg = 'Could not find correct notifications for alarm {}'.format(alarm_id) - return False, msg - - # Check that monasca statsd is sending metrics - # Metrics may take some time to arrive - print('Waiting for statsd metrics') - for x in range(0,30): - final_statsd_num_metrics = count_metrics(statsd_metric_name, statsd_metric_dimensions, hour_ago_str) - if final_statsd_num_metrics > initial_statsd_num_metrics: - break - if x >= 29: - msg = 'No metrics received for statsd metric {}{} in {} seconds'.format( - statsd_metric_name, statsd_metric_dimensions, time.time() - start_time) - return False, msg - time.sleep(1) - print('Received {0} metrics for {1}{2} in {3} seconds'.format(final_statsd_num_metrics - initial_statsd_num_metrics, - statsd_metric_name, - statsd_metric_dimensions, - time.time() - start_time)) - - msg = '' - return True, msg - - -def find_processes(): - """Find_process is meant to validate that all the required processes - are running before starting the smoke test """ - process_missing = [] - process_list = config['system_vars']['expected_processes'] - - for process in process_list: - process_found_flag = False - - for item in psutil.process_iter(): - for cmd in item.cmdline(): - if process in cmd: - process_found_flag = True - break - - if not process_found_flag: - process_missing.append(process) - - if len(process_missing) > 0: # if processes were not found - print ('Process = {} Not Found'.format(process_missing)) - return False - else: - print ('All Mini-Mon Processes Found') - return True - - -def main(): - # May be able to delete this test because the find_process check should - # validate the notification engine present. - if not utils.ensure_has_notification_engine(): - return 1 - - utils.setup_cli() - - # parse the command line arguments - cmd_args = parse_commandline_args() - - if not set_config(cmd_args.config): - return 1 - - print('*****VERIFYING HOST ENVIRONMENT*****') - if find_processes(): - print('*****BEGIN TEST*****') - complete, msg = smoke_test() - if not complete: - print('*****TEST FAILED*****', file=sys.stderr) - print(msg, file=sys.stderr) - return 1 - else: - return 1 - - cleanup(config['notification']['name'], config['alarm']['name']) - print('*****TEST COMPLETE*****') - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/smoke_configs.py b/tests/smoke_configs.py deleted file mode 100644 index aff5b37..0000000 --- a/tests/smoke_configs.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- encoding: utf-8 -*- - -"""configurations for smoke test""" - -import subprocess - -system_vars = { - 'default': { # the default configuration, assumes monasca-vagrant setup - 'expected_processes': ('monasca-persister', 'monasca-notification', - 'kafka', 'zookeeper.jar', 'monasca-api', - 'apache-storm', 'mysqld'), - 'mail_host': 'localhost', - 'metric_host': subprocess.check_output(['hostname', '-f']).strip()}, -} - - -test_config = { - 'default': { # the default configuration, - # simple test of each component of monasca-vagrant - 'system_vars': system_vars['default'], - - 'notification': { - 'name': u'Monasca Smoke Test Ā', - 'addr': 'root@'+system_vars['default']['mail_host'], - 'type': 'EMAIL'}, - - 'alarm': { - 'name': u'high cpu and load Ա', - 'expression': 'max(cpu.system_perc) > 0 and ' + - 'max(load.avg_1_min{hostname=' + - system_vars['default']['metric_host'] + - '}) > 0', - 'description': u'System CPU Utilization exceeds 1% and ' + - u'Load exceeds 3 per measurement period ἀ'}, - - 'metric': { - 'name': 'load.avg_1_min', - 'dimensions': {'hostname': - system_vars['default']['metric_host']}}, - - 'statsd_metric': { - 'name': 'monasca.sent_smtp_count', - 'dimensions': {'hostname': - system_vars['default']['metric_host']}} - }, - - 'webhook': { - 'system_vars': system_vars['default'], - - 'notification': { - 'name': 'Smoke Test Webhook', - 'addr': 'http://127.0.0.1:8080', - 'type': 'WEBHOOK'}, - - 'alarm': { - 'name': 'high cpu and load', - 'expression': 'max(cpu.system_perc) > 0 and ' + - 'max(load.avg_1_min{hostname=' + - system_vars['default']['metric_host'] + - '}) > 0', - 'description': 'System CPU Utilization exceeds 1% and ' + - 'Load exceeds 3 per measurement period'}, - 'metric': { - 'name': 'load.avg_1_min', - 'dimensions': {'hostname': - system_vars['default']['metric_host']}}, - - 'statsd_metric': { - 'name': 'monasca.sent_smtp_count', - 'dimensions': {'hostname': - system_vars['default']['metric_host']}} - - } -} diff --git a/tests/utils.py b/tests/utils.py deleted file mode 100644 index a5f2341..0000000 --- a/tests/utils.py +++ /dev/null @@ -1,157 +0,0 @@ -from __future__ import print_function -import cli_wrapper -import os -import re -import subprocess -import sys -import time -from monascaclient import client -from monasca_agent.common.keystone import Keystone - -""" - Utility methods for testing -""" - - -OS_USERNAME = 'mini-mon' -OS_PASSWORD = 'password' -OS_PROJECT_NAME = 'mini-mon' -OS_AUTH_URL = 'http://192.168.10.5:35357/v3/' - - -def check_alarm_history(alarm_id, states): - transitions = len(states) - 1 - print('Checking Alarm History') - # May take some time for Alarm history to flow all the way through - for _ in range(0, 20): - result_json = cli_wrapper.run_mon_cli(['alarm-history', alarm_id]) - if len(result_json) >= transitions: - break - time.sleep(4) - - result = True - if transitions != len(result_json): - print('Wrong number of history entries, expected %d but was %d' % - (transitions, len(result_json)), file=sys.stderr) - return False - # Alarm history is sorted by date - index = 0 - for i in range(0, transitions): - old_state = states[i] - new_state = states[i+1] - alarm_json = result_json[index] - if not check_expected(old_state, alarm_json['old_state'], 'old_state', - i): - result = False - if not check_expected(new_state, alarm_json['new_state'], 'new_state', - i): - result = False - if not check_expected(alarm_id, alarm_json['alarm_id'], 'alarm_id', - i): - result = False - index = index + 1 - - if result: - print('Alarm History is OK') - return result - - -def check_expected(expected, actual, what, index): - if (expected == actual): - return True - print('Wrong %s for alarm history expected %s but was %s transition %d' % - (what, expected, actual, index+1), file=sys.stderr) - return False - - -def check_alarm_state(alarm_id, expected): - state = cli_wrapper.get_alarm_state(alarm_id) - if state != expected: - print('Wrong initial alarm state, expected %s but is %s' % - (expected, state)) - return False - return True - - -def get_api_host(): - # Determine if we are running on multiple VMs or just the one - if os.path.isfile('/etc/mon/mon-api-config.yml'): - return 'localhost' - else: - return '192.168.10.4' - - -def set_if_not_env(name, default): - if name not in os.environ: - os.environ[name] = default - elif default != os.environ[name]: - print('%s already set to %s' % (name, os.environ[name])) - - -def setup_cli(): - api_host = get_api_host() - - # These need to be set because we are invoking the CLI as a process - set_if_not_env('OS_USERNAME', OS_USERNAME) - set_if_not_env('OS_PASSWORD', OS_PASSWORD) - set_if_not_env('OS_PROJECT_NAME', OS_PROJECT_NAME) - set_if_not_env('OS_AUTH_URL', OS_AUTH_URL) - os.environ['http_proxy'] = '' - os.environ['https_proxy'] = '' - os.environ['HTTP_PROXY'] = '' - os.environ['HTTPS_PROXY'] = '' - - -def create_mon_client(): - api_host = get_api_host() - - token = get_token(OS_USERNAME, OS_PASSWORD, OS_PROJECT_NAME, - OS_AUTH_URL) - - api_version = '2_0' - endpoint = 'http://' + api_host + ':8080/v2.0' - kwargs = {'token': token} - return client.Client(api_version, endpoint, **kwargs) - - -def get_token(os_username, os_password, os_project_name, os_auth_url): - kwargs = { 'keystone_url': os_auth_url, - 'username': os_username, - 'password': os_password, - 'project_domain_name':os_project_name} - keystone = Keystone(kwargs) - - return keystone.refresh_token() - - -def ensure_has_notification_engine(): - if not os.path.isfile('/etc/monasca/notification.yaml'): - print('Must be run on a VM with Notification Engine installed', - file=sys.stderr) - return False - return True - - -def find_notifications(alarm_id, user): - args = ['sudo', 'cat', '/var/mail/' + user] - result = [] - env = os.environ.copy() - env['PYTHONIOENCODING'] = "utf-8" - try: - stdout = subprocess.check_output(args, env=env) - except subprocess.CalledProcessError as e: - print(e, file=sys.stderr) - sys.exit(1) - - previous = '' - for line in stdout.splitlines(): - # Get the state; the alarm_id always follows the state message - line = unicode(line, "utf-8") - if alarm_id in line: - """ In the notification message the state verb is framed by - 'transitioned to the ' and ' state' - """ - result.append(re.search('transitioned to the (.+?) state', - previous).group(1)) - previous = line - return result