Skip to content

Instantly share code, notes, and snippets.

@rc5hack
Last active August 29, 2015 14:05
Show Gist options
  • Save rc5hack/34a68d464a76fd32df5f to your computer and use it in GitHub Desktop.
Save rc5hack/34a68d464a76fd32df5f to your computer and use it in GitHub Desktop.
4yandex
#!/usr/bin/env python
import os, sys, commands
import argparse
import ConfigParser
version = '0.1.1'
default_monitoring_checks_cache_path = '/var/cache/monitoring'
def createParser ():
parser = argparse.ArgumentParser(
prog = 'custom-monitoring-checks-helper',
description = '''Helper Python script to handle custom monitoring checks.
Checks are defined with config files (one for each).
Each check could be forced to run and display it's actual status,
or all checks latest statuses could be displayed from cache.
If there are no cached data for one of the checks, this check
would be also forced to run in order to retrieve it's status.''',
epilog = '''(c) Antonio Kless 2014.
This software is available under BSD license.'''
)
parser.add_argument('-a', '--all', action='store_true', default=False, help='show all checks latest statuses (show cached status, or cause a new check run if no cached data found)')
parser.add_argument('-f', '--force-check', help="force check run and show it's actual status", metavar='CHECK_NAME')
parser.add_argument('-s', '--show', help='show config details for the check specified', metavar='CHECK_NAME')
parser.add_argument('-d', '--config-file-scan-dir', default='./custom-monitoring-checks.d', help='specify a directory where config files should be looked for (default - ./custom-monitoring-checks.d)', metavar='DIR')
parser.add_argument('-V', '--version', action='version', version='%(prog)s {}'.format(version), help='show version and exit')
return parser
def config_file_scan_dir (dirname):
if (os.path.exists(dirname)):
files_found = os.listdir(dirname)
if (len(files_found)) < 1:
sys.stderr.write("No config files found in " + dirname + " - don't know what to do, aborting.\n")
sys.exit(1)
checks = {}
for config_file in files_found:
check = config_file_parse(config_file)
if check:
checks.update(check)
if (len(checks)) < 1:
sys.stderr.write("No valid config files found, no checks loaded, exiting.\n")
sys.exit(0)
print('Now ' + format(len(checks)) + ' check(s) loaded.')
return checks
else:
sys.stderr.write("Directory " + dirname + " does not exist or not accessable, aborting.\n")
sys.exit(1)
def config_file_parse (filename):
print('Found config file: ' + filename)
config = ConfigParser.ConfigParser()
config.readfp(open(args.config_file_scan_dir + '/' + filename))
#TODO: config values validation needed
try:
parsed_config = {
config.get('check', 'name'): {
'path': config.get('check', 'path'),
'description': config.get('check', 'description'),
'cronstring': config.get('check', 'cronstring'),
'cache': config.get('check', 'cache')
}
}
print(' ...successfully parsed config for check "' + config.get('check', 'name') + '"')
return parsed_config
except BaseException:
print(' ...not a valid config file, skipping')
def read_check_status_from_cache (filename, checkname):
#FIXME: f.read() is danger to use as it may causes memory overflow
if (os.path.exists(filename)):
try:
f = open(filename, 'r')
except IOError:
pass
else:
content = f.read()
f.close()
if (len(content) > 1):
return content
backupfilename = default_monitoring_checks_cache_path + '/' + checkname + '.last-run'
if (os.path.exists(backupfilename)):
try:
f = open(backupfilename, 'r')
except IOError:
pass
else:
content = f.read()
f.close()
if (len(content) > 1):
return content
return False
if __name__ == '__main__':
parser = createParser()
if (len(sys.argv)) < 2:
sys.stderr.write("No arguments passed - don't know what to do, aborting.\n")
print("\n")
parser.print_help()
sys.exit(1)
args = parser.parse_args()
checks = config_file_scan_dir(args.config_file_scan_dir)
print("\n")
if (args.show):
if (args.show in checks):
print('Config details for check "' + args.show + '":')
print(' command to execute or path to executable file: ' + checks[args.show]['path'])
print(' check description: ' + checks[args.show]['description'])
print(' scheduling string for cron job: ' + checks[args.show]['cronstring'])
print(' latest check status should be stored to: ' + checks[args.show]['cache'])
else:
sys.stderr.write("No such check found - " + args.show + ", aborting.\n")
sys.exit(1)
elif (args.force_check):
if (args.force_check in checks):
print('Force run for check "' + args.force_check + '":')
print(commands.getoutput(checks[args.force_check]['path']))
else:
sys.stderr.write("No such check found - " + args.force_check + ", aborting.\n")
sys.exit(1)
elif (args.all):
for check in checks:
print('Latest value for check "' + check + '":')
data_from_cache = read_check_status_from_cache(checks[check]['cache'], check)
if (data_from_cache):
print ' ...cached data available:'
print data_from_cache
else:
print ' ...cached data unavailable, force check run:'
print(commands.getoutput(checks[check]['path']))
else:
sys.stderr.write("Not enough arguments passed - don't know what to do, aborting.\n")
print("\n")
parser.print_help()
sys.exit(1)
#TODO: when processing --force_check or --all, it's better to format check's status output to some human-friendly view
[check]
name = new_os_updates_available
path = /opt/scripts/monitoring/new-os-updates-available.sh
description = Returns 1, if there are some new OS updates available to install, and 0 instead
cronstring = */30 * * * *
cache = /any/custom/path/to/cache/new-os-updates-available.last-run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment