mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-23 05:34:48 +02:00
Add verbosity levels to the vm-test-runner and add more debug output
This commit is contained in:
parent
f867029180
commit
de79c1232d
@ -233,10 +233,10 @@ The following macros are available in all executed commands:
|
|||||||
Name | Description
|
Name | Description
|
||||||
-----------------------|--------------
|
-----------------------|--------------
|
||||||
TIMET | Current UNIX timestamp.
|
TIMET | Current UNIX timestamp.
|
||||||
LONGDATETIME | Current date and time including timezone information. Example: `2014-01-0311:23:08+0000`
|
LONGDATETIME | Current date and time including timezone information. Example: `2014-01-03 11:23:08 +0000`
|
||||||
SHORTDATETIME | Current date and time. Example: `2014-01-0311:23:08`
|
SHORTDATETIME | Current date and time. Example: `2014-01-03 11:23:08`
|
||||||
DATE | Current date. Example: `2014-01-03`
|
DATE | Current date. Example: `2014-01-03`
|
||||||
TIME | Current time including timezone information. Example: `11:23:08+0000`
|
TIME | Current time including timezone information. Example: `11:23:08 +0000`
|
||||||
|
|
||||||
### <a id="runtime-macros-env-vars"></a> Runtime Macros as Environment Variables
|
### <a id="runtime-macros-env-vars"></a> Runtime Macros as Environment Variables
|
||||||
|
|
||||||
|
@ -31,16 +31,6 @@ output=%(output)s
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def success(msg):
|
|
||||||
print '[OK] {0}'.format(msg).encode('utf-8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def fail(msg):
|
|
||||||
print '[FAIL] {0}'.format(msg).encode('utf-8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
run_query = lambda q: utils.run_mysql_query(q, b'/usr/bin/mysql')
|
run_query = lambda q: utils.run_mysql_query(q, b'/usr/bin/mysql')
|
||||||
|
|
||||||
@ -53,14 +43,16 @@ def main():
|
|||||||
"where c.display_name = 'PassiveService1'"
|
"where c.display_name = 'PassiveService1'"
|
||||||
state_time = float(next(iter(run_query(query)), {}).get('last_check', '0'))
|
state_time = float(next(iter(run_query(query)), {}).get('last_check', '0'))
|
||||||
if state_time == 0:
|
if state_time == 0:
|
||||||
fail('"PassiveService1" seems not to have been checked yet')
|
utils.Logger.fail('"PassiveService1" seems not'
|
||||||
|
' to have been checked yet\n')
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if (state_time + CHECK_INTERVAL) - time.time() < 30:
|
if (state_time + CHECK_INTERVAL) - time.time() < 30:
|
||||||
time.sleep(45)
|
time.sleep(45)
|
||||||
|
|
||||||
# Now pass the checkresult in
|
# Now pass the checkresult in
|
||||||
with open(os.path.join(CHECKRESULT_LOCATION, 'cfoobar'), 'w') as f:
|
resultfile_path = os.path.join(CHECKRESULT_LOCATION, 'cfoobar')
|
||||||
|
with open(resultfile_path, 'w') as f:
|
||||||
f.write(CHECKRESULT_TEMPLATE % {
|
f.write(CHECKRESULT_TEMPLATE % {
|
||||||
'hostname': 'nsca-ng',
|
'hostname': 'nsca-ng',
|
||||||
'servicename': 'PassiveService1',
|
'servicename': 'PassiveService1',
|
||||||
@ -72,10 +64,15 @@ def main():
|
|||||||
'output': 'Passing in CheckResult header files works!'
|
'output': 'Passing in CheckResult header files works!'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
utils.Logger.debug('Written file: {0}\n'.format(resultfile_path))
|
||||||
|
|
||||||
# And notfiy Icinga that the file has been completely written...
|
# And notfiy Icinga that the file has been completely written...
|
||||||
with open(os.path.join(CHECKRESULT_LOCATION, 'cfoobar.ok'), 'w') as f:
|
resultfileok_path = os.path.join(CHECKRESULT_LOCATION, 'cfoobar.ok')
|
||||||
|
with open(resultfileok_path, 'w') as f:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
utils.Logger.debug('Written file: {0}\n'.format(resultfileok_path))
|
||||||
|
|
||||||
# Lastly check whether the service changed its state
|
# Lastly check whether the service changed its state
|
||||||
time.sleep(CHECKRESULT_READ_INTERVAL * 2)
|
time.sleep(CHECKRESULT_READ_INTERVAL * 2)
|
||||||
|
|
||||||
@ -86,10 +83,11 @@ def main():
|
|||||||
"where c.display_name = 'PassiveService1'"
|
"where c.display_name = 'PassiveService1'"
|
||||||
output = next(iter(run_query(query)), {}).get('output', '')
|
output = next(iter(run_query(query)), {}).get('output', '')
|
||||||
if output != 'Passing in CheckResult header files works!':
|
if output != 'Passing in CheckResult header files works!':
|
||||||
fail('Checkresult header files seem not to be processed properly')
|
utils.Logger.fail('Checkresult header files seem '
|
||||||
|
'not to be processed properly\n')
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
success('Checkresult header files are processed properly')
|
utils.Logger.ok('Checkresult header files are processed properly\n')
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,24 +108,13 @@ def convert_output(value):
|
|||||||
return STATE_MAP.get(value, value)
|
return STATE_MAP.get(value, value)
|
||||||
|
|
||||||
|
|
||||||
def success(msg):
|
def validate_time_format(inputstr, formatstr):
|
||||||
print '[OK] {0}'.format(msg).encode('utf-8')
|
try:
|
||||||
sys.stdout.flush()
|
time.strptime(inputstr, formatstr)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
def fail(msg):
|
else:
|
||||||
print '[FAIL] {0}'.format(msg).encode('utf-8')
|
return True
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def info(msg):
|
|
||||||
print '[INFO] {0}'.format(msg).encode('utf-8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def error(msg):
|
|
||||||
print '[ERROR] {0}'.format(msg).encode('utf-8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -133,84 +122,147 @@ def main():
|
|||||||
host_info = get_one('GET hosts\nFilter: name = localhost'
|
host_info = get_one('GET hosts\nFilter: name = localhost'
|
||||||
'\nColumns: event_handler')
|
'\nColumns: event_handler')
|
||||||
if host_info.get('event_handler') != 'test_event':
|
if host_info.get('event_handler') != 'test_event':
|
||||||
fail('Could not assign eventcommand "test_event" to host "localhost"')
|
utils.Logger.fail('Could not assign eventcommand "test_event"'
|
||||||
|
' to host "localhost"\n')
|
||||||
return 1
|
return 1
|
||||||
success('Successfully assigned an eventcommand to host "localhost"')
|
utils.Logger.ok('Successfully assigned an eventcommand'
|
||||||
|
' to host "localhost"\n')
|
||||||
|
|
||||||
send_command('PROCESS_HOST_CHECK_RESULT;localhost;1;A negative result to'
|
send_command('PROCESS_HOST_CHECK_RESULT;localhost;1;A negative result to'
|
||||||
' trigger an eventhandler|some interesting perfdata!')
|
' trigger an eventhandler|some interesting perfdata!')
|
||||||
event_output = get_event_output()
|
event_output = get_event_output()
|
||||||
if not event_output:
|
if not event_output:
|
||||||
send_command('CHANGE_HOST_EVENT_HANDLER;localhost;')
|
send_command('CHANGE_HOST_EVENT_HANDLER;localhost;')
|
||||||
fail('Could not trigger the eventcommand')
|
utils.Logger.fail('Could not trigger the eventcommand\n')
|
||||||
return 1
|
return 1
|
||||||
success('Successfully triggered the eventcommand')
|
utils.Logger.ok('Successfully triggered the eventcommand\n')
|
||||||
failure = False
|
failure = False
|
||||||
|
|
||||||
info('Checking host macros...')
|
utils.Logger.info('Checking host macros...\n')
|
||||||
host_info = get_one('GET hosts\nFilter: name = localhost\nColumns: {0}'
|
host_info = get_one('GET hosts\nFilter: name = localhost\nColumns: {0}'
|
||||||
''.format(' '.join(c for c in LS_HOST_COLUMNS if c)))
|
''.format(' '.join(c for c in LS_HOST_COLUMNS if c)))
|
||||||
if event_output[0] != host_info['name']*2:
|
if event_output[0] != host_info['name']*2:
|
||||||
failure = True
|
failure = True
|
||||||
fail('Escaping environment variables seems not to properly working')
|
utils.Logger.fail('Escaping environment variables '
|
||||||
fail(' Expected: {0!r} Got: {1!r}'.format(host_info['name']*2,
|
'seems not to properly working\n')
|
||||||
event_output[0]))
|
utils.Logger.fail(' Expected: {0!r} Got: {1!r}\n'
|
||||||
|
''.format(host_info['name']*2, event_output[0]))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Escaped environment variables'
|
||||||
|
' are properly processed\n')
|
||||||
for i, column in enumerate(LS_HOST_COLUMNS[1:], 1):
|
for i, column in enumerate(LS_HOST_COLUMNS[1:], 1):
|
||||||
if column is not None:
|
if column is not None:
|
||||||
output_value = convert_output(event_output[i])
|
macro_name, _, macro_value = event_output[i].partition('=')
|
||||||
|
output_value = convert_output(macro_value)
|
||||||
if output_value != host_info[column]:
|
if output_value != host_info[column]:
|
||||||
failure = True
|
failure = True
|
||||||
fail('{0!r} is unequal to {1!r} ({2})'.format(output_value,
|
utils.Logger.fail('Macro "{0}" returns an incorrect value. '
|
||||||
host_info[column],
|
'Expected "{2}" but got "{1}"\n'
|
||||||
column))
|
''.format(macro_name, output_value,
|
||||||
|
host_info[column]))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Macro "{0}" returns the correct value\n'
|
||||||
|
''.format(macro_name))
|
||||||
|
|
||||||
info('Checking service macros...')
|
utils.Logger.info('Checking service macros...\n')
|
||||||
svc_info = get_one('GET services\nFilter: description = ping4\nColumns: {0}'
|
svc_info = get_one('GET services\nFilter: description = ping4\nColumns: {0}'
|
||||||
''.format(' '.join(c for c in LS_SVC_COLUMNS if c)))
|
''.format(' '.join(c for c in LS_SVC_COLUMNS if c)))
|
||||||
for i, column in enumerate(LS_SVC_COLUMNS, len(LS_HOST_COLUMNS)):
|
for i, column in enumerate(LS_SVC_COLUMNS, len(LS_HOST_COLUMNS)):
|
||||||
if column is not None:
|
if column is not None:
|
||||||
output_value = convert_output(event_output[i])
|
macro_name, _, macro_value = event_output[i].partition('=')
|
||||||
|
output_value = convert_output(macro_value)
|
||||||
if output_value != svc_info[column]:
|
if output_value != svc_info[column]:
|
||||||
failure = True
|
failure = True
|
||||||
fail('{0!r} is unequal to {1!r} ({2})'.format(output_value,
|
utils.Logger.fail('Macro "{0}" returns an incorrect value. '
|
||||||
svc_info[column],
|
'Expected "{2}" but got "{1}"\n'
|
||||||
column))
|
''.format(macro_name, output_value,
|
||||||
|
svc_info[column]))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Macro "{0}" returns the correct value\n'
|
||||||
|
''.format(macro_name))
|
||||||
|
|
||||||
info('Checking global macros...')
|
utils.Logger.info('Checking global macros...\n')
|
||||||
|
timet = convert_output(event_output[-6].partition('=')[2])
|
||||||
info('Checking command macros...')
|
if not isinstance(timet, int):
|
||||||
if convert_output(event_output[-1]) != 1337:
|
|
||||||
failure = True
|
failure = True
|
||||||
fail('The command macro "custom_macro" is not being substituted')
|
utils.Logger.fail('Macro "TIMET" does not return a timestamp. '
|
||||||
|
'Expected int but got: {0!r}\n'.format(timet))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Macro "TIMET" returns the correct value\n')
|
||||||
|
longdatetime = event_output[-5].partition('=')[2]
|
||||||
|
longdatetime_format = '%Y-%m-%d %H:%M:%S +0000'
|
||||||
|
if not validate_time_format(longdatetime, longdatetime_format):
|
||||||
|
failure = True
|
||||||
|
utils.Logger.fail('Macro "LONGDATETIME" returns an incorrect value.'
|
||||||
|
' Expected value of format "{0}" but got "{1}"\n'
|
||||||
|
''.format(longdatetime_format, longdatetime))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Macro "LONGDATETIME" returns the correct value\n')
|
||||||
|
shortdatetime = event_output[-4].partition('=')[2]
|
||||||
|
shortdatetime_format = '%Y-%m-%d %H:%M:%S'
|
||||||
|
if not validate_time_format(shortdatetime, shortdatetime_format):
|
||||||
|
failure = True
|
||||||
|
utils.Logger.fail('Macro "SHORTDATETIME" returns an incorrect value.'
|
||||||
|
' Expected value of format "{0}" but got "{1}"\n'
|
||||||
|
''.format(shortdatetime_format, shortdatetime))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Macro "SHORTDATETIME" returns the correct value\n')
|
||||||
|
m_date = event_output[-3].partition('=')[2]
|
||||||
|
m_date_format = '%Y-%m-%d'
|
||||||
|
if not validate_time_format(m_date, m_date_format):
|
||||||
|
failure = True
|
||||||
|
utils.Logger.fail('Macro "DATE" returns an incorrect value. '
|
||||||
|
'Expected value of format "{0}" but got "{1}"\n'
|
||||||
|
''.format(m_date_format, m_date))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Macro "DATE" returns the correct value\n')
|
||||||
|
m_time = event_output[-2].partition('=')[2]
|
||||||
|
m_time_format = '%H:%M:%S +0000'
|
||||||
|
if not validate_time_format(m_time, m_time_format):
|
||||||
|
failure = True
|
||||||
|
utils.Logger.fail('Macro "TIME" returns an incorrect value. '
|
||||||
|
'Expected value of format "{0}" but got "{1}"\n'
|
||||||
|
''.format(m_time_format, m_time))
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('Macro "TIME" returns the correct value\n')
|
||||||
|
|
||||||
|
utils.Logger.info('Checking command macros...\n')
|
||||||
|
if convert_output(event_output[-1].partition('=')[2]) != 1337:
|
||||||
|
failure = True
|
||||||
|
utils.Logger.fail('The command macro "custom_macro"'
|
||||||
|
' is not being substituted\n')
|
||||||
|
else:
|
||||||
|
utils.Logger.ok('The command macro "custom_macro"'
|
||||||
|
' is correctly substituted\n')
|
||||||
|
|
||||||
send_command('DISABLE_HOST_EVENT_HANDLER;localhost')
|
send_command('DISABLE_HOST_EVENT_HANDLER;localhost')
|
||||||
send_command('PROCESS_HOST_CHECK_RESULT;localhost;0;A positive result that'
|
send_command('PROCESS_HOST_CHECK_RESULT;localhost;0;A positive result that'
|
||||||
' should not trigger an eventhandler')
|
' should not trigger an eventhandler')
|
||||||
if get_event_output():
|
if get_event_output():
|
||||||
failure = True
|
failure = True
|
||||||
fail('Could not disable the eventcommand')
|
utils.Logger.fail('Could not disable the eventcommand\n')
|
||||||
else:
|
else:
|
||||||
success('Successfully disabled the eventcommand')
|
utils.Logger.ok('Successfully disabled the eventcommand\n')
|
||||||
|
|
||||||
send_command('ENABLE_HOST_EVENT_HANDLER;localhost')
|
send_command('ENABLE_HOST_EVENT_HANDLER;localhost')
|
||||||
host_info = get_one('GET hosts\nFilter: name = localhost'
|
host_info = get_one('GET hosts\nFilter: name = localhost'
|
||||||
'\nColumns: event_handler_enabled')
|
'\nColumns: event_handler_enabled')
|
||||||
if host_info['event_handler_enabled'] != 1:
|
if host_info['event_handler_enabled'] != 1:
|
||||||
failure = True
|
failure = True
|
||||||
fail('Could not re-enable the eventcommand')
|
utils.Logger.fail('Could not re-enable the eventcommand\n')
|
||||||
else:
|
else:
|
||||||
success('Successfully re-enabled the eventcommand')
|
utils.Logger.ok('Successfully re-enabled the eventcommand\n')
|
||||||
|
|
||||||
send_command('CHANGE_HOST_EVENT_HANDLER;localhost;')
|
send_command('CHANGE_HOST_EVENT_HANDLER;localhost;')
|
||||||
host_info = get_one('GET hosts\nFilter: name = localhost'
|
host_info = get_one('GET hosts\nFilter: name = localhost'
|
||||||
'\nColumns: event_handler')
|
'\nColumns: event_handler')
|
||||||
if host_info['event_handler']:
|
if host_info['event_handler']:
|
||||||
failure = True
|
failure = True
|
||||||
fail('Could not remove eventcommand "test_event"'
|
utils.Logger.fail('Could not remove eventcommand "test_event"'
|
||||||
' assigned to host "localhost"')
|
' assigned to host "localhost"\n')
|
||||||
else:
|
else:
|
||||||
success('Successfully removed the eventcommand'
|
utils.Logger.ok('Successfully removed the eventcommand'
|
||||||
' assigned to host "localhost"')
|
' assigned to host "localhost"\n')
|
||||||
|
|
||||||
return 1 if failure else 0
|
return 1 if failure else 0
|
||||||
|
|
||||||
@ -220,6 +272,6 @@ if __name__ == '__main__':
|
|||||||
with utils.LiveStatusSocket(LIVESTATUS_PATH) as LIVESTATUS:
|
with utils.LiveStatusSocket(LIVESTATUS_PATH) as LIVESTATUS:
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
except (OSError, IOError, socket.error), e:
|
except (OSError, IOError, socket.error), e:
|
||||||
error('Could not connect to Livestatus socket: {0} ({1})'
|
utils.Logger.error('Could not connect to Livestatus socket: {0} ({1})'
|
||||||
''.format(LIVESTATUS_PATH, unicode(e)))
|
'\n'.format(LIVESTATUS_PATH, unicode(e)))
|
||||||
|
|
||||||
|
@ -62,20 +62,17 @@ def restart_icinga():
|
|||||||
|
|
||||||
|
|
||||||
def success(msg):
|
def success(msg):
|
||||||
print '[OK] {0}'.format(msg).encode('utf-8')
|
utils.Logger.ok(msg + '\n')
|
||||||
sys.stdout.flush()
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def fail(msg):
|
def fail(msg):
|
||||||
print '[FAIL] {0}'.format(msg).encode('utf-8')
|
utils.Logger.fail(msg + '\n')
|
||||||
sys.stdout.flush()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def error(msg):
|
def error(msg):
|
||||||
print '[ERROR] {0}'.format(msg).encode('utf-8')
|
utils.Logger.error(msg + '\n')
|
||||||
sys.stdout.flush()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,55 +1,55 @@
|
|||||||
object EventCommand "test_event" inherits "plugin-event-command" {
|
object EventCommand "test_event" inherits "plugin-event-command" {
|
||||||
command = {{{echo "\
|
command = {{{echo "\
|
||||||
$$HOSTNAME$HOSTNAME$\
|
$$HOSTNAME$HOSTNAME$\
|
||||||
|$HOSTNAME$\
|
|HOSTNAME=$HOSTNAME$\
|
||||||
|$HOSTDISPLAYNAME$\
|
|HOSTDISPLAYNAME=$HOSTDISPLAYNAME$\
|
||||||
|$HOSTALIAS$\
|
|HOSTALIAS=$HOSTALIAS$\
|
||||||
|$HOSTSTATE$\
|
|HOSTSTATE=$HOSTSTATE$\
|
||||||
|$HOSTSTATEID$\
|
|HOSTSTATEID=$HOSTSTATEID$\
|
||||||
|$HOSTSTATETYPE$\
|
|HOSTSTATETYPE=$HOSTSTATETYPE$\
|
||||||
|$HOSTATTEMPT$\
|
|HOSTATTEMPT=$HOSTATTEMPT$\
|
||||||
|$MAXHOSTATTEMPT$\
|
|MAXHOSTATTEMPT=$MAXHOSTATTEMPT$\
|
||||||
|$LASTHOSTSTATE$\
|
|LASTHOSTSTATE=$LASTHOSTSTATE$\
|
||||||
|$LASTHOSTSTATEID$\
|
|LASTEHOSTSTATEID=$LASTHOSTSTATEID$\
|
||||||
|$LASTHOSTSTATETYPE$\
|
|LASTHOSTSTATETYPE=$LASTHOSTSTATETYPE$\
|
||||||
|$LASTHOSTSTATECHANGE$\
|
|LASTHOSTSTATECHANGE=$LASTHOSTSTATECHANGE$\
|
||||||
|$HOSTDURATIONSEC$\
|
|HOSTDURATIONSEC=$HOSTDURATIONSEC$\
|
||||||
|$HOSTLATENCY$\
|
|HOSTLATENCY=$HOSTLATENCY$\
|
||||||
|$HOSTEXECUTIONTIME$\
|
|HOSTEXECUTIONTIME=$HOSTEXECUTIONTIME$\
|
||||||
|$HOSTOUTPUT$\
|
|HOSTOUTPUT=$HOSTOUTPUT$\
|
||||||
|$HOSTPERFDATA$\
|
|HOSTPERFDATA=$HOSTPERFDATA$\
|
||||||
|$LASTHOSTCHECK$\
|
|LASTHOSTCHECK=$LASTHOSTCHECK$\
|
||||||
|$HOSTADDRESS$\
|
|HOSTADDRESS=$HOSTADDRESS$\
|
||||||
|$HOSTADDRESS6$\
|
|HOSTADDRESS6=$HOSTADDRESS6$\
|
||||||
|$SERVICEDESC$\
|
|SERVICEDESC=$SERVICEDESC$\
|
||||||
|$SERVICEDISPLAYNAME$\
|
|SERVICEDISPLAYNAME=$SERVICEDISPLAYNAME$\
|
||||||
|$SERVICECHECKCOMMAND$\
|
|SERVICECHECKCOMMAND=$SERVICECHECKCOMMAND$\
|
||||||
|$SERVICESTATE$\
|
|SERVICESTATE=$SERVICESTATE$\
|
||||||
|$SERVICESTATEID$\
|
|SERVICESTATEID=$SERVICESTATEID$\
|
||||||
|$SERVICESTATETYPE$\
|
|SERVICESTATETYPE=$SERVICESTATETYPE$\
|
||||||
|$SERVICEATTEMPT$\
|
|SERVICEATTEMPT=$SERVICEATTEMPT$\
|
||||||
|$MAXSERVICEATTEMPT$\
|
|MAXSERVICEATTEMPT=$MAXSERVICEATTEMPT$\
|
||||||
|$LASTSERVICESTATE$\
|
|LASTSERVICESTATE=$LASTSERVICESTATE$\
|
||||||
|$LASTSERVICESTATEID$\
|
|LASTSERVICESTATEID=$LASTSERVICESTATEID$\
|
||||||
|$LASTSERVICESTATETYPE$\
|
|LASTSERVICESTATETYPE=$LASTSERVICESTATETYPE$\
|
||||||
|$LASTSERVICESTATECHANGE$\
|
|LASTSERVICESTATECHANGE=$LASTSERVICESTATECHANGE$\
|
||||||
|$SERVICEDURATIONSEC$\
|
|SERVICEDURATIONSEC=$SERVICEDURATIONSEC$\
|
||||||
|$SERVICELATENCY$\
|
|SERVICELATENCY=$SERVICELATENCY$\
|
||||||
|$SERVICEEXECUTIONTIME$\
|
|SERVICEEXECUTIONTIME=$SERVICEEXECUTIONTIME$\
|
||||||
|$SERVICEOUTPUT$\
|
|SERVICEOUTPUT=$SERVICEOUTPUT$\
|
||||||
|$SERVICEPERFDATA$\
|
|SERVICEPERFDATA=$SERVICEPERFDATA$\
|
||||||
|$LASTSERVICECHECK$\
|
|LASTSERVICECHECK=$LASTSERVICECHECK$\
|
||||||
|$TOTALHOSTSERVICES$\
|
|TOTALHOSTSERVICES=$TOTALHOSTSERVICES$\
|
||||||
|$TOTALHOSTSERVICESOK$\
|
|TOTALHOSTSERVICESOK=$TOTALHOSTSERVICESOK$\
|
||||||
|$TOTALHOSTSERVICESWARNING$\
|
|TOTALHOSTSERVICESWARNING=$TOTALHOSTSERVICESWARNING$\
|
||||||
|$TOTALHOSTSERVICESUNKNOWN$\
|
|TOTALHOSTSERVICESUNKNOWN=$TOTALHOSTSERVICESUNKNOWN$\
|
||||||
|$TOTALHOSTSERVICESCRITICAL$\
|
|TOTALHOSTSERVICESCRITICAL=$TOTALHOSTSERVICESCRITICAL$\
|
||||||
|$TIMET$\
|
|TIMET=$TIMET$\
|
||||||
|$LONGDATETIME$\
|
|LONGDATETIME=$LONGDATETIME$\
|
||||||
|$SHORTDATETIME$\
|
|SHORTDATETIME=$SHORTDATETIME$\
|
||||||
|$DATE$\
|
|DATE=$DATE$\
|
||||||
|$TIME$\
|
|TIME=$TIME$\
|
||||||
|$custom_macro$\
|
|custom_macro=$custom_macro$\
|
||||||
" > /tmp/test_event.out}}},
|
" > /tmp/test_event.out}}},
|
||||||
|
|
||||||
export_macros = ["HOSTNAME"],
|
export_macros = ["HOSTNAME"],
|
||||||
|
@ -3,7 +3,9 @@ from __future__ import unicode_literals
|
|||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
CHECK_INTERVAL = 10 # minutes; The actual interval are 5 minutes but as other
|
import utils
|
||||||
|
|
||||||
|
CHECK_INTERVAL = 10 # minutes; The actual interval is 5 minutes but as other
|
||||||
# tests might restart Icinga we need to take any
|
# tests might restart Icinga we need to take any
|
||||||
# rescheduling into account
|
# rescheduling into account
|
||||||
|
|
||||||
@ -79,36 +81,20 @@ EXAMPLE_CONFIG = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def success(msg):
|
|
||||||
print '[OK] {0}'.format(msg).encode('utf-8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def fail(msg):
|
|
||||||
print '[FAIL] {0}'.format(msg).encode('utf-8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def info(msg):
|
|
||||||
print '[INFO] {0}'.format(msg).encode('utf-8')
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def validate_tables(tables):
|
def validate_tables(tables):
|
||||||
"""
|
"""
|
||||||
Return whether all tables of the IDO database scheme exist in
|
Return whether all tables of the IDO database scheme exist in
|
||||||
the given table listing
|
the given table listing
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info('Checking database scheme... (tables)')
|
utils.Logger.info('Checking database scheme... (tables)\n')
|
||||||
failures = False
|
failures = False
|
||||||
for table in (TABLE_PREFIX + n for n in TABLES):
|
for table in (TABLE_PREFIX + n for n in TABLES):
|
||||||
if table in tables:
|
if table in tables:
|
||||||
success('Found table "{0}" in database'.format(table))
|
utils.Logger.ok('Found table "{0}" in database\n'.format(table))
|
||||||
else:
|
else:
|
||||||
fail('Could not find table "{0}" in database'.format(table))
|
utils.Logger.fail('Could not find table "{0}" in database\n'
|
||||||
|
''.format(table))
|
||||||
failures = True
|
failures = True
|
||||||
|
|
||||||
return not failures
|
return not failures
|
||||||
@ -119,14 +105,14 @@ def verify_host_config(config_data):
|
|||||||
Return whether the example hosts exist in the given "hosts" table
|
Return whether the example hosts exist in the given "hosts" table
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info('Checking example host configuration...')
|
utils.Logger.info('Checking example host configuration...\n')
|
||||||
failures = False
|
failures = False
|
||||||
for hostname in EXAMPLE_CONFIG:
|
for hostname in EXAMPLE_CONFIG:
|
||||||
if not any(1 for e in config_data if e['alias'] == hostname):
|
if not any(1 for e in config_data if e['alias'] == hostname):
|
||||||
fail('Could not find host "{0}"'.format(hostname))
|
utils.Logger.fail('Could not find host "{0}"\n'.format(hostname))
|
||||||
failures = True
|
failures = True
|
||||||
else:
|
else:
|
||||||
success('Found host "{0}"'.format(hostname))
|
utils.Logger.ok('Found host "{0}"\n'.format(hostname))
|
||||||
|
|
||||||
return not failures
|
return not failures
|
||||||
|
|
||||||
@ -136,19 +122,19 @@ def verify_service_config(config_data):
|
|||||||
Return whether the example services exist in the given "services" table
|
Return whether the example services exist in the given "services" table
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info('Checking example service configuration...')
|
utils.Logger.info('Checking example service configuration...\n')
|
||||||
failures = False
|
failures = False
|
||||||
for hostname, servicename in ((h, s) for h, ss in EXAMPLE_CONFIG.iteritems()
|
for hostname, servicename in ((h, s) for h, ss in EXAMPLE_CONFIG.iteritems()
|
||||||
for s in ss):
|
for s in ss):
|
||||||
if not any(1 for c in config_data
|
if not any(1 for c in config_data
|
||||||
if c['alias'] == hostname and
|
if c['alias'] == hostname and
|
||||||
c['display_name'] == servicename):
|
c['display_name'] == servicename):
|
||||||
fail('Could not find service "{0}" on host "{1}"'
|
utils.Logger.fail('Could not find service "{0}" on host "{1}"\n'
|
||||||
''.format(servicename, hostname))
|
''.format(servicename, hostname))
|
||||||
failures = True
|
failures = True
|
||||||
else:
|
else:
|
||||||
success('Found service "{0}" on host "{1}"'
|
utils.Logger.ok('Found service "{0}" on host "{1}"\n'
|
||||||
''.format(servicename, hostname))
|
''.format(servicename, hostname))
|
||||||
|
|
||||||
return not failures
|
return not failures
|
||||||
|
|
||||||
@ -158,28 +144,33 @@ def check_last_host_status_update(check_info):
|
|||||||
Return whether the example hosts are checked as scheduled
|
Return whether the example hosts are checked as scheduled
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info('Checking last host status updates...')
|
utils.Logger.info('Checking last host status updates...\n')
|
||||||
failures = False
|
failures = False
|
||||||
for host_info in check_info:
|
for host_info in check_info:
|
||||||
if host_info['alias'] == 'localhost':
|
if host_info['alias'] == 'localhost':
|
||||||
last_check = datetime.fromtimestamp(float(host_info['last_check']))
|
last_check = datetime.fromtimestamp(float(host_info['last_check']))
|
||||||
if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL,
|
if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL,
|
||||||
seconds=10):
|
seconds=10):
|
||||||
fail('The last status update of host "{0}" was more than {1} '
|
utils.Logger.fail('The last status update of host "{0}" was'
|
||||||
'minutes ago'.format(host_info['alias'], CHECK_INTERVAL))
|
' more than {1} minutes ago\n'
|
||||||
|
''.format(host_info['alias'], CHECK_INTERVAL))
|
||||||
failures = True
|
failures = True
|
||||||
else:
|
else:
|
||||||
success('Host "{0}" is being updated'.format(host_info['alias']))
|
utils.Logger.ok('Host "{0}" is being updated\n'
|
||||||
|
''.format(host_info['alias']))
|
||||||
elif host_info['alias'] == 'nsca-ng':
|
elif host_info['alias'] == 'nsca-ng':
|
||||||
if float(host_info['last_check']) > 0:
|
if float(host_info['last_check']) > 0:
|
||||||
fail('The host "{0}" was checked even though it has'
|
utils.Logger.fail('The host "{0}" was checked even'
|
||||||
' no check service'.format(host_info['alias']))
|
' though it has no check service'
|
||||||
|
''.format(host_info['alias']))
|
||||||
failures = True
|
failures = True
|
||||||
else:
|
else:
|
||||||
success('Host "{0}" is not being checked because there '
|
utils.Logger.ok('Host "{0}" is not being checked because '
|
||||||
'is no check service'.format(host_info['alias']))
|
'there is no check service\n'
|
||||||
|
''.format(host_info['alias']))
|
||||||
else:
|
else:
|
||||||
info('Skipping host "{0}"'.format(host_info['alias']))
|
utils.Logger.info('Skipping host "{0}"\n'
|
||||||
|
''.format(host_info['alias']))
|
||||||
|
|
||||||
return not failures
|
return not failures
|
||||||
|
|
||||||
@ -189,24 +180,27 @@ def check_last_service_status_update(check_info):
|
|||||||
Return whether the example services are checked as scheduled
|
Return whether the example services are checked as scheduled
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info('Checking last service status updates...')
|
utils.Logger.info('Checking last service status updates...\n')
|
||||||
failures = False
|
failures = False
|
||||||
for svc_info in check_info:
|
for svc_info in check_info:
|
||||||
if svc_info['display_name'] in EXAMPLE_CONFIG.get(svc_info['alias'], []):
|
if svc_info['display_name'] in EXAMPLE_CONFIG.get(svc_info['alias'], []):
|
||||||
last_check = datetime.fromtimestamp(float(svc_info['last_check']))
|
last_check = datetime.fromtimestamp(float(svc_info['last_check']))
|
||||||
if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL,
|
if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL,
|
||||||
seconds=10):
|
seconds=10):
|
||||||
fail('The last status update of service "{0}" on'
|
utils.Logger.fail('The last status update of service "{0}" on '
|
||||||
' host "{1}" was more than {2} minutes ago'
|
'host "{1}" was more than {2} minutes ago\n'
|
||||||
''.format(svc_info['display_name'], svc_info['alias'],
|
''.format(svc_info['display_name'],
|
||||||
CHECK_INTERVAL))
|
svc_info['alias'],
|
||||||
|
CHECK_INTERVAL))
|
||||||
failures = True
|
failures = True
|
||||||
else:
|
else:
|
||||||
success('Service "{0}" on host "{1}" is being updated'
|
utils.Logger.ok('Service "{0}" on host "{1}" is being updated\n'
|
||||||
''.format(svc_info['display_name'], svc_info['alias']))
|
''.format(svc_info['display_name'],
|
||||||
|
svc_info['alias']))
|
||||||
else:
|
else:
|
||||||
info('Skipping service "{0}" on host "{1}"'
|
utils.Logger.info('Skipping service "{0}" on host "{1}"\n'
|
||||||
''.format(svc_info['display_name'], svc_info['alias']))
|
''.format(svc_info['display_name'],
|
||||||
|
svc_info['alias']))
|
||||||
|
|
||||||
return not failures
|
return not failures
|
||||||
|
|
||||||
@ -217,15 +211,19 @@ def check_logentries(logentry_info):
|
|||||||
and refers to its very last hard status change
|
and refers to its very last hard status change
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info('Checking status log for host "localhost"...')
|
utils.Logger.info('Checking status log for host "localhost"...\n')
|
||||||
if logentry_info and logentry_info[0]['alias'] == 'localhost':
|
if logentry_info and logentry_info[0]['alias'] == 'localhost':
|
||||||
entry_time = datetime.fromtimestamp(float(logentry_info[0]['entry_time']))
|
entry_time = datetime.fromtimestamp(float(logentry_info[0]['entry_time']))
|
||||||
state_time = datetime.fromtimestamp(float(logentry_info[0]['state_time']))
|
state_time = datetime.fromtimestamp(float(logentry_info[0]['state_time']))
|
||||||
if entry_time - state_time > timedelta(seconds=10):
|
if entry_time - state_time > timedelta(seconds=10):
|
||||||
return fail('The last hard state of host "localhost"'
|
utils.Logger.fail('The last hard state of host "localhost"'
|
||||||
' seems not to have been logged')
|
' seems not to have been logged\n')
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
return fail('No logs found in the IDO for host "localhost"')
|
utils.Logger.fail('No logs found in the IDO for host "localhost"\n')
|
||||||
|
return False
|
||||||
|
|
||||||
return success('The last hard state of host "localhost" was properly logged')
|
utils.Logger.ok('The last hard state of host "localhost"'
|
||||||
|
' was properly logged\n')
|
||||||
|
return True
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
@ -52,7 +53,11 @@ def _cast_status_value(value):
|
|||||||
def run_mysql_query(query, path):
|
def run_mysql_query(query, path):
|
||||||
p = subprocess.Popen([path] + MYSQL_PARAMS + [query.encode('utf-8')],
|
p = subprocess.Popen([path] + MYSQL_PARAMS + [query.encode('utf-8')],
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
return _parse_mysql_result([l.decode('utf-8') for l in p.stdout.readlines()])
|
Logger.debug('Sent MYSQL query: {0!r}\n'.format(query))
|
||||||
|
resultset = [l.decode('utf-8') for l in p.stdout.readlines()]
|
||||||
|
Logger.debug('Received MYSQL resultset: {0!r}\n'
|
||||||
|
''.format(''.join(resultset)), True)
|
||||||
|
return _parse_mysql_result(resultset)
|
||||||
|
|
||||||
|
|
||||||
def _parse_mysql_result(resultset):
|
def _parse_mysql_result(resultset):
|
||||||
@ -70,7 +75,11 @@ def _parse_mysql_result(resultset):
|
|||||||
def run_pgsql_query(query, path):
|
def run_pgsql_query(query, path):
|
||||||
p = subprocess.Popen([path] + PGSQL_PARAMS + [query.encode('utf-8')],
|
p = subprocess.Popen([path] + PGSQL_PARAMS + [query.encode('utf-8')],
|
||||||
stdout=subprocess.PIPE, env=PGSQL_ENVIRONMENT)
|
stdout=subprocess.PIPE, env=PGSQL_ENVIRONMENT)
|
||||||
return _parse_pgsql_result([l.decode('utf-8') for l in p.stdout.readlines()])
|
Logger.debug('Sent PostgreSQL query: {0!r}\n'.format(query))
|
||||||
|
resultset = [l.decode('utf-8') for l in p.stdout.readlines()]
|
||||||
|
Logger.debug('Received PostgreSQL resultset: {0!r}\n'
|
||||||
|
''.format(''.join(resultset)), True)
|
||||||
|
return _parse_pgsql_result(resultset)
|
||||||
|
|
||||||
|
|
||||||
def _parse_pgsql_result(resultset):
|
def _parse_pgsql_result(resultset):
|
||||||
@ -109,15 +118,20 @@ class LiveStatusSocket(object):
|
|||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
Logger.debug('Opened UNIX stream socket\n', True)
|
||||||
self.sock.connect(self.path)
|
self.sock.connect(self.path)
|
||||||
|
Logger.debug('Connected to Livestatus socket: {0}\n'.format(self.path),
|
||||||
|
True)
|
||||||
self._connected = True
|
self._connected = True
|
||||||
|
|
||||||
def reconnect(self, timeout=30):
|
def reconnect(self, timeout=30):
|
||||||
|
Logger.debug('Reconnecting to Livestatus socket\n', True)
|
||||||
start = time.time()
|
start = time.time()
|
||||||
while not self._connected and time.time() - start < timeout:
|
while not self._connected and time.time() - start < timeout:
|
||||||
try:
|
try:
|
||||||
self.connect()
|
self.connect()
|
||||||
except socket.error:
|
except socket.error, error:
|
||||||
|
Logger.debug('Could not connect: {0}\n'.format(error), True)
|
||||||
# Icinga2 does some "magic" with the socket during startup
|
# Icinga2 does some "magic" with the socket during startup
|
||||||
# which causes random errors being raised (EACCES, ENOENT, ..)
|
# which causes random errors being raised (EACCES, ENOENT, ..)
|
||||||
# so we just ignore them until the timeout is reached
|
# so we just ignore them until the timeout is reached
|
||||||
@ -129,7 +143,9 @@ class LiveStatusSocket(object):
|
|||||||
def close(self):
|
def close(self):
|
||||||
if self._connected:
|
if self._connected:
|
||||||
self.sock.shutdown(socket.SHUT_RDWR)
|
self.sock.shutdown(socket.SHUT_RDWR)
|
||||||
|
Logger.debug('Shutted down Livestatus connection\n', True)
|
||||||
self.sock.close()
|
self.sock.close()
|
||||||
|
Logger.debug('Closed Livestatus socket\n', True)
|
||||||
self._connected = False
|
self._connected = False
|
||||||
|
|
||||||
def query(self, command):
|
def query(self, command):
|
||||||
@ -147,6 +163,7 @@ class LiveStatusSocket(object):
|
|||||||
|
|
||||||
full_query = '\n'.join([query] + self.options)
|
full_query = '\n'.join([query] + self.options)
|
||||||
self.sock.sendall((full_query + '\n\n').encode('utf-8'))
|
self.sock.sendall((full_query + '\n\n').encode('utf-8'))
|
||||||
|
Logger.debug('Sent Livestatus query: {0!r}\n'.format(full_query))
|
||||||
|
|
||||||
def recv(self):
|
def recv(self):
|
||||||
if not self._connected:
|
if not self._connected:
|
||||||
@ -168,5 +185,79 @@ class LiveStatusSocket(object):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
Logger.debug('Received Livestatus response: {0!r} (Header was: {1!r})'
|
||||||
|
'\n'.format(response, response_header), True)
|
||||||
return response_code, response
|
return response_code, response
|
||||||
|
|
||||||
|
|
||||||
|
class Logger(object):
|
||||||
|
INFO = 1
|
||||||
|
OK = 2
|
||||||
|
FAIL = 3
|
||||||
|
ERROR = 4
|
||||||
|
DEBUG_STD = 5
|
||||||
|
DEBUG_EXT = 6
|
||||||
|
|
||||||
|
VERBOSITY = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def permitted(cls, severity):
|
||||||
|
if cls.VERBOSITY is None:
|
||||||
|
cls.VERBOSITY = next((int(sys.argv.pop(i).partition('=')[2])
|
||||||
|
for i, a in enumerate(sys.argv)
|
||||||
|
if a.startswith('--verbosity=')), 1)
|
||||||
|
|
||||||
|
return (severity == cls.INFO and cls.VERBOSITY >= 1) or \
|
||||||
|
(severity == cls.OK and cls.VERBOSITY >= 1) or \
|
||||||
|
(severity == cls.FAIL and cls.VERBOSITY >= 1) or \
|
||||||
|
(severity == cls.ERROR and cls.VERBOSITY >= 1) or \
|
||||||
|
(severity == cls.DEBUG_STD and cls.VERBOSITY >= 2) or \
|
||||||
|
(severity == cls.DEBUG_EXT and cls.VERBOSITY >= 3)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def write(text, stderr=False):
|
||||||
|
if stderr:
|
||||||
|
sys.stderr.write(text)
|
||||||
|
sys.stderr.flush()
|
||||||
|
else:
|
||||||
|
sys.stdout.write(text)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def log(cls, severity, text):
|
||||||
|
if severity == cls.INFO and cls.permitted(cls.INFO):
|
||||||
|
cls.write('\x00[INFO] {0}'.format(text))
|
||||||
|
elif severity == cls.ERROR and cls.permitted(cls.ERROR):
|
||||||
|
cls.write('\x00[ERROR] {0}'.format(text))
|
||||||
|
elif severity == cls.FAIL and cls.permitted(cls.FAIL):
|
||||||
|
cls.write('\x00[FAIL] {0}'.format(text))
|
||||||
|
elif severity == cls.OK and cls.permitted(cls.OK):
|
||||||
|
cls.write('\x00[OK] {0}'.format(text))
|
||||||
|
elif severity == cls.DEBUG_STD and cls.permitted(cls.DEBUG_STD):
|
||||||
|
cls.write('\x00\x00[DEBUG] {0}'.format(text))
|
||||||
|
elif severity == cls.DEBUG_EXT and cls.permitted(cls.DEBUG_EXT):
|
||||||
|
cls.write('\x00\x00\x00\x00[DEBUG] {0}'.format(text))
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def info(cls, text):
|
||||||
|
return cls.log(cls.INFO, text)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def error(cls, text):
|
||||||
|
return cls.log(cls.ERROR, text)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fail(cls, text):
|
||||||
|
return cls.log(cls.FAIL, text)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ok(cls, text):
|
||||||
|
return cls.log(cls.OK, text)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def debug(cls, text, extended=False):
|
||||||
|
return cls.log(cls.DEBUG_EXT if extended else cls.DEBUG_STD, text)
|
||||||
|
|
||||||
|
@ -20,45 +20,69 @@ except ImportError:
|
|||||||
|
|
||||||
class Logger(object):
|
class Logger(object):
|
||||||
INFO = 1
|
INFO = 1
|
||||||
ERROR = 2
|
OK = 2
|
||||||
FAIL = 3
|
FAIL = 3
|
||||||
OK = 4
|
ERROR = 4
|
||||||
|
DEBUG_STD = 5
|
||||||
|
DEBUG_EXT = 6
|
||||||
|
|
||||||
|
VERBOSITY = 0
|
||||||
|
OUTPUT_LENGTH = 1024
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def write(text, stderr=False):
|
def write(text, stderr=False):
|
||||||
if stderr:
|
if stderr:
|
||||||
sys.stderr.write(text)
|
sys.stderr.write(text.encode('utf-8'))
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
else:
|
else:
|
||||||
sys.stdout.write(text)
|
sys.stdout.write(text.encode('utf-8'))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_verbosity(cls, verbosity):
|
||||||
|
cls.VERBOSITY = verbosity
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def log(cls, severity, text):
|
def log(cls, severity, text):
|
||||||
if severity == cls.INFO:
|
if severity == cls.INFO and cls.VERBOSITY >= 1:
|
||||||
cls.write('\033[1;94m[INFO]\033[1;0m {0}'.format(text))
|
cls.write('\033[1;94m[INFO]\033[1;0m {0}'.format(text))
|
||||||
elif severity == cls.ERROR:
|
elif severity == cls.ERROR and cls.VERBOSITY >= 1:
|
||||||
cls.write('\033[1;33m[ERROR]\033[1;0m {0}'.format(text), True)
|
cls.write('\033[1;33m[ERROR]\033[1;0m {0}'.format(text), True)
|
||||||
elif severity == cls.FAIL:
|
elif severity == cls.FAIL and cls.VERBOSITY >= 1:
|
||||||
cls.write('\033[1;31m[FAIL] {0}\033[1;0m'.format(text))
|
cls.write('\033[1;31m[FAIL] {0}\033[1;0m'.format(text))
|
||||||
elif severity == cls.OK:
|
elif severity == cls.OK and cls.VERBOSITY >= 1:
|
||||||
cls.write('\033[1;32m[OK]\033[1;0m {0}'.format(text))
|
cls.write('\033[1;32m[OK]\033[1;0m {0}'.format(text))
|
||||||
|
elif severity == cls.DEBUG_STD and cls.VERBOSITY >= 2:
|
||||||
|
cls.write('\033[1;90m[DEBUG]\033[1;0m {0}'.format(text))
|
||||||
|
elif severity == cls.DEBUG_EXT and cls.VERBOSITY >= 3:
|
||||||
|
if cls.VERBOSITY < 4 and len(text) > cls.OUTPUT_LENGTH:
|
||||||
|
suffix = '... (Truncated to {0} bytes)\n' \
|
||||||
|
''.format(cls.OUTPUT_LENGTH)
|
||||||
|
text = text[:cls.OUTPUT_LENGTH] + suffix
|
||||||
|
cls.write('\033[1;90m[DEBUG]\033[1;0m {0}'.format(text))
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def info(cls, text):
|
def info(cls, text):
|
||||||
cls.log(cls.INFO, text)
|
return cls.log(cls.INFO, text)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def error(cls, text):
|
def error(cls, text):
|
||||||
cls.log(cls.ERROR, text)
|
return cls.log(cls.ERROR, text)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fail(cls, text):
|
def fail(cls, text):
|
||||||
cls.log(cls.FAIL, text)
|
return cls.log(cls.FAIL, text)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ok(cls, text):
|
def ok(cls, text):
|
||||||
cls.log(cls.OK, text)
|
return cls.log(cls.OK, text)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def debug(cls, text, extended=False):
|
||||||
|
return cls.log(cls.DEBUG_EXT if extended else cls.DEBUG_STD, text)
|
||||||
|
|
||||||
|
|
||||||
class TestSuite(object):
|
class TestSuite(object):
|
||||||
@ -115,26 +139,27 @@ class TestSuite(object):
|
|||||||
def run(self):
|
def run(self):
|
||||||
for path in self._tests:
|
for path in self._tests:
|
||||||
test_name = os.path.basename(path)
|
test_name = os.path.basename(path)
|
||||||
Logger.info('Copying test "{0}" to remote machine\n'.format(test_name))
|
Logger.debug('Copying test "{0}" to remote machine\n'.format(test_name))
|
||||||
self._copy_test(path)
|
self._copy_test(path)
|
||||||
self._apply_setup_routines(test_name, 'setup')
|
self._apply_setup_routines(test_name, 'setup')
|
||||||
Logger.info('Running test "{0}"...\n'.format(test_name))
|
note_printed = Logger.info('Running test "{0}"...\n'.format(test_name))
|
||||||
result = self._run_test(path)
|
result = self._run_test(path)
|
||||||
Logger.info('Test "{0}" has finished (Total tests: {1}, Failures: {2})\n'
|
Logger.info('Test "{0}" has finished (Total tests: {1}, Failures: {2})\n'
|
||||||
''.format(test_name, result['total'], result['failures']))
|
''.format(test_name, result['total'], result['failures']))
|
||||||
self._apply_setup_routines(test_name, 'teardown')
|
self._apply_setup_routines(test_name, 'teardown')
|
||||||
Logger.info('Removing test "{0}" from remote machine\n'.format(test_name))
|
Logger.debug('Removing test "{0}" from remote machine\n'.format(test_name))
|
||||||
self._remove_test(test_name)
|
self._remove_test(test_name)
|
||||||
self._results[test_name] = result
|
self._results[test_name] = result
|
||||||
Logger.write('\n')
|
if note_printed:
|
||||||
|
Logger.write('\n')
|
||||||
|
|
||||||
def _apply_setup_routines(self, test_name, context):
|
def _apply_setup_routines(self, test_name, context):
|
||||||
instructions = next((t[1].get(context)
|
instructions = next((t[1].get(context)
|
||||||
for t in self._config.get('setups', {}).iteritems()
|
for t in self._config.get('setups', {}).iteritems()
|
||||||
if re.match(t[0], test_name)), None)
|
if re.match(t[0], test_name)), None)
|
||||||
if instructions is not None:
|
if instructions is not None:
|
||||||
Logger.info('Applying {0} routines for test "{1}" .. '
|
note_printed = Logger.info('Applying {0} routines for test "{1}" .. '
|
||||||
''.format(context, test_name))
|
''.format(context, test_name))
|
||||||
for instruction in instructions.get('copy', []):
|
for instruction in instructions.get('copy', []):
|
||||||
source, _, destination = instruction.partition('>>')
|
source, _, destination = instruction.partition('>>')
|
||||||
self._copy_file(source.strip(), destination.strip())
|
self._copy_file(source.strip(), destination.strip())
|
||||||
@ -142,7 +167,8 @@ class TestSuite(object):
|
|||||||
self._remove_file(filepath)
|
self._remove_file(filepath)
|
||||||
for command in instructions.get('exec', []):
|
for command in instructions.get('exec', []):
|
||||||
self._exec_command(command)
|
self._exec_command(command)
|
||||||
Logger.write('Done\n')
|
if note_printed:
|
||||||
|
Logger.write('Done\n')
|
||||||
|
|
||||||
def _remove_file(self, path):
|
def _remove_file(self, path):
|
||||||
command = self._config['commands']['clean'].format(path)
|
command = self._config['commands']['clean'].format(path)
|
||||||
@ -154,14 +180,14 @@ class TestSuite(object):
|
|||||||
command = self._config['commands']['exec'].format(command)
|
command = self._config['commands']['exec'].format(command)
|
||||||
rc = subprocess.call(command, stdout=DEVNULL, shell=True)
|
rc = subprocess.call(command, stdout=DEVNULL, shell=True)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
Logger.error('Command "{0}" exited with exit code "{1}"' \
|
Logger.error('Command "{0}" exited with exit code "{1}"\n' \
|
||||||
''.format(command, rc))
|
''.format(command, rc))
|
||||||
|
|
||||||
def _copy_file(self, source, destination):
|
def _copy_file(self, source, destination):
|
||||||
command = self._config['commands']['copy'].format(source, destination)
|
command = self._config['commands']['copy'].format(source, destination)
|
||||||
rc = subprocess.call(command, stdout=DEVNULL, shell=True)
|
rc = subprocess.call(command, stdout=DEVNULL, shell=True)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
Logger.error('Cannot copy file "{0}" to "{1}" ({2})' \
|
Logger.error('Cannot copy file "{0}" to "{1}" ({2})\n' \
|
||||||
''.format(source, destination, rc))
|
''.format(source, destination, rc))
|
||||||
|
|
||||||
def _copy_test(self, path):
|
def _copy_test(self, path):
|
||||||
@ -176,8 +202,10 @@ class TestSuite(object):
|
|||||||
command = self._config['commands']['exec']
|
command = self._config['commands']['exec']
|
||||||
target = os.path.join(self._config['settings']['test_root'],
|
target = os.path.join(self._config['settings']['test_root'],
|
||||||
os.path.basename(path))
|
os.path.basename(path))
|
||||||
p = subprocess.Popen(command.format(target), stdout=subprocess.PIPE,
|
options = ['--verbosity={0}'.format(Logger.VERBOSITY)]
|
||||||
stderr=subprocess.PIPE, shell=True)
|
p = subprocess.Popen(command.format(' '.join([target] + options)),
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
|
shell=True)
|
||||||
output, test_count, failed_tests = self._watch_output(p.stdout)
|
output, test_count, failed_tests = self._watch_output(p.stdout)
|
||||||
return {
|
return {
|
||||||
'total': test_count,
|
'total': test_count,
|
||||||
@ -194,8 +222,12 @@ class TestSuite(object):
|
|||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
verbosity_level = line.count('\x00')
|
||||||
|
line = line[verbosity_level:]
|
||||||
if line.startswith('[ERROR] '):
|
if line.startswith('[ERROR] '):
|
||||||
Logger.error(line[8:])
|
Logger.error(line[8:])
|
||||||
|
elif line.startswith('[DEBUG] '):
|
||||||
|
Logger.debug(line[8:], verbosity_level == 4)
|
||||||
elif line.startswith('[FAIL] '):
|
elif line.startswith('[FAIL] '):
|
||||||
Logger.fail(line[7:])
|
Logger.fail(line[7:])
|
||||||
failures += 1
|
failures += 1
|
||||||
@ -211,11 +243,15 @@ class TestSuite(object):
|
|||||||
|
|
||||||
|
|
||||||
def parse_commandline():
|
def parse_commandline():
|
||||||
parser = OptionParser(version='0.2')
|
parser = OptionParser(version='0.5')
|
||||||
parser.add_option('-C', '--config', default="run_tests.conf",
|
parser.add_option('-C', '--config', default="run_tests.conf",
|
||||||
help='The path to the config file to use [%default]')
|
help='The path to the config file to use [%default]')
|
||||||
parser.add_option('-R', '--results',
|
parser.add_option('-R', '--results',
|
||||||
help='The file where to store the test results')
|
help='The file where to store the test results')
|
||||||
|
parser.add_option('-v', '--verbose', action='count', default=1,
|
||||||
|
help='Be more verbose (Maximum output: -vvv)')
|
||||||
|
parser.add_option('-q', '--quiet', action='count', default=0,
|
||||||
|
help='Be less verbose')
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
@ -226,6 +262,7 @@ def main():
|
|||||||
for path in (p for a in arguments for p in glob.glob(a)):
|
for path in (p for a in arguments for p in glob.glob(a)):
|
||||||
suite.add_test(path)
|
suite.add_test(path)
|
||||||
|
|
||||||
|
Logger.set_verbosity(options.verbose - options.quiet)
|
||||||
suite.run()
|
suite.run()
|
||||||
|
|
||||||
if options.results is not None:
|
if options.results is not None:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
vagrant ssh-config > ssh_config
|
vagrant ssh-config > ssh_config
|
||||||
./run_tests.py *.test
|
./run_tests.py $@ *.test
|
||||||
rm -f ssh_config
|
rm -f ssh_config
|
||||||
|
Loading…
x
Reference in New Issue
Block a user