Commit e4adff53 authored by Alain Takoudjou's avatar Alain Takoudjou

cleanup monitor2 stack

parent 48d970f4
This diff is collapsed.
PidFile "{{ httpd_configuration.get('pid-file') }}"
StartServers 1
ServerLimit 1
ThreadLimit 4
ThreadsPerChild 4
ServerName example.com
ServerAdmin someone@email
<IfDefine !MonitorPort>
Listen [{{ httpd_configuration.get('listening-ip') }}]:{{ monitor_parameters.get('port') }}
Define MonitorPort
</IfDefine>
DocumentRoot "{{ directory.get('www') }}"
ErrorLog "{{ httpd_configuration.get('error-log') }}"
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule mime_module modules/mod_mime.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule dir_module modules/mod_dir.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule alias_module modules/mod_alias.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
# SSL Configuration
<IfDefine !SSLConfigured>
Define SSLConfigured
SSLCertificateFile {{ httpd_configuration.get('certificate') }}
SSLCertificateKeyFile {{ httpd_configuration.get('key') }}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLRandomSeed startup /dev/urandom 256
SSLRandomSeed connect builtin
SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite RC4-SHA:HIGH:!ADH
</IfDefine>
SSLEngine On
ScriptSock {{ httpd_configuration.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}>
SSLVerifyDepth 1
SSLRequireSSL
SSLOptions +StrictRequire
# XXX: security????
Options +ExecCGI
AddHandler cgi-script .cgi
DirectoryIndex {{ monitor_parameters.get('index-filename') }}
</Directory>
Alias /private/ {{ directory.get('private-directory') }}/
<Directory {{ directory.get('private-directory') }}>
Order Deny,Allow
Deny from env=AUTHREQUIRED
<Files ".??*">
Order Allow,Deny
Deny from all
</Files>
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ monitor_parameters.get('htaccess-file') }}"
Require valid-user
Options Indexes FollowSymLinks
Satisfy all
</Directory>
<Location /rewrite>
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ monitor_parameters.get('htaccess-file') }}"
Require valid-user
</Location>
ProxyVia On
RewriteEngine On
{% for key, value in monitor_rewrite_rule.iteritems() %}
RewriteRule ^/rewrite/{{ key }}($|/.*) {{ value }}/$1 [P,L]
{% endfor %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="monitor.css" />
<script src="monitor.js"></script>
</head>
<body>
<noscript>Please enable javascript on your browser to make this application to work.</noscript>
</body>
</html>
......@@ -115,14 +115,18 @@ wrapper = ${directory:services}/monitor-httpd
[monitor-conf-parameters]
title = ${monitor-instance-parameter:monitor-title}
service-executable-dir = ${monitor-directory:run}
template-service-run = {{ monitor_service_run }}
public-folder = ${monitor-directory:public}
private-folder = ${monitor-directory:private}
web-folder = ${monitor-directory:web-dir}
monitor-hal-json = ${monitor-directory:web-dir}/monitor.haljson
service-pid-folder = ${monitor-directory:pids}
crond-folder = ${logrotate-directory:cron-entries}
wraper-folder = ${monitor-directory:promise-wrapper}
promise-runner = {{ promise_executor_py }}
promise-folder-list =
${directory:promises}
${directory:monitor-promise}
public-path-list =
${directory:log}
private-path-list =
......@@ -136,6 +140,19 @@ rendered = ${directory:etc}/${:filename}
filename = monitor.conf
context = section parameter_dict monitor-conf-parameters
[python-symlink]
recipe = plone.recipe.command
target = ${directory:bin}
command = ln -sf {{ python_executable }} ${:target}/python
update-command = ${:command}
[start-monitor]
recipe = slapos.cookbook:wrapper
command-line = {{ python_executable }} {{ monitor_bin }} --config_file ${monitor-conf:rendered}
wrapper-path = ${directory:scripts}/bootstrap-monitor
environment =
PATH=${python-symlink:target}:/usr/local/bin:/usr/bin:/bin
[httpd-monitor-htpasswd]
recipe = plone.recipe.command
stop-on-error = true
......@@ -195,30 +212,11 @@ name = monitor-status2rss
frequency = * * * * *
command = ${monitor-status2rss-wrapper:wrapper-path}
[monitor-web-default-promise-interface]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_default_promise_interface }}
rendered = ${monitor-directory:web-dir}/default-promise-interface.html
context =
[monitor-web-index-html]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_index_html }}
rendered = ${monitor-directory:web-dir}/index.html
context =
[monitor-web-monitor-css]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_css }}
rendered = ${monitor-directory:web-dir}/monitor.css
context =
[monitor-web-directory]
recipe = plone.recipe.command
command = cp -f {{ monitor_web_directory }}/* ${monitor-directory:web-dir}
update-command = ${:command}
[monitor-web-monitor-js]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_js }}
rendered = ${monitor-directory:web-dir}/monitor.js
context =
key monitor_title monitor-instance-parameter:monitor-title
[monitor-web-monitor-logout-cgi]
recipe = slapos.recipe.template:jinja2
......@@ -227,12 +225,6 @@ rendered = ${monitor-directory:cgi-bin}/monitor-logout.cgi
mode = 0755
context =
[monitor-web-monitor-logout-page]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_logout_page }}
rendered = ${monitor-directory:web-dir}/logout
context =
[monitor-web-monitor-promise-runner-cgi]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_promise_runner_cgi }}
......@@ -242,28 +234,6 @@ context =
raw python_executable {{ python_executable }}
key promise_wrapper_folder monitor-directory:promise-wrapper
[start-monitor]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_bin }}
rendered = ${directory:scripts}/bootstrap-monitor
context =
raw python_executable {{ python_executable }}
key public_folder monitor-directory:public
key private_folder monitor-directory:private
key monitor_configuration_path monitor-conf:rendered
key promise_runner_path monitor-run-promise:rendered
key promise_folder directory:promises
key monitor_promise_folder directory:monitor-promise
key promise_wrapper_folder monitor-directory:promise-wrapper
[monitor-run-promise]
recipe = slapos.recipe.template:jinja2
template = {{ promise_executor_py }}
rendered = ${directory:bin}/monitor-run-promise
mode = 700
context =
raw python_executable {{ python_executable }}
[monitor-httpd-promise]
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/${:filename}
......@@ -337,12 +307,8 @@ monitor-title = Monitoring interface
[buildout]
parts =
monitor-web-default-promise-interface
monitor-web-index-html
monitor-web-monitor-css
monitor-web-monitor-js
monitor-web-directory
monitor-web-monitor-logout-cgi
monitor-web-monitor-logout-page
monitor-web-monitor-promise-runner-cgi
cron-entry-logrotate
certificate-authority
......
......@@ -34,4 +34,8 @@ def main():
pidfile.write(str(process.pid))
if __name__ == "__main__":
if len(sys.argv) == 1:
print "Use: %s Monitor_Config_File"
sys.exit(1)
sys.exit(main())
\ No newline at end of file
[slap-parameters]
recipe = slapos.cookbook:slapconfiguration
computer = $${slap-connection:computer-id}
partition = $${slap-connection:partition-id}
url = $${slap-connection:server-url}
key = $${slap-connection:key-file}
cert = $${slap-connection:cert-file}
[monitor-parameters]
json-filename = monitor.json
json-path = $${monitor-directory:monitor-result}/$${:json-filename}
rss-filename = rssfeed.html
rss-path = $${monitor-directory:public-cgi}/$${:rss-filename}
executable = $${monitor-directory:bin}/monitor.py
port = 9685
htaccess-file = $${monitor-directory:etc}/.htaccess-monitor
url = https://[$${slap-parameters:ipv6-random}]:$${:port}
index-filename = index.cgi
index-path = $${monitor-directory:www}/$${:index-filename}
db-path = $${monitor-directory:etc}/monitor.db
monitor-password-path = $${monitor-directory:etc}/.monitor.shadow
[monitor-directory]
recipe = slapos.cookbook:mkdirectory
# Standard directory needed by monitoring stack
home = $${buildout:directory}
etc = $${:home}/etc
bin = $${:home}/bin
srv = $${:home}/srv
var = $${:home}/var
log = $${:var}/log
run = $${:var}/run
service = $${:etc}/service/
etc-run = $${:etc}/run/
tmp = $${:home}/tmp
promise = $${:etc}/promise
cron-entries = $${:etc}/cron.d
crontabs = $${:etc}/crontabs
cronstamps = $${:etc}/cronstamps
ca-dir = $${:srv}/ssl
www = $${:var}/www
cgi-bin = $${:var}/cgi-bin
monitoring-cgi = $${:cgi-bin}/monitoring
knowledge0-cgi = $${:cgi-bin}/zero-knowledge
public-cgi = $${:cgi-bin}/monitor-public
monitor-custom-scripts = $${:etc}/monitor
monitor-result = $${:var}/monitor
private-directory = $${:srv}/monitor-private
[public-symlink]
recipe = cns.recipe.symlink
symlink = $${monitor-directory:public-cgi} = $${monitor-directory:www}/monitor-public
autocreate = true
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${monitor-directory:cron-entries}
crontabs = $${monitor-directory:crontabs}
cronstamps = $${monitor-directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${monitor-directory:service}/crond
# Add log to cron
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${monitor-directory:bin}/cron_simplelogger
log = $${monitor-directory:log}/cron.log
[cron-entry-monitor]
<= cron
recipe = slapos.cookbook:cron.d
name = launch-monitor
frequency = */5 * * * *
command = $${deploy-monitor-script:rendered} -a
[cron-entry-rss]
<= cron
recipe = slapos.cookbook:cron.d
name = build-rss
frequency = */5 * * * *
command = $${make-rss:rendered}
[setup-static-files]
recipe = plone.recipe.command
command = ln -s ${download-monitor-jquery:destination} $${monitor-directory:www}/static
update-command = $${:command}
[deploy-index]
recipe = slapos.recipe.template:jinja2
template = ${index:location}/${index:filename}
rendered = $${monitor-parameters:index-path}
update-apache-access = ${apache:location}/bin/htpasswd -cb $${monitor-parameters:htaccess-file} admin
mode = 0744
context =
key cgi_directory monitor-directory:cgi-bin
raw index_template $${deploy-index-template:location}/$${deploy-index-template:filename}
key monitor_password_path monitor-parameters:monitor-password-path
key monitor_password_script_path deploy-monitor-password-cgi:rendered
key apache_update_command :update-apache-access
raw extra_eggs_interpreter ${buildout:directory}/bin/${extra-eggs:interpreter}
raw default_page /static/welcome.html
section rewrite_element monitor-rewrite-rule
[deploy-index-template]
recipe = hexagonit.recipe.download
url = ${index-template:location}/$${:filename}
destination = $${monitor-directory:www}
filename = ${index-template:filename}
download-only = true
mode = 0644
[deploy-status-cgi]
recipe = slapos.recipe.template:jinja2
template = ${status-cgi:location}/${status-cgi:filename}
rendered = $${monitor-directory:monitoring-cgi}/$${:filename}
filename = status.cgi
mode = 0744
context =
key json_file monitor-parameters:json-path
key monitor_bin monitor-parameters:executable
key pwd monitor-directory:monitoring-cgi
key this_file :filename
raw python_executable ${buildout:executable}
[deploy-status-history-cgi]
recipe = slapos.recipe.template:jinja2
template = ${status-history-cgi:location}/${status-history-cgi:filename}
rendered = $${monitor-directory:monitoring-cgi}/$${:filename}
filename = status-history.cgi
mode = 0744
context =
key monitor_db_path monitor-parameters:db-path
key status_history_length zero-parameters:status-history-length
raw python_executable ${buildout:executable}
[deploy-settings-cgi]
recipe = slapos.recipe.template:jinja2
template = ${settings-cgi:location}/${settings-cgi:filename}
rendered = $${monitor-directory:knowledge0-cgi}/$${:filename}
filename = settings.cgi
mode = 0744
context =
raw config_cfg $${buildout:directory}/knowledge0.cfg
raw timestamp $${buildout:directory}/.timestamp
raw python_executable ${buildout:executable}
key pwd monitor-directory:knowledge0-cgi
key this_file :filename
[deploy-monitor-password-cgi]
recipe = slapos.recipe.template:jinja2
template = ${monitor-password-cgi:location}/${monitor-password-cgi:filename}
rendered = $${monitor-directory:knowledge0-cgi}/$${:filename}
filename = monitor-password.cgi
mode = 0744
context =
raw python_executable ${buildout:executable}
key pwd monitor-directory:knowledge0-cgi
key this_file :filename
[deploy-monitor-script]
recipe = slapos.recipe.template:jinja2
template = ${monitor-bin:location}/${monitor-bin:filename}
rendered = $${monitor-parameters:executable}
mode = 0744
context =
section directory monitor-directory
section monitor_parameter monitor-parameters
key monitoring_file_json monitor-parameters:json-path
raw python_executable ${buildout:executable}
[make-rss]
recipe = slapos.recipe.template:jinja2
template = ${make-rss-script:output}
rendered = $${monitor-directory:bin}/make-rss.sh
mode = 0744
context =
section directory monitor-directory
section monitor_parameters monitor-parameters
[monitor-directory-access]
recipe = plone.recipe.command
command = ln -s $${:source} $${monitor-directory:private-directory}
source =
[monitor-instance-log-access]
recipe = plone.recipe.command
command = if [ -d $${:source} ]; then ln -s $${:source} $${monitor-directory:private-directory}/instance-logs; fi
update-command = if [ -d $${:source} ]; then ln -s $${:source} $${monitor-directory:private-directory}/instance-logs; fi
source = $${monitor-directory:home}/.slapgrid/log/
location = $${:source}
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${monitor-directory:ca-dir}/requests/
private = $${monitor-directory:ca-dir}/private/
certs = $${monitor-directory:ca-dir}/certs/
newcerts = $${monitor-directory:ca-dir}/newcerts/
crl = $${monitor-directory:ca-dir}/crl/
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${monitor-directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${monitor-directory:service}/certificate_authority
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[ca-httpd]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = $${cadirectory:certs}/httpd.key
cert-file = $${cadirectory:certs}/httpd.crt
executable = $${monitor-directory:bin}/cgi-httpd
wrapper = $${monitor-directory:service}/cgi-httpd
# Put domain name
name = example.com
###########
# Deploy a webserver running cgi scripts for monitoring
###########
[public]
recipe = slapos.cookbook:zero-knowledge.write
filename = knowledge0.cfg
status-history-length = 5
[zero-parameters]
recipe = slapos.cookbook:zero-knowledge.read
filename = $${public:filename}
[monitor-rewrite-rule]
# XXX could it be something lighter?
[monitor-httpd-configuration]
pid-file = $${monitor-directory:run}/cgi-httpd.pid
cgid-pid-file = $${monitor-directory:run}/cgi-httpd-cgid.pid
error-log = $${monitor-directory:log}/cgi-httpd-error-log
listening-ip = $${slap-parameters:ipv6-random}
certificate = $${ca-httpd:cert-file}
key = $${ca-httpd:key-file}
[monitor-httpd-configuration-file]
recipe = slapos.recipe.template:jinja2
template = ${monitor-httpd-template:destination}/${monitor-httpd-template:filename}
rendered = $${monitor-directory:etc}/cgi-httpd.conf
mode = 0744
context =
section directory monitor-directory
section monitor_parameters monitor-parameters
section httpd_configuration monitor-httpd-configuration
section monitor_rewrite_rule monitor-rewrite-rule
[cgi-httpd-wrapper]
recipe = slapos.cookbook:wrapper
apache-executable = ${apache:location}/bin/httpd
command-line = $${:apache-executable} -f $${monitor-httpd-configuration-file:rendered} -DFOREGROUND
wrapper-path = $${ca-httpd:executable}
wait-for-files =
$${cadirectory:certs}/httpd.key
$${cadirectory:certs}/httpd.crt
[cgi-httpd-graceful-wrapper]
recipe = slapos.recipe.template:jinja2
template = ${template-wrapper:output}
rendered = $${monitor-directory:etc-run}/cgi-httpd-graceful
mode = 0700
context =
key content :command
command = kill -USR1 $(cat $${monitor-httpd-configuration:pid-file})
[monitor-promise]
recipe = slapos.cookbook:check_url_available
path = $${monitor-directory:promise}/monitor
url = $${monitor-parameters:url}/$${monitor-parameters:index-filename}
check-secure = 1
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[publish-connection-informations]
recipe = slapos.cookbook:publish
monitor_url = $${monitor-parameters:url}
#!{{ python_executable }}
# Put this file in the software release
promise_runner_path = "{{ promise_runner_path }}"
public_folder = "{{ public_folder }}"
private_folder = "{{ private_folder }}"
monitor_configuration_path = "{{ monitor_configuration_path }}"
promise_folder = "{{ promise_folder }}"
monitor_promise_folder = "{{ monitor_promise_folder }}"
promise_wrapper_folder = "{{ promise_wrapper_folder }}"
import sys
import os
import stat
import subprocess
import threading
import json
import ConfigParser
import traceback
def main():
# initialisation
config = loadConfig([monitor_configuration_path])
# get promises in monitor_promise_folder
promise_dict = {}
fillPromiseDictFromFolder(promise_dict, monitor_promise_folder)
# get promises in promise_folder
fillPromiseDictFromFolder(promise_dict, promise_folder)
# get promises configurations
for filename in os.listdir(monitor_promise_folder):
path = os.path.join(monitor_promise_folder, filename)
if os.path.isfile(path) and filename[-4:] == ".cfg":
promise_name = filename[:-4]
if promise_name in promise_dict:
loadConfig([path], promise_dict[promise_name]["configuration"])
promise_items = promise_dict.items()
# create symlinks from service configurations
for service_name, promise in promise_items:
service_config = promise["configuration"]
createSymlinksFromConfig((config, "monitor", "public-folder"), (service_config, "service", "public-path-list"), service_name)
createSymlinksFromConfig((config, "monitor", "private-folder"), (service_config, "service", "private-path-list"), service_name)
# create symlinks from monitor.conf
createSymlinksFromConfig((config, "monitor", "public-folder"), (config, "monitor", "public-path-list"))
createSymlinksFromConfig((config, "monitor", "private-folder"), (config, "monitor", "private-path-list"))
# generate monitor.json
monitor_dict = {}
tmp = softConfigGet(config, "monitor", "title")
if tmp:
monitor_dict["title"] = tmp
tmp = softConfigGet(config, "monitor", "monitor-url-list")
if tmp:
monitor_dict["_links"] = {"related_monitor": [{"href": url} for url in tmp.split()]}
if promise_items:
service_list = []
monitor_dict["_embedded"] = {"service": service_list}
for service_name, promise in promise_items:
service_config = promise["configuration"]
service_dict = {}
service_list.append(service_dict)
service_dict["id"] = service_name
service_dict["_links"] = {"status": {"href": "/public/%s.status.json" % service_name}} # hardcoded
tmp = softConfigGet(service_config, "service", "title")
if tmp:
service_dict["title"] = tmp
interface_path = os.path.join(private_folder, service_name, "interface/index.html") # hardcoded
if os.path.isfile(interface_path):
service_dict["_links"]["interface"] = {"href": "/private/%s/interface/" % service_name} # hardcoded
else:
service_dict["_links"]["interface"] = {"href": "/default-promise-interface.html?service_name=%s" % service_name} # XXX hardcoded
with open(config.get("monitor", "monitor-hal-json"), "w") as fp:
json.dump(monitor_dict, fp)
# put promises to a cron file
# XXX only if at least one configuration file is modified, then write in the cron
service_pid_folder = config.get("monitor", "service-pid-folder")
crond_folder = config.get("monitor", "crond-folder")
cron_line_list = []
for service_name, promise in promise_items:
service_status_path = "%s/%s.status.json" % (public_folder, service_name) # hardcoded
mkdirAll(os.path.dirname(service_status_path))
command = ("%s %s %s " % (
promise_runner_path,
os.path.join(service_pid_folder, "%s.pid" % service_name),
service_status_path,
)) + promise["path"]
cron_line_list.append("%s %s" % (
softConfigGet(service_config, "service", "frequency") or "* * * * *",
command.replace("%", "\\%"),
))
wrapper_path = os.path.join(promise_wrapper_folder, service_name)
with open(wrapper_path, "w") as fp:
fp.write("#!/bin/sh\n%s" % command) # XXX hardcoded, use dash, sh or bash binary!
os.chmod(wrapper_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IROTH )
with open(crond_folder + "/monitor-promises", "w") as fp:
fp.write("\n".join(cron_line_list))
return 0
def loadConfig(pathes, config=None):
if config is None:
config = ConfigParser.ConfigParser()
try:
config.read(pathes)
except ConfigParser.MissingSectionHeaderError:
traceback.print_exc()
return config
def fillPromiseDictFromFolder(promise_dict, folder):
for filename in os.listdir(folder):
path = os.path.join(folder, filename)
if os.path.isfile(path) and os.access(path, os.X_OK):
promise_dict[filename] = {"path": path, "configuration": ConfigParser.ConfigParser()}
def softConfigGet(config, *args, **kwargs):
try:
return config.get(*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
return None
def createSymlinksFromConfig(destination_folder_config_tuple, source_list_config_tuple, service_name=""):
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():
dirname = os.path.join(destination_folder, service_name)
try:
mkdirAll(dirname) # could also raise OSError
os.symlink(path, os.path.join(dirname, os.path.basename(path)))
except OSError, e:
if e.errno != os.errno.EEXIST:
raise
def mkdirAll(path):
try:
os.makedirs(path)
except OSError, e:
if e.errno == os.errno.EEXIST and os.path.isdir(path):
pass
else: raise
if __name__ == "__main__":
sys.exit(main())
#!{{ python_executable }}
#!/usr/bin/env python
password_changed_once_path = "{{ password_changed_once_path }}"
import os
......
#!/usr/bin/env python
import sys
import os
import stat
import subprocess
import threading
import json
import ConfigParser
import traceback
import argparse
def parseArguments():
"""
Parse arguments for monitor instance.
"""
parser = argparse.ArgumentParser()
parser.add_argument('--config_file',
default='monitor.cfg',
help='Monitor Configuration file')
parser.add_argument('--promise-folder',
action='append', dest='promise_folder_list',
default=[],
help='The path to get promise executable files')
parser.add_argument('--public-folder',
action='append', dest='public_folder',
help='The path of public folder. All files in this folders will have public acess')
parser.add_argument('--private-folder',
action='append', dest='private_folder',
help='The path of private folder. All files in this folders will be accessible with password')
parser.add_argument('--promise-runner',
help='The path of promise runner, use to run promise files')
parser.add_argument('--wrapper-path',
help='Path of monitor generated promise scripts files.')
return parser.parse_args()
def mkdirAll(path):
try:
os.makedirs(path)
except OSError, e:
if e.errno == os.errno.EEXIST and os.path.isdir(path):
pass
else: raise
def softConfigGet(config, *args, **kwargs):
try:
return config.get(*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
return None
class Monitoring(object):
def __init__(self, configuration_file):
config = self.loadConfig([configuration_file])
# Set Monitor variables
self.monitor_hal_json = config.get("monitor", "monitor-hal-json")
self.title = config.get("monitor", "title")
self.service_pid_folder = config.get("monitor", "service-pid-folder")
self.crond_folder = config.get("monitor", "crond-folder")
self.wraper_folder = config.get("monitor", "wraper-folder")
self.promise_runner = config.get("monitor", "promise-runner")
self.promise_folder_list = config.get("monitor", "promise-folder-list").split()
self.public_folder = config.get("monitor", "public-folder")
self.private_folder = config.get("monitor", "private-folder")
self.public_path_list = config.get("monitor", "public-path-list").split()
self.private_path_list = config.get("monitor", "private-path-list").split()
self.monitor_url_list = config.get("monitor", "monitor-url-list").split()
self.promise_dict = {}
for promise_folder in self.promise_folder_list:
self.setupPromiseDictFromFolder(promise_folder)
def loadConfig(self, pathes, config=None):
if config is None:
config = ConfigParser.ConfigParser()
try:
config.read(pathes)
except ConfigParser.MissingSectionHeaderError:
traceback.print_exc()
return config
def setupPromiseDictFromFolder(self, folder):
for filename in os.listdir(folder):
path = os.path.join(folder, filename)
if os.path.isfile(path) and os.access(path, os.X_OK):
self.promise_dict[filename] = {"path": path,
"configuration": ConfigParser.ConfigParser()}
# get promises configurations
#for filename in os.listdir(monitor_promise_folder):
# path = os.path.join(monitor_promise_folder, filename)
# if os.path.isfile(path) and filename[-4:] == ".cfg":
# promise_name = filename[:-4]
# if promise_name in promise_dict:
# loadConfig([path], promise_dict[promise_name]["configuration"])
def createSymlinksFromConfig(self, destination_folder, source_path_list, service_name=""):
if destination_folder:
if source_path_list:
for path in source_path_list:
dirname = os.path.join(destination_folder, service_name)
try:
mkdirAll(dirname) # could also raise OSError
os.symlink(path, os.path.join(dirname, os.path.basename(path)))
except OSError, e:
if e.errno != os.errno.EEXIST:
raise
def generateMonitorHalJson(self):
if self.title:
self.monitor_dict["title"] = self.title
if self.monitor_url_list:
self.monitor_dict["_links"] = {"related_monitor": [{"href": url}
for url in self.monitor_url_list]}
if self.promise_items:
service_list = []
for service_name, promise in self.promise_items:
service_config = promise["configuration"]
service_dict = {}
service_dict["id"] = service_name
service_dict["_links"] = {"status": {"href": "/public/%s.status.json" % service_name}} # hardcoded
tmp = softConfigGet(service_config, "service", "title")
if tmp:
service_dict["title"] = tmp
interface_path = os.path.join(self.private_folder, service_name, "interface/index.html") # hardcoded
if os.path.isfile(interface_path):
service_dict["_links"]["interface"] = {"href": "/private/%s/interface/" % service_name} # hardcoded
else:
service_dict["_links"]["interface"] = {"href": "/default-promise-interface.html?service_name=%s" % service_name} # XXX hardcoded
service_list.append(service_dict)
self.monitor_dict["_embedded"] = {"service": service_list}
with open(self.monitor_hal_json, "w") as fp:
json.dump(self.monitor_dict, fp)
def generateServiceCronEntries(self):
# XXX only if at least one configuration file is modified, then write in the cron
cron_line_list = []
for service_name, promise in self.promise_items:
service_config = promise["configuration"]
service_status_path = "%s/%s.status.json" % (self.public_folder, service_name) # hardcoded
mkdirAll(os.path.dirname(service_status_path))
command = ("%s %s %s " % (
self.promise_runner,
os.path.join(self.service_pid_folder, "%s.pid" % service_name),
service_status_path,)
) + promise["path"]
cron_line_list.append("%s %s" % (
softConfigGet(service_config, "service", "frequency") or "* * * * *",
command.replace("%", "\\%"),
))
wrapper_path = os.path.join(self.wraper_folder, service_name)
with open(wrapper_path, "w") as fp:
fp.write("#!/bin/sh\n%s" % command) # XXX hardcoded, use dash, sh or bash binary!
os.chmod(wrapper_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IROTH )
with open(self.crond_folder + "/monitor-promises", "w") as fp:
fp.write("\n".join(cron_line_list))
def bootstrapMonitor(self):
# create symlinks from service configurations
self.promise_items = self.promise_dict.items()
for service_name, promise in self.promise_items:
service_config = promise["configuration"]
public_path_list = softConfigGet(service_config, "service", "public-path-list")
private_path_list = softConfigGet(service_config, "service", "private-path-list")
if public_path_list:
self.createSymlinksFromConfig(self.public_folder,
public_path_list.split(),
service_name)
if private_path_list:
self.createSymlinksFromConfig(self.private_folder,
private_path_list.split(),
service_name)
# create symlinks from monitor.conf
self.createSymlinksFromConfig(self.public_folder, self.public_path_list)
self.createSymlinksFromConfig(self.private_folder, self.private_path_list)
# generate monitor.json
self.monitor_dict = {}
self.generateMonitorHalJson()
# put promises to a cron file
self.generateServiceCronEntries()
return 0
if __name__ == "__main__":
parser = parseArguments()
monitor = Monitoring(parser.config_file)
sys.exit(monitor.bootstrapMonitor())
#!{{ python_executable }}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import subprocess
import json
from cStringIO import StringIO
def main():
if len(sys.argv) < 4:
......
......@@ -30,6 +30,7 @@ LoadModule authn_file_module modules/mod_authn_file.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
# SSL Configuration
<IfDefine !SSLConfigured>
......@@ -47,6 +48,24 @@ SSLCipherSuite RC4-SHA:HIGH:!ADH
AddType application/hal+json .haljson
SSLEngine On
{% if parameter_dict.has_key('monitor-url-list') -%}
RewriteEngine on
SSLProxyEngine on
ProxyPreserveHost On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
{% set index=1 -%}
{% set monitor_url_list = parameter_dict.get('monitor-url-list').split('\n') -%}
{% for url in monitor_url_list -%}
{% if url.strip() -%}
RewriteRule /monitor{{ index }}/(.*) {{ url }}/$1 [L,P]
{% set index = index + 1 -%}
{% endif -%}
{% endfor -%}
{% endif -%}
ScriptSock {{ parameter_dict.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}>
SSLVerifyDepth 1
......@@ -55,6 +74,7 @@ ScriptSock {{ parameter_dict.get('cgid-pid-file') }}
# XXX: security????
DirectoryIndex index.html
Options FollowSymLinks
AllowOverride All
Order Deny,Allow
AuthType Basic
AuthName "Private access"
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<link rel="stylesheet" href="monitor.css" />
<script src="monitor.js"></script>
</head>
<body>
<noscript>Please enable javascript on your browser to make this application to work.</noscript>
</body>
</html>
......@@ -48,3 +48,10 @@ a.as-button:active, button:active {
a.as-button:hover, button:hover {
border-color: #777777;
}
.monitor-section {
float: left;
table-layout: fixed;
margin-top: 30px;
margin-right: 30px;
}
\ No newline at end of file
/*jslint indent: 2 */
/*jslint indent:2 */
(function () {
"use strict";
var monitor_title = '{{ dumps(monitor_title)[5:-1] }}',
var monitor_title = 'Monitoring interface',
RSS_ICON_DATA_URI = [
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwhRE9DVFlQR",
"SBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cu",
......@@ -25,7 +25,8 @@
var response = event.target;
if (response.status < 400) {
try {
resolve(JSON.parse(response.responseText));
var data = ( response.responseType === 'text' || response.responseType === '') ? JSON.parse(response.responseText) : response.response;
resolve(data);
} catch (e) {
reject(e);
}
......@@ -95,6 +96,16 @@
return url.href;
}
function joinUrl(url, path) {
if (path && path[0] === '/') {
path = path.slice(1);
}
if (url.indexOf('/', url.length - 1) === -1) {
return url + '/' + path;
}
return url + escapeHtml(path);
}
function escapeHtml(html) {
return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
}
......@@ -106,6 +117,7 @@
return;
}
table = document.createElement("table");
table.className = "monitor-section";
root.appendChild(table);
return Promise.all(service_list.map(function (service_dict) {
var interface_url = softGetProperty(service_dict, ["_links", "interface", "href"]),
......@@ -118,7 +130,8 @@
row[5].textContent = "No status";
return;
}
return loadJson(resolveUrl(monitor_url, status_url)).then(function (status_dict) {
var full_status_url = (monitor_url === undefined) ? resolveUrl(monitor_url, status_url): joinUrl(monitor_url, status_url);
return loadJson(full_status_url).then(function (status_dict) {
if (status_dict.description) {
row[2].title = status_dict.description;
}
......@@ -144,8 +157,8 @@
if (link.href[link.href.length - 1] !== "/") {
link.href += "/";
}
link.href = resolveUrl(link.href, "monitor.haljson");
return loadJson(link.href).catch(function (reason) {
var haljson_link = resolveUrl(link.href, "monitor.haljson");
return loadJson(haljson_link).catch(function (reason) {
div.textContent = (reason && (reason.name + ": " + reason.message));
}).then(function (monitor_dict) {
//monitor_json_list.push(monitor_dict);
......@@ -160,7 +173,7 @@
var element_list = htmlToElementList([
"<header>",
" <a href=\"\" class=\"as-button\">Refresh</a>",
" <a href=\"/logout\" class=\"as-button\">Logout</a>",
" <a href=\"/logout.html\" class=\"as-button\">Logout</a>",
" <a href=\"/feed\"><img src=\"" + RSS_ICON_DATA_URI + "\" style=\"width: 10mm; height: 10mm; vertical-align: middle;\" alt=\"[RSS Feed]\" /></a>",
"</header>",
"<h1>" + monitor_title + "</h1>",
......
#!{{ extra_eggs_interpreter }}
import cgi
import cgitb
import Cookie
import base64
import hashlib
import hmac
import jinja2
import os
import subprocess
import urllib
cgitb.enable(display=0, logdir="/tmp/cgi.log")
form = cgi.FieldStorage()
cookie = Cookie.SimpleCookie()
cgi_path = "{{ cgi_directory }}"
monitor_password_path = "{{ monitor_password_path }}"
monitor_password_script_path = "{{ monitor_password_script_path }}"
monitor_apache_password_command = "{{ apache_update_command }}"
monitor_rewrite = "{{ ' '.join(rewrite_element.keys()) }}"
########
# Password functions
#######
def crypt(word, salt="$$"):
salt = salt.split("$")
algo = salt[0] or 'sha1'
if algo in hashlib.algorithms:
H = getattr(hashlib, algo)
elif algo == "plain":
return "%s$%s" % (algo, word)
else:
raise ValueError
rounds = min(max(0, int(salt[1])), 30) if salt[1] else 9
salt = salt[2] or base64.b64encode(os.urandom(12), "./")
h = hmac.new(salt, word, H).digest()
for x in xrange(1, 1 << rounds):
h = H(h).digest()
return "%s$%s$%s$%s" % (algo, rounds, salt,
base64.b64encode(h, "./").rstrip("="))
def is_password_set():
if not os.path.exists(monitor_password_path):
return False
hashed_password = open(monitor_password_path, 'r').read()
try:
void, algo, salt, hsh = hashed_password.split('$')
except ValueError:
return False
return True
def set_password(raw_password):
hashed_password = crypt(raw_password)
subprocess.check_call(monitor_apache_password_command + " %s" % raw_password,
shell=True)
open(monitor_password_path, 'w').write(hashed_password)
def check_password(raw_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
encryption formats behind the scenes.
"""
if not os.path.exists(monitor_password_path) or not raw_password:
return False
hashed_password = open(monitor_password_path, 'r').read()
return hashed_password == crypt(raw_password, hashed_password)
### End of password functions
def forward_form():
command = os.path.join(cgi_path, form['posting-script'].value)
params_dict = {}
for f in form:
params_dict[f] = form[f].value
del params_dict['posting-script']
os.environ['QUERY_STRING'] = urllib.urlencode(params_dict)
try:
if os.access(command, os.X_OK):
print '\n', subprocess.check_output([command])
except subprocess.CalledProcessError:
print "There is a problem with sub-process"
pass
def return_document(command=None):
if not command:
script = form['script'].value
command = os.path.join(cgi_path, script)
#XXX this functions should be called only for display,
#so a priori it doesn't need form data
os.environ['QUERY_STRING'] = ''
try:
if os.access(command, os.X_OK):
print '\n', subprocess.check_output([command])
elif os.access(command, os.R_OK):
print open(command).read()
else:
raise OSError
except (subprocess.CalledProcessError, OSError) as e:
print "<p>Error :</p><pre>%s</pre>" % e
def make_menu():
# Transform deep-2 tree in json
folder_list = {}
for folder in os.listdir(cgi_path):
if os.path.isdir(os.path.join(cgi_path, folder)):
folder_list[folder] = []
for folder in folder_list:
for file in os.listdir(os.path.join(cgi_path, folder)):
if os.path.isfile(os.path.join(cgi_path, folder, file)):
folder_list[folder].append(file)
return folder_list
def get_cookie_password():
cookie_string = os.environ.get('HTTP_COOKIE')
if cookie_string:
cookie.load(cookie_string)
try:
return cookie['password'].value
except KeyError:
pass
return None
def set_cookie_password(password):
cookie['password'] = password
print cookie, "; Path=/; HttpOnly"
# Beginning of response
print "Content-Type: text/html"
password = None
# Check if user is logged
if "password_2" in form and "password" in form:
password_2 = form['password_2'].value
password_1 = form['password'].value
password = get_cookie_password()
if not is_password_set() or check_password(password):
if password_2 == password_1:
password = password_1
set_password(password)
set_cookie_password(password)
elif "password" in form:
password = form['password'].value
if is_password_set() and check_password(password):
set_cookie_password(password)
else:
password = get_cookie_password()
print '\n'
if not is_password_set():
return_document(monitor_password_script_path)
elif not check_password(password):
print "<html><head>"
print """
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">"""
print "</head><body>"
if password is None:
print "<h1>This is the monitoring interface</h1>"
else:
print "<h1>Error</h1><p>Wrong password</p>"
print """
<p>Please enter the monitor_password in the next field to access the data</p>
<form action="/index.cgi" method="post" class="pure-form-aligned">
Password : <input type="password" name="password">
<button type="submit" class="pure-button pure-button-primary">Access</button>
</form>
</body></html>"""
# redirection to the required script/page
else:
print
if "posting-script" in form:
forward_form()
elif "script" in form:
return_document()
else:
html_base = jinja2.Template(open('{{ index_template }}').read())
print
print html_base.render(tree=make_menu(), default_page="{{ default_page }}", monitor_rewrite=monitor_rewrite)
<html>
<head>
<title>Monitoring Interface</title>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">
<script src="static/jquery-1.10.2.min.js"></script>
<script src="static/script.js"></script>
</head>
<body>
<div id="div-menu">
<h1>Monitoring</h1>
<div id="script-categories" class="pure-menu pure-menu-open">
<ul>
{% for category in tree %}
<li class="pure-menu-heading category">{{ category }}</li>
{% for script in tree[category] %}
<li><a href="{{ category }}/{{ script }}" class="script">{{ script }}</a></li>
{% endfor %}
{% endfor %}
<li class="pure-menu-heading category">Files</li>
<li><a href="./private/" class="link"> User: admin</br> Password is yours</a></li>
<li class="pure-menu-heading category">Local Service</li>
{% set rewrite_list = monitor_rewrite.split() %}
{% for path in rewrite_list %}
<li><a href="./rewrite/{{path}}/" class="link">{{path}}</a></li>
{% endfor %}
</ul>
</div>
</div>
<div id="content">
<iframe src="{{ default_page }}">
</iframe>
</div>
</body>
</html>
#!{{ python_executable }}
import cgitb
cgitb.enable()
print "<html><head>"
print """
<script type="text/javascript" src="static/jquery-1.10.2.min.js"></script>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">"""
print "</head><body>"
print "<h1>This is the monitoring interface</h1>"
print "<h2>Please set your password for later access</h2>"
print """
<form action="/index.cgi" method="post" class="pure-form-aligned">
<div class="pure-control-group">
<label for="password">Password*:</label>
<input placeholder="Set your password" type="password" name="password" id="password"></br>
</div><div class="pure-control-group">
<label for="password">Verify Password*:</label>
<input placeholder="Verify password" type="password" name="password_2" id="password_2"></br>
</div><p id="validate-status" style="color:red"></p>
<div class="pure-controls">
<button id="register-button" type="submit" class="pure-button pure-button-primary" disabled>Access</button></div>
</form>
<script type="text/javascript" src="static/monitor-register.js"></script>
</body></html>
"""
#!{{ python_executable }}
import cgi
import cgitb
import ConfigParser
import os
cgitb.enable()
form = cgi.FieldStorage()
print "<html><head>"
print "<link rel=\"stylesheet\" href=\"static/pure-min.css\">"
print "<link rel=\"stylesheet\" href=\"static/style.css\">"
print "</head><body>"
config_file = "{{ config_cfg }}"
if not os.path.exists(config_file):
print "Your software does <b>not</b> embed 0-knowledge. \
This interface is useless in this case</body></html>"
exit(0)
parser = ConfigParser.ConfigParser()
parser.read(config_file)
if not parser.has_section('public'):
print "<p>Your software does not use 0-knowledge settings.</p></body></html>"
exit(0)
for name in form:
if parser.has_option('public', name):
parser.set('public', name, form[name].value)
with open(config_file, 'w') as file:
parser.write(file)
if len(form) > 0:
try:
os.remove("{{ timestamp }}")
except OSError:
pass
print "<h1>Values that can be defined :</h1>"
print "<form action=\"/index.cgi\" method=\"post\" class=\"pure-form-aligned\">"
print "<input type=\"hidden\" name=\"posting-script\" value=\"{{ pwd }}/{{ this_file }}\">"
for option in parser.options("public"):
print "<div class=\"pure-control-group\">"
print "<label for=\"%s\">%s</label>" % (cgi.escape(option, quote=True), cgi.escape(option))
print "<input type=\"text\" name=\"%s\" value=\"%s\">" % (cgi.escape(option, quote=True), cgi.escape(parser.get('public', option), quote=True))
print "</div>"
print "<div class=\"pure-controls\"><button type=\"submit\" class=\"pure-button \
pure-button-primary\">Save</button></div></form>"
print "<br><h1>Other values :</h1>"
print "<form class=\"pure-form-aligned\">"
for section in parser.sections():
if section != 'public':
for option in parser.options(section):
print "<div class=\"pure-control-group\">"
print "<label for=\"%s\">%s</label>" % (cgi.escape(option, quote=True), cgi.escape(option))
print "<input type=\"text\" name=\"%s\" value=\"%s\" readonly>" %(cgi.escape(option, quote=True), cgi.escape(parser.get(section, option), quote=True))
print "</div>"
print "</form>"
print "</body></html>"
$(window).load(function(){
$(document).ready(function() {
$("#password_2").keyup(validate);
});
function validate() {
var password1 = $("#password").val();
var password2 = $("#password_2").val();
if(password1 == password2) {
$("#register-button").removeAttr("disabled");
$("#validate-status").attr("style", "display:none");
}
else {
$("#register-button").attr("disabled", "disabled");
$("#validate-status").attr("style", "").text("Passwords do not match");
}
}
});
\ No newline at end of file
This diff is collapsed.
$(document).ready(function() {
function doDataUrl (data) {
var frame_content = document.getElementsByTagName("iframe")[0].contentWindow;
var b64 = btoa(data);
dataurl = 'data:text/html;base64,' + b64;
$("iframe").attr('src', dataurl);
}
if ( window.self === window.top ) {
//not in an iframe
$(".script").click(function(e) {
e.preventDefault();
var message = $(this).attr('href');
var slash_pos = message.search('/');
//let's differenciate kind of script called
if ( slash_pos === -1 || slash_pos === 0) {
url = message;
}
else {
url = '/index.cgi';
}
$("iframe").attr('src', url + '?script=' + encodeURIComponent(message));
});
$(".link").click(function(e) {
e.preventDefault();
var url = $(this).attr('href');
$("iframe").attr('src', url);
});
}
else {
//in an iframe
$("body").empty();
}
});
body {
padding: 15px;
}
.pure-menu .pure-menu-heading {
font-size: 120%;
}
#content {
display: inline-block;
min-width: 72%;
height: 97%;
margin-left: 30px;
}
#div-menu {
display: inline-block;
vertical-align: top;
}
#div-menu h1 {
text-align: center;
}
iframe {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
border-style: none;
}
<html>
<head>
<title>Welcome to the Monitoring Interface</title>
<link rel="stylesheet" href="pure-min.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Welcome to your monitoring interface</h1>
<p>From this interface you can monitor, configure your instance</p>
</body>
</html>
#!{{ python_executable }}
import cgi
import datetime
import os
import sqlite3
db_path = '{{ monitor_db_path }}'
status_history_length = '{{ status_history_length }}'
db = sqlite3.connect(db_path)
print """<html><head>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">
</head><body>
<h1>Monitor Status History :</h1>"""
def get_date_from_timestamp(timestamp):
return datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
def print_individual_status(timestamp):
print "<div><h3>Failure on %s</h3><ul>" % get_date_from_timestamp(timestamp)
rows = db.execute("select status, element, output from individual_status where timestamp=?", (timestamp,))
for row in rows:
status, element, output = row
print "<li>%s , %s :</br><pre>%s</pre></li>" % (status, cgi.escape(element), cgi.escape(output))
print "</ul></div>"
if not os.path.exists(db_path):
print """No status history found</p></body></html>"""
exit(0)
failure_row_list = db.execute("select timestamp from status where status='FAILURE' order by timestamp desc limit ?", status_history_length )
for failure_row in failure_row_list:
timestamp, = failure_row
print_individual_status(timestamp)
print "</body></html>"
#!{{ python_executable }}
import cgi
import cgitb
import json
import os
import subprocess
def refresh():
command = ["{{ monitor_bin }}", "-a"]
subprocess.call(command)
cgitb.enable(display=0, logdir="/tmp/cgi.log")
form = cgi.FieldStorage()
json_file = "{{ json_file }}"
if not os.path.exists(json_file) or "refresh" in form:
refresh()
if not os.path.exists(json_file):
print """<html><head>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">
</head><body>
<h1>Monitoring :</h1>
No status file found</p></body></html>"""
exit(0)
result = json.load(open(json_file))
print "<html><head>"
print "<link rel=\"stylesheet\" href=\"static/pure-min.css\">"
print "<link rel=\"stylesheet\" href=\"static/style.css\">"
print "</head><body>"
print "<h1>Monitoring :</h1>"
print "<form action=\"/index.cgi\" method=\"post\" class=\"pure-form-aligned\">"
print "<input type=\"hidden\" name=\"posting-script\" value=\"{{ pwd }}/{{ this_file }}\">"
print "<p><em>Last time of monitoring process : %s</em></p>" % (result['datetime'])
del result['datetime']
print "<div class=\"pure-controls\"><button type=\"submit\" class=\"pure-button \
pure-button-primary\" name=\"refresh\" value=\"refresh\">Refresh</button></div></form>"
print "<br/>"
print "<h2>These scripts and promises have failed :</h2>"
for r in result:
if result[r] != '':
print "<h3>%s</h3><pre style=\"padding-left:30px;\">%s</pre>" % (cgi.escape(r), cgi.escape(result[r]))
print "<br/>"
print "<h2>These scripts and promises were successful :</h2>"
print "<ul>"
for r in result:
if result[r] == '':
print "<li>%s</li>" % (r)
print "</ul>"
print "</body></html>"
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