More eefactoring for reuse. Added utils.py.

Added alarm_crud.py to test more alarm functionality.
This commit is contained in:
Craig Bryant 2014-06-01 20:00:45 -06:00
parent 0b46c17f65
commit f01c344d6c
6 changed files with 253 additions and 95 deletions

View File

@ -1,5 +1,9 @@
from __future__ import print_function from __future__ import print_function
import sys import sys
#
"""
Utility methods for CRUD of alarms
"""
def get_state(mon_client, alarm_id): def get_state(mon_client, alarm_id):

136
tests/alarm_crud.py Executable file
View File

@ -0,0 +1,136 @@
#!/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)
# 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
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
cli_wrapper.patch_alarm(alarm_id, '--expression', expression)
# 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],
[new_metric_name, new_dimension]]):
return 1
states.append('ALARM')
# Query History
# 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())

View File

@ -5,13 +5,12 @@
""" """
from __future__ import print_function from __future__ import print_function
import sys import sys
import platform
import os import os
import time import time
from monclient import client
import notification import notification
import monclient.exc as exc import monclient.exc as exc
import alarm import alarm
import utils
def cycle_states(mon_client, alarm_id, states): def cycle_states(mon_client, alarm_id, states):
@ -70,7 +69,7 @@ def check_notifications(alarm_id, email1, email2, email3, state1, state2,
return True return True
def print_actions(state, action_ids): def print_actions(mon_client, state, action_ids):
addresses = [] addresses = []
for action_id in action_ids: for action_id in action_ids:
action_notification = notification.get(mon_client, action_id) action_notification = notification.get(mon_client, action_id)
@ -80,32 +79,21 @@ def print_actions(state, action_ids):
def print_notification_setup(mon_client, alarm_id): def print_notification_setup(mon_client, alarm_id):
alarm_data = alarm.get(mon_client, alarm_id) alarm_data = alarm.get(mon_client, alarm_id)
print_actions('ALARM', alarm_data['alarm_actions']) print_actions(mon_client, 'ALARM', alarm_data['alarm_actions'])
print_actions('OK', alarm_data['ok_actions']) print_actions(mon_client, 'OK', alarm_data['ok_actions'])
print_actions('UNDETERMINED', alarm_data['undetermined_actions']) print_actions(mon_client, 'UNDETERMINED',
alarm_data['undetermined_actions'])
def main(): def main():
hostname = platform.node() if not utils.ensure_has_notification_engine():
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 return 1
# Delete notification for OK.Cycle OK, ALARM, UNDETERMINED # Delete notification for OK.Cycle OK, ALARM, UNDETERMINED
# Ensure proper notifications got written for ALARM, UNDETERMINED # Ensure proper notifications got written for ALARM, UNDETERMINED
states = ['OK', 'ALARM', 'UNDETERMINED'] states = ['OK', 'ALARM', 'UNDETERMINED']
api_version = '2_0' mon_client = utils.create_mon_client()
endpoint = 'http://' + api_host + ':8080/v2.0'
kwargs = {'token': '82510970543135'}
global mon_client
mon_client = client.Client(api_version, endpoint, **kwargs)
try: try:
# Create 3 notifications with different emails, root, kafka, mon-agent # Create 3 notifications with different emails, root, kafka, mon-agent

View File

@ -6,10 +6,9 @@
from __future__ import print_function from __future__ import print_function
import sys import sys
import time import time
from monclient import client
import notification import notification
import alarm import alarm
import os import utils
def main(): def main():
@ -17,23 +16,10 @@ def main():
print('usage: %s count [alarm-id]' % sys.argv[0], file=sys.stderr) print('usage: %s count [alarm-id]' % sys.argv[0], file=sys.stderr)
return 1 return 1
if not os.path.isfile('/etc/mon/notification.yaml'): if not utils.ensure_has_notification_engine():
print('Must be run on a VM with Notification Engine installed',
file=sys.stderr)
return 1 return 1
# Determine if we are running on mutiple VMs or just the one
if os.path.isfile('/etc/mon/mon-api-config.yml'):
api_host = 'localhost'
else:
api_host = '192.168.10.4'
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)
mon_client = utils.create_mon_client()
num_cycles = int(sys.argv[1]) num_cycles = int(sys.argv[1])
alarm_name = 'notification_cycleTest' alarm_name = 'notification_cycleTest'

View File

