From 00360bf03e331a71432aad110c8304e121a44f98 Mon Sep 17 00:00:00 2001 From: Nicolas Wavrant <nicolas.wavrant@tiolive.com> Date: Wed, 18 Dec 2013 12:07:57 +0100 Subject: [PATCH] stack-monitor: creation of the stack. Right now, it can run promises and monitoring scripts(manually added), and create a false rss feed --- stack/monitor/buildout.cfg | 88 ++++++++++++++++++++++++++ stack/monitor/make-rss.sh.in | 9 +++ stack/monitor/monitor.cfg.in | 77 ++++++++++++++++++++++ stack/monitor/monitor.py.in | 73 +++++++++++++++++++++ stack/monitor/run-monitor-script.sh.in | 4 ++ stack/monitor/status2rss.py | 46 ++++++++++++++ 6 files changed, 297 insertions(+) create mode 100644 stack/monitor/buildout.cfg create mode 100644 stack/monitor/make-rss.sh.in create mode 100644 stack/monitor/monitor.cfg.in create mode 100644 stack/monitor/monitor.py.in create mode 100644 stack/monitor/run-monitor-script.sh.in create mode 100644 stack/monitor/status2rss.py diff --git a/stack/monitor/buildout.cfg b/stack/monitor/buildout.cfg new file mode 100644 index 000000000..6cd24b63b --- /dev/null +++ b/stack/monitor/buildout.cfg @@ -0,0 +1,88 @@ +[buildout] + +extends = + ../../component/dcron/buildout.cfg + +parts = + backup-script-template + collective.recipe.template-egg + dcron + eggs + extra-eggs + make-rss + monitor-bin + monitor-template + rss-bin + slapos-cookbook + +[collective.recipe.template-egg] +recipe = zc.recipe.egg +eggs = collective.recipe.template + PyRSS2Gen + +[extra-eggs] +recipe = zc.recipe.egg +interpreter = pythonforrssgen +eggs = + PyRSS2Gen + +[make-rss-script] +recipe = slapos.recipe.template +url = ${:_profile_base_location_}/make-rss.sh.in +#md5sum = +output = ${buildout:directory}/make-rss.sh.in +mode = 0644 + +[run-monitor-script] +recipe = hexagonit.recipe.download +url = ${:_profile_base_location_}/${:filename} +download-only = true +#md5sum = +filename = run-monitor-script.sh.in +mode = 0644 + +[monitor-template] +recipe = slapos.recipe.template +url = ${:_profile_base_location_}/monitor.cfg.in +output = ${buildout:directory}/monitor.cfg +#md5sum = 6564a2e7c7d9e631b997ff2960ad3299 +mode = 0644 + +[monitor-bin] +recipe = hexagonit.recipe.download +url = ${:_profile_base_location_}/${:filename} +download-only = true +#md5sum = +filename = monitor.py.in +mode = 0644 + +[rss-bin] +recipe = hexagonit.recipe.download +url = ${:_profile_base_location_}/${:filename} +download-only = true +#md5sum = +filename = status2rss.py +mode = 0644 + +[dcron-service] +recipe = slapos.recipe.template +url = ${template-dcron-service:output} +output = $${directory:services}/crond +mode = 0700 +logfile = $${directory:log}/crond.log + +#[status2rss] +#recipe = slapos.recipe.download +#url = ${:_profile_base_location_}/status2rss.py +#md5sum = 916f37f083b1ef391adea2f7a717bf8a +#location = ${buildout:parts-directory}/${:_buildout_section_name_}/status2rss.py +#mode = 0644 + +[eggs] +recipe = z3c.recipe.scripts +eggs = + slapos.cookbook + PyRSS2Gen + +[versions] +PyRSS2Gen = 1.1 diff --git a/stack/monitor/make-rss.sh.in b/stack/monitor/make-rss.sh.in new file mode 100644 index 000000000..a788bd87e --- /dev/null +++ b/stack/monitor/make-rss.sh.in @@ -0,0 +1,9 @@ +#!${dash-output:dash} + +status=$${directory:monitor-result}/monitor.bool +RSS_DIR=$${directory:monitor-result} +PYTHON=${buildout:directory}/bin/${extra-eggs:interpreter} +STATUS2RSS=${rss-bin:location}/${rss-bin:filename} + +NAME=`basename $status` +cat $status | $PYTHON $STATUS2RSS "Backup status $NAME" "http://localhost/$NAME.rss" > $RSS_DIR/monitor.rss \ No newline at end of file diff --git a/stack/monitor/monitor.cfg.in b/stack/monitor/monitor.cfg.in new file mode 100644 index 000000000..4cef1bbb9 --- /dev/null +++ b/stack/monitor/monitor.cfg.in @@ -0,0 +1,77 @@ +[directory] +home = $${buildout:directory} +etc = $${:home}/etc +bin = $${:home}/bin +var = $${:home}/var +cron-entries = $${:etc}/cron.d +crontabs = $${:etc}/crontabs +cronstamps = $${:etc}/cronstamps +log = $${:var}/log +monitor = $${:etc}/monitor +monitor-result = $${:var}/monitor +promise = $${:etc}/promise + +[cron] +recipe = slapos.cookbook:cron +dcrond-binary = ${dcron:location}/sbin/crond +cron-entries = $${directory:cron-entries} +crontabs = $${directory:crontabs} +cronstamps = $${directory:cronstamps} +catcher = $${cron-simplelogger:wrapper} +binary = $${directory:service}/crond + +# Add log to cron +[cron-simplelogger] +recipe = slapos.cookbook:simplelogger +wrapper = $${directory:bin}/cron_simplelogger +log = $${directory:log}/cron.log + +[cron-entry-monitor] +<= cron +recipe = slapos.cookbook:cron.d +name = launch-monitor +frequency = * * * * * +command = $${deploy-run-monitor-script:rendered} + +[cron-entry-rss] +<= cron +recipe = slapos.cookbook:cron.d +name = build-rss +frequency = * * * * * +command = $${make-rss:output} + +[deploy-run-monitor-script] +recipe = slapos.recipe.template:jinja2 +template = ${run-monitor-script:location}/${run-monitor-script:filename} +rendered = $${directory:bin}/run-monitor.sh +mode = 0744 +context = + raw dash_bin ${dash:location}/bin/dash + key monitor_bin deploy-monitor-script:rendered + key output_directory directory:monitor-result + raw output_file_verbose monitor.json + raw output_file_quiet monitor.bool + +[deploy-monitor-script] +recipe = slapos.recipe.template:jinja2 +template = ${monitor-bin:location}/${monitor-bin:filename} +rendered = $${directory:bin}/monitor.py +mode = 0744 +context = + section directory directory + +[deploy-rss-script] +recipe = hexagonit.recipe.download +url = ${rss-bin:destination}/${rss-bin:filename} +destination = $${directory:bin} +filename = ${rss-bin:filename} +#md5sum = +mode = 0744 +download-only = true + +[make-rss] +recipe = slapos.recipe.template +url = ${make-rss-script:output} +output = $${directory:bin}/make-rss.sh +#md5sum = +mode = 0744 \ No newline at end of file diff --git a/stack/monitor/monitor.py.in b/stack/monitor/monitor.py.in new file mode 100644 index 000000000..7109cd08a --- /dev/null +++ b/stack/monitor/monitor.py.in @@ -0,0 +1,73 @@ +#!/usr/bin/python + +import json +import os +import subprocess +import sys +import time +from optparse import OptionParser + +promise_dir = "{{ directory['promise'] }}" +service_dir = "{{ directory['service'] }}" +monitor_dir = "{{ directory['monitor'] }}" +instance_path = "{{ directory['home'] }}" + +def getListOfScripts(): + scripts = [] + for dir in (promise_dir, monitor_dir): + if os.path.exists(dir) and os.path.isdir(dir): + for file in os.listdir(dir): + scripts.append(os.path.join(dir, file)) + if scripts: + return scripts + else: + exit("There is a problem in your directories" \ + "of monitoring. Please check them") + +def run(): + scripts = getListOfScripts() + script_timeout = 3 + failed_scripts = [] + failed_bool = False + for script_path in scripts: + command = [os.path.join(promise_dir, script_path)] + script = os.path.basename(command[0]) + + process_handler = subprocess.Popen(command, + cwd=instance_path, + env=None if sys.platform == 'cygwin' else {}, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE) + process_handler.stdin.flush() + process_handler.stdin.close() + process_handler.stdin = None + + time.sleep(script_timeout) + + if process_handler.poll() is None: + process_handler.terminate() + failed_bool = True + failed_scripts.append({script_path : "Time Out"}) + elif process_handler.poll() != 0: + stderr = process_handler.communicate()[1] + if stderr is not None: + failed_bool = True + failed_scripts.append({script_path : stderr.strip()}) + return failed_scripts + + +if __name__ == "__main__": + parser = OptionParser() + parser.add_option("-v", "--verbose", action="store_true", dest="verbose", + help="return a json containing info for each monitored script") + (options, args) = parser.parse_args() + fails = run() + if options.verbose: + print fails + elif len(fails) == 0: + print 0 + exit(0) + else: + print 1 + exit(1) \ No newline at end of file diff --git a/stack/monitor/run-monitor-script.sh.in b/stack/monitor/run-monitor-script.sh.in new file mode 100644 index 000000000..75d15bca3 --- /dev/null +++ b/stack/monitor/run-monitor-script.sh.in @@ -0,0 +1,4 @@ +#!{{ dash_bin }} + +echo "`date`, `{{ monitor_bin }} -v`" > {{ output_directory }}/{{ output_file_verbose }} +echo "`date`, `{{ monitor_bin }}`" > {{ output_directory }}/{{ output_file_quiet }} \ No newline at end of file diff --git a/stack/monitor/status2rss.py b/stack/monitor/status2rss.py new file mode 100644 index 000000000..a1e7f7f5c --- /dev/null +++ b/stack/monitor/status2rss.py @@ -0,0 +1,46 @@ +import datetime +import uuid +import PyRSS2Gen +import sys +from email.utils import parsedate_tz, mktime_tz +import base64 + +# Based on http://thehelpfulhacker.net/2011/03/27/a-rss-feed-for-your-crontabs/ + +# ### Defaults +TITLE = sys.argv[1] +LINK = sys.argv[2] +DESCRIPTION = TITLE + +items = [] + +while 1: + try: + line = sys.stdin.readline() + except KeyboardInterrupt: + break + + if not line: + break + + time, desc = line.split(',', 1) + + rss_item = PyRSS2Gen.RSSItem( + title = desc, + description = "%s, %s" % (time, desc), + link = LINK, + pubDate = datetime.datetime.fromtimestamp(mktime_tz(parsedate_tz(time))), + guid = PyRSS2Gen.Guid(base64.b64encode("%s, %s" % (time, desc))) + ) + items.append(rss_item) + +### Build the rss feed +rss_feed = PyRSS2Gen.RSS2 ( + title = TITLE, + link = LINK, + description = DESCRIPTION, + lastBuildDate = datetime.datetime.utcnow(), + items = items + ) + +print rss_feed.to_xml() \ No newline at end of file -- 2.30.9