#!{{ python_executable }} import datetime import json import os import subprocess import sys import sqlite3 import time import threading from optparse import OptionParser, make_option FAILURE = "FAILURE" SUCCESS = "SUCCESS" db_path = "{{ monitor_parameter['db-path'] }}" instance_path = "{{ directory['home'] }}" monitor_dir = "{{ directory['monitor-custom-scripts'] }}" pid_dir = "{{ directory['run'] }}" promise_dir = "{{ directory['promise'] }}" monitoring_file_json = "{{ monitoring_file_json }}" option_list = [ make_option("-a", "--all", action="store_true", dest="all", help="test everything : promises, services, customs"), make_option("-n", "--no-write", action="store_true", dest="only_stdout", help="just show the json output on stdout"), make_option("-m", "--monitors", action="store_true", dest="monitor", help="add the custom monitoring file to the files to monitor"), make_option("-p", "--promises", action="store_true", dest="promise", help="add the promises\'file to the files to monitor"), make_option("-s", "--services", action="store_true", dest="service", help="add the file containing services\'pid to the files to monitor") ] class Popen(subprocess.Popen): def set_timeout(self, timeout): self.set_timeout = None # assert we're not called twice event = threading.Event() event.__killed = False # we just need a mutable def t(): # do not call wait() or poll() because they're not thread-safe if not event.wait(timeout) and self.returncode is None: # race condition if waitpid completes just before the signal sent ? self.terminate() event.__killed = True if event.wait(5): return if self.returncode is None: self.kill() # same race as for terminate ? t = threading.Thread(target=t) t.daemon = True t.start() def killed(): event.set() t.join() return event.__killed return killed def init_db(): db = sqlite3.connect(db_path) c = db.cursor() c.executescript(""" CREATE TABLE IF NOT EXISTS status ( timestamp INTEGER UNIQUE, status VARCHAR(255)); CREATE TABLE IF NOT EXISTS individual_status ( timestamp INTEGER, status VARCHAR(255), element VARCHAR(255), output TEXT); """) db.commit() db.close() def getListOfScripts(directory): """ Get the list of script inside of a directory (not recursive) """ scripts = [] if os.path.exists(directory) and os.path.isdir(directory): for file_name in os.listdir(directory): file = os.path.join(directory, file_name) if os.access(file, os.X_OK) and not os.path.isdir(file): scripts.append(file) else: exit("There is a problem in your directories" \ "of monitoring. Please check them") return scripts def runServices(directory): services = getListOfScripts(directory) result = {} for service in services: service_path = os.path.join(pid_dir, service) service_name = os.path.basename(service_path) try: pid = int(open(service_path).read()) ### because apache (or others) can write sockets ### We also ignore not readable pid files except (IOError, ValueError): continue try: os.kill(pid, 0) result[service_name] = '' except OSError: result[service_name] = "This service is not running anymore" return result def runScripts(directory): # XXX script_timeout could be passed as parameters script_timeout = 60 # in seconds result = {} with open(os.devnull, 'r+') as f: for script in getListOfScripts(directory): command = os.path.join(promise_dir, script), script = os.path.basename(script) result[script] = '' p = Popen(command, cwd=instance_path, env=None if sys.platform == 'cygwin' else {}, stdin=f, stdout=f, stderr=subprocess.PIPE) killed = p.set_timeout(script_timeout) stderr = p.communicate()[1] if killed(): result[script] = "Time Out" elif p.returncode: result[script] = stderr.strip() return result def writeFiles(monitors): timestamp = int(time.time()) date = datetime.datetime.now().ctime() init_db() db = sqlite3.connect(db_path) fail = False for key, value in monitors.iteritems(): element_status = SUCCESS if value != "" : fail = True element_status = FAILURE db.execute("insert into individual_status(timestamp, element, output, status) values (?, ?, ?, ?)", (timestamp, key, value, element_status)) db.commit() status = SUCCESS if fail: status = FAILURE db.execute("insert into status(timestamp, status) values (?, ?)", (timestamp, status)) db.commit() db.close() monitors['datetime'] = date open(monitoring_file_json, "w+").write(json.dumps(monitors)) def main(): parser = OptionParser(option_list=option_list) monitors = {} (options, args) = parser.parse_args() if not (options.monitor or options.promise or options.service or options.all): exit("Please provide at list one arg in : -a, -m, -p, -s") if options.monitor or options.all: monitors.update(runScripts(monitor_dir)) if options.promise or options.all: monitors.update(runScripts(promise_dir)) if options.service or options.all: monitors.update(runServices(pid_dir)) if options.only_stdout: print json.dumps(monitors) else: writeFiles(monitors) if __name__ == "__main__": main()