@ -19,6 +19,7 @@ import os
import subprocess import subprocess
import time import time
import cli_wrapper import cli_wrapper
import utils
from notification import find_notifications from notification import find_notifications
# export OS_AUTH_TOKEN=82510970543135 # export OS_AUTH_TOKEN=82510970543135
@ -26,45 +27,6 @@ from notification import find_notifications
# export MON_API_URL=http://192.168.10.4:8080/v2.0/ # export MON_API_URL=http://192.168.10.4:8080/v2.0/
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, 10):
result_json = cli_wrapper.run_mon_cli(['alarm-history', alarm_id])
if len(result_json) >= transitions:
break
time.sleep(4)
result = True
if not check_expected(transitions, len(result_json),
'number of history entries'):
return False
result_json.sort(key=lambda x: x['timestamp'])
for i in range(0, transitions):
old_state = states[i]
new_state = states[i+1]
alarm_json = result_json[i]
if not check_expected(old_state, alarm_json['old_state'], 'old_state'):
result = False
if not check_expected(new_state, alarm_json['new_state'], 'new_state'):
result = False
if not check_expected(alarm_id, alarm_json['alarm_id'], 'alarm_id'):
result = False
if result:
print('Alarm History is OK')
return result
def check_expected(expected, actual, what):
if (expected == actual):
return True
print("Incorrect value for alarm history %s expected '%s' but was '%s'" %
(what, str(expected), str(actual)), file=sys.stderr)
return False
def get_metrics(name, dimensions): def get_metrics(name, dimensions):
print('Getting metrics for %s ' % (name + str(dimensions))) print('Getting metrics for %s ' % (name + str(dimensions)))
dimensions_arg = '' dimensions_arg = ''
@ -135,20 +97,13 @@ def ensure_at_least(desired, actual):
def main(): def main():
# Determine if we are running on mutiple VMs or just the one if not utils.ensure_has_notification_engine():
if os.path.isfile('/etc/mon/mon-api-config.yml'): return 1
api_host = 'localhost'
metric_host = subprocess.check_output(['hostname', '-f']).strip()
mail_host = 'localhost'
else:
api_host = '192.168.10.4'
metric_host = 'thresh'
mail_host = 'kafka'
# These need to be set because we are invoking the CLI as a process mail_host = 'localhost'
os.environ['OS_AUTH_TOKEN'] = '82510970543135' metric_host = subprocess.check_output(['hostname', '-f']).strip()
os.environ['OS_NO_CLIENT_AUTH'] = '1'
os.environ['MON_API_URL'] = 'http://' + api_host + ':8080/v2.0/' utils.setup_cli()
notification_name = 'Jahmon Smoke Test' notification_name = 'Jahmon Smoke Test'
notification_email_addr = 'root@' + mail_host notification_email_addr = 'root@' + mail_host
@ -177,14 +132,11 @@ def main():
ok_notif_id=notification_id, ok_notif_id=notification_id,
alarm_notif_id=notification_id, alarm_notif_id=notification_id,
undetermined_notif_id=notification_id) undetermined_notif_id=notification_id)
state = cli_wrapper.get_alarm_state(alarm_id)
# Ensure it is created in the right state # Ensure it is created in the right state
initial_state = 'UNDETERMINED' initial_state = 'UNDETERMINED'
states = [] if not utils.check_alarm_state(alarm_id, initial_state):
if state != initial_state:
print('Wrong initial alarm state, expected %s but is %s' %
(initial_state, state))
return 1 return 1
states = []
states.append(initial_state) states.append(initial_state)
state = wait_for_alarm_state_change(alarm_id, initial_state) state = wait_for_alarm_state_change(alarm_id, initial_state)
@ -227,7 +179,7 @@ def main():
return 1 return 1
print('Received %d metrics in %d seconds' % print('Received %d metrics in %d seconds' %
((final_num_metrics - initial_num_metrics), change_time)) ((final_num_metrics - initial_num_metrics), change_time))
if not check_alarm_history(alarm_id, states): if not utils.check_alarm_history(alarm_id, states):
return 1 return 1
# Notifications are only sent out for the changes, so omit the first state # Notifications are only sent out for the changes, so omit the first state

92
tests/utils.py Normal file
View File

@ -0,0 +1,92 @@
from __future__ import print_function
import sys
import time
import os
import cli_wrapper
from monclient import client
"""
Utility methods for testing
"""
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, 10):
result_json = cli_wrapper.run_mon_cli(['alarm-history', alarm_id])
if len(result_json) >= transitions:
break
time.sleep(4)
result = True
if not check_expected(transitions, len(result_json),
'number of history entries'):
return False
result_json.sort(key=lambda x: x['timestamp'])
for i in range(0, transitions):
old_state = states[i]
new_state = states[i+1]
alarm_json = result_json[i]
if not check_expected(old_state, alarm_json['old_state'], 'old_state'):
result = False
if not check_expected(new_state, alarm_json['new_state'], 'new_state'):
result = False
if not check_expected(alarm_id, alarm_json['alarm_id'], 'alarm_id'):
result = False
if result:
print('Alarm History is OK')
return result
def check_expected(expected, actual, what):
if (expected == actual):
return True
print("Incorrect value for alarm history %s expected '%s' but was '%s'" %
(what, str(expected), str(actual)), 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 setup_cli():
api_host = get_api_host()
# These need to be set because we are invoking the CLI as a process
os.environ['OS_AUTH_TOKEN'] = '82510970543135'
os.environ['OS_NO_CLIENT_AUTH'] = '1'
os.environ['MON_API_URL'] = 'http://' + api_host + ':8080/v2.0/'
def create_mon_client():
api_host = get_api_host()
api_version = '2_0'
endpoint = 'http://' + api_host + ':8080/v2.0'
kwargs = {'token': '82510970543135'}
return client.Client(api_version, endpoint, **kwargs)
def ensure_has_notification_engine():
if not os.path.isfile('/etc/mon/notification.yaml'):
print('Must be run on a VM with Notification Engine installed',
file=sys.stderr)
return False
return True