Commit c9acedbe authored by Tristan Cavelier's avatar Tristan Cavelier

monitor: redesign monitor.py.in

parent c6b9b5ef
#!{{ python_executable }} #!{{ python_executable }}
configuration_location = "{{ configuration_location }}"
import json import sys
import os import os
import subprocess import subprocess
import sys
import sqlite3
import time
import threading import threading
from optparse import OptionParser, make_option import json
import ConfigParser
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 = [ def main():
make_option("-a", "--all", action="store_true", dest="all", # initialisation
help="test everything : promises, services, customs"), config = loadConfig([configuration_location])
make_option("-n", "--no-write", action="store_true", dest="only_stdout", # create symlinks from monitor.conf
help="just show the json output on stdout"), createSymlinksFromConfig((config, "monitor", "public-folder"), (config, "monitor", "public-path-list"))
make_option("-m", "--monitors", action="store_true", dest="monitor", createSymlinksFromConfig((config, "monitor", "private-folder"), (config, "monitor", "private-path-list"))
help="add the custom monitoring file to the files to monitor"), # search for configurations in monitor.conf.d
make_option("-p", "--promises", action="store_true", dest="promise", configuration_folder_location = configuration_location + ".d"
help="add the promises\'file to the files to monitor"), service_config_list = [
make_option("-s", "--services", action="store_true", dest="service", loadConfig(os.path.join(configuration_folder_location, filename))
help="add the file containing services\'pid to the files to monitor") for filename in os.listdir(configuration_folder_location)
] if os.path.isfile(os.path.join(configuration_folder_location, filename))
]
# search for promises in ...?
# XXX see old monitor.py.in
# generate monitor.json
monitor_dict = {}
tmp = softConfigGet(config, "monitor", "monitor-url-list")
if tmp:
monitor_dict["monitor_url_list"] = tmp.split()
if service_config_list:
monitor_dict["service_list"] = []
for service_config in service_config_list:
service_dict = {}
monitor_dict["service_list"].append(service_dict)
setConfigIfNotEmptyToDict(service_config, "service", "title", service_dict, "title")
service_name = service_dict["service_name"] = service_config.get("service", "name")
service_dict["status_url"] = "/public/%s/status.json" % service_name
with open(config.get("monitor", "monitor-json"), "w") as fp:
json.dump(monitor_dict, fp)
# create symlinks from service configurations
for service_config in service_config_list:
createSymlinksFromConfig((config, "monitor", "public-folder"), (service_config, "service", "public-path-list"))
createSymlinksFromConfig((config, "monitor", "private-folder"), (service_config, "service", "private-path-list"))
# run scripts according to frequency
# XXX
return 0
def loadConfig(pathes):
config = ConfigParser.ConfigParser()
config.read(pathes)
return config
def softConfigGet(config, *args, **kwargs):
try:
return config.get(*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
return None
def setConfigIfNotEmptyToDict(config, section, option, dyct, key):
tmp = softConfigGet(config, section, option)
if tmp:
dyct[key] = tmp
def createSymlinksFromConfig(destination_folder_config_tuple, source_list_config_tuple):
destination_folder = softConfigGet(*destination_folder_config_tuple)
if destination_folder:
source_path_str = softConfigGet(*source_list_config_tuple)
if source_path_str:
for path in source_path_str.split():
try:
os.symlink(path, os.path.join(destination_folder, os.path.basename(path)))
except OSError, e:
if e.errno != os.errno.EEXIST:
raise
class Popen(subprocess.Popen): class Popen(subprocess.Popen):
def set_timeout(self, timeout): def set_timeout(self, timeout):
self.set_timeout = None # assert we're not called twice self.set_timeout = None # assert we're not called twice
event = threading.Event() event = threading.Event()
event.__killed = False # we just need a mutable killed = [False] # we just need a mutable
def t(): def t():
# do not call wait() or poll() because they're not thread-safe # do not call wait() or poll() because they're not thread-safe
if not event.wait(timeout) and self.returncode is None: if not event.wait(timeout) and self.returncode is None:
# race condition if waitpid completes just before the signal sent ? # race condition if waitpid completes just before the signal sent ?
self.terminate() self.terminate()
event.__killed = True killed[0] = True
if event.wait(5): if event.wait(5):
return return
if self.returncode is None: if self.returncode is None:
...@@ -53,120 +94,26 @@ class Popen(subprocess.Popen): ...@@ -53,120 +94,26 @@ class Popen(subprocess.Popen):
t = threading.Thread(target=t) t = threading.Thread(target=t)
t.daemon = True t.daemon = True
t.start() t.start()
def killed(): def isKilled():
event.set() event.set()
t.join() t.join()
return event.__killed return killed[0]
return killed return isKilled
def init_db(db):
db.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);
""")
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): def executePath(path):
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 # XXX script_timeout could be passed as parameters
script_timeout = 60 # in seconds script_timeout = 3600 # in seconds
result = {}
with open(os.devnull, 'r+') as f: 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, p = Popen(command, cwd=instance_path,
env=None if sys.platform == 'cygwin' else {}, env=None if sys.platform == 'cygwin' else {},
stdin=f, stdout=f, stderr=subprocess.PIPE) stdin=f, stdout=f, stderr=subprocess.PIPE)
killed = p.set_timeout(script_timeout) killed = p.set_timeout(script_timeout)
stderr = p.communicate()[1] stderr = p.communicate()[1]
if killed(): if killed():
result[script] = "Time Out" return "Timed Out"
elif p.returncode: elif p.returncode:
result[script] = stderr.strip() return stderr.strip()
return result return None
def writeFiles(monitors):
timestamp = int(time.time())
db = sqlite3.connect(db_path)
init_db(db)
status = SUCCESS
for key, value in monitors.iteritems():
if value:
element_status = status = FAILURE
else:
element_status = SUCCESS
db.execute("insert into individual_status(timestamp, element, output, status) values (?, ?, ?, ?)", (timestamp, key, value, element_status))
db.execute("insert into status(timestamp, status) values (?, ?)", (timestamp, status))
db.commit()
db.close()
monitors['datetime'] = time.ctime(timestamp)
json.dump(monitors, open(monitoring_file_json, "w+"))
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__": if __name__ == "__main__":
main() sys.exit(main())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment