Commit 60b90929 authored by Tristan Cavelier's avatar Tristan Cavelier

index.cgi +1

parent f9853052
...@@ -46,7 +46,7 @@ recipe = slapos.recipe.template ...@@ -46,7 +46,7 @@ recipe = slapos.recipe.template
url = ${:_profile_base_location_}/monitor.cfg.in url = ${:_profile_base_location_}/monitor.cfg.in
output = ${buildout:directory}/monitor.cfg output = ${buildout:directory}/monitor.cfg
filename = monitor.cfg filename = monitor.cfg
md5sum = 12a46157fa882da1d17fcf3d168a3a95 md5sum = 60ab90ef68879e7e1204b3087b05a66c
mode = 0644 mode = 0644
[monitor-bin] [monitor-bin]
...@@ -70,7 +70,7 @@ mode = 0644 ...@@ -70,7 +70,7 @@ mode = 0644
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename} url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true download-only = true
md5sum = e759977b21c70213daa4c2701f2c2078 md5sum = 1e17f3c1850a3bda25409e2fdc0e3db8
destination = ${buildout:parts-directory}/monitor-index destination = ${buildout:parts-directory}/monitor-index
filename = index.cgi.in filename = index.cgi.in
mode = 0644 mode = 0644
......
...@@ -6,12 +6,13 @@ import Cookie ...@@ -6,12 +6,13 @@ import Cookie
import base64 import base64
import hashlib import hashlib
import hmac import hmac
import jinja2
import os import os
import subprocess import subprocess
import urllib import sys
import json
import argparse
cgitb.enable(display=0, logdir="/tmp/cgi.log") cgitb.enable(display=1, logdir="/tmp/cgi.log")
form = cgi.FieldStorage() form = cgi.FieldStorage()
cookie = Cookie.SimpleCookie() cookie = Cookie.SimpleCookie()
...@@ -25,10 +26,625 @@ monitor_apache_password_command = "{{ apache_update_command }}" ...@@ -25,10 +26,625 @@ monitor_apache_password_command = "{{ apache_update_command }}"
monitor_rewrite = "{{ ' '.join(rewrite_element.keys()) }}" monitor_rewrite = "{{ ' '.join(rewrite_element.keys()) }}"
######## #################
# Password functions # Main function #
#################
def main():
password = handleSentPasswordIfNecessaryAndGetPasswordIfCorrect()
setHeader("Content-Type", "text/html")
setHeader("Cache-Control", "no-cache")
if not isPasswordSet():
setHeader("Status", "200 OK")
sendHeaders()
renderer.printCreatePasswordForm()
# TODO make a promise to change the password, to avoid choosing on first connection.
# Actually, a default password should be set, and the promise should warn we have to change it.
# The promise should show RED if the password is not changed once, else GREEN.
return 0
if password is None:
setHeader("Status", "200 OK")
sendHeaders()
renderer.printLoginForm()
return 0
if not checkWithSetPassword(password):
setHeader("Status", "401 Unauthorized")
sendHeaders()
renderer.printLoginForm(error_message="Wrong password")
return 0
try:
href = form["href"].value
except KeyError:
sys.argv = ["monitor-status", "--cgi"]
return promises["monitor-status"]()
handler = getattr(renderer, "handle" + href, None)
if handler is not None:
handler()
return 0
printer = getattr(renderer, "print" + href, None)
if printer is not None:
setHeader("Status", "200 OK")
sendHeaders()
printer()
return 0
promise = promises.get(href)
if promise is not None:
sys.argv = [href, "--cgi"]
return promise()
setHeader("Status", "404 Not Found")
sendHeaders()
renderer._printResourceNotFound()
return 0
############
# Promises #
############
def promise_monitorPassword():
parser = argparse.ArgumentParser()
parser.add_argument("--cgi", action="store_true", help="Run this script as a CGI")
parser.add_argument("--json", action="store_true", help="Set output as json")
parser.add_argument("args", nargs="*", metavar="ARGS", default=[])
args = parser.parse_args()
password_changed_once = True # hardcoded for test
def renderForm(status_message=None, error_message=None):
print("<!DOCTYPE html><html><head>")
renderer._printHeadCss()
print("</head><body>")
print('<header><a href="?" class="as-button">Parent page</a></header>')
print("<h1>Monitor password</h1>")
if error_message:
print('<p style="color: red;">%s</p>' % escapeHtml(error_message))
if status_message:
print('<p style="color: cornflowerblue;">%s</p>' % escapeHtml(status_message))
if not password_changed_once: # Change the password
print("<p>The password is not changed at least once. It is highly recommended to change it now!</p>")
print("<p>The monitor password is the password used to connect to this interface. Here you can change the monitor password by filling the formular just below.</p>")
print('<form method="post"><input name="old_password" type="password" placeholder="Old password" /><br/>')
print('<input name="new_password" type="password" placeholder="New password" /><br/>')
print('<input name="confirm_password" type="password" placeholder="Confirm new password" /><br/>')
print('<input name="change_password" type="submit" value="Change password" /></form>')
print("</body></html>")
if args.cgi:
if form.has_key("change_password"):
if not (
form.has_key("old_password") and
form.has_key("new_password") and
form.has_key("confirm_password")
):
setHeader("Status", "200 OK")
sendHeaders()
renderForm(error_message="Sorry, unable to understand the sent formular.")
return 0
if not checkWithSetPassword(form["old_password"].value):
setHeader("Status", "200 OK")
sendHeaders()
renderForm(error_message="Wrong password.")
return 0
new_password = form["new_password"].value
if new_password != form["confirm_password"].value:
setHeader("Status", "200 OK")
sendHeaders()
renderForm(error_message="The two typed passwords don't match together.")
return 0
setPassword(new_password)
setCookiePassword(new_password)
setHeader("Status", "200 OK")
sendHeaders()
renderForm(status_message="Password changed successfully")
return 0
# Change the password
setHeader("Status", "200 OK")
sendHeaders()
renderForm()
return 0
if lget(args.args, 1) == "show":
if lget(args.args, 2) == "status":
if args.json:
if password_changed_once:
print(json.dumps({"status": "ok", "title": "Change password"}))
return 0
print(json.dumps({"status": "error", "title": "Change password", "message": "The password should be changed at least once"}))
return 1
print("Monitor password: OK: password changed at least once.")
return 0
return 2
def promise_checkWebPageHttpCacheHit():
parser = argparse.ArgumentParser()
parser.add_argument("--cgi", action="store_true", help="Run this script as a CGI")
parser.add_argument("--json", action="store_true", help="Set output as json")
parser.add_argument("args", nargs="*", metavar="ARGS", default=[])
args = parser.parse_args()
QUERY_STRING = os.getenv("QUERY_STRING")
if args.cgi:
if form.has_key("display_log"):
display_log = form["display_log"].value
if display_log != "web-page-cache-hit":
setHeader("Status", "404 Not Found")
sendHeaders()
renderer._printResourceNotFound()
return 0
if form.has_key("grep"):
setHeader("Status", "200 OK")
setHeader("Content-Type", "text/plain")
sendHeaders()
grep = form["grep"].value
with open(os.path.join(cgi_path, "web-page-cache-hit.log")) as f:
i = 1
for line in f:
if grep in line:
sys.stdout.write("% 6d: %s" % (i, line))
i += 1
return 0
with open(os.path.join(cgi_path, "web-page-cache-hit.log"), "rb") as f:
setHeader("Status", "200 OK")
setHeader("Content-Type", "text/plain")
sendHeaders()
sys.stdout.write(f.read())
return 0
if form.has_key("feeds"):
feed = form["feeds"].value
if feed == "report":
with open(os.path.join(cgi_path, "web-page-cache-report-rss.xml")) as f:
setHeader("Status", "200 OK")
setHeader("Content-Type", "application/atom+xml")
sendHeaders()
sys.stdout.write(f.read())
return 0
if feed == "last-log":
with open(os.path.join(cgi_path, "web-page-cache-log-rss.xml")) as f:
setHeader("Status", "200 OK")
setHeader("Content-Type", "application/atom+xml")
sendHeaders()
sys.stdout.write(f.read())
return 0
setHeader("Status", "404 Not Found")
sendHeaders()
renderer._printResourceNotFound()
return 0
setHeader("Status", "200 OK")
sendHeaders()
print("<!DOCTYPE html><html><head>")
renderer._printHeadCss()
print(' <link rel="alternate" href="?href=check-web-page-http-cache-hit&feeds=report" title="Promises status" type="application/atom+xml" />')
print("</head><body>")
print('<header><a href="?" class="as-button">Parent page</a><a href="" class="as-button">Refresh</a></header>')
print("<h1>Web page cache status</h1>")
print("<p>This page shows a report about cache status of some web pages and their contents, like Javascript files or CSS files.</p>")
print("<p>Index:</p>")
print('<ul>')
print(' <li><a href="#cache-issue-report">Cache issue report</a></li>')
print(' <li><a href="#last-log">Last log</a></li>')
print('</ul>')
print('<h2 id="cache-issue-report">Cache issue report</h2>')
print('<p><a href="?href=check-web-page-http-cache-hit&feeds=report"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | <button>Rerun</button></p>' % rssIconDataUri)
print('<pre style="overflow-wrap: initial; overflow-x: auto; white-space: pre;">')
print("http://my.domain.com/")
print(" The Cache-Control header is not set correctly (`no-cache`)")
print("http://my.domain.com/style.css")
print(" No headers found telling the resource was cached")
print("</pre>")
print('<h2 id="last-log">Last log</h2>')
QUERY_STRING = os.getenv("QUERY_STRING")
query_list = parseQueryString(QUERY_STRING)
print('<p style="display: inline-block;"><a href="?href=check-web-page-http-cache-hit&feeds=last-log"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | ' % rssIconDataUri)
print('<a href="?%s" download="web-page-cache-hit.log" class="as-button">Download</a> | </p>' % (QUERY_STRING + ("&" if QUERY_STRING else "") + "display_log=web-page-cache-hit"))
print('<form style="display: inline-block;" method="get" action="?">')
for query in query_list:
print('<input name="%s" type="hidden" value="%s" />' % (escapeHtml(query[0]), escapeHtml(query[1])))
print('<input name="display_log" type="hidden" value="web-page-cache-hit" />')
print('<input name="grep" type="text" /><input type="submit" value="Search" /></form>')
print('<div style="display: inline-block;"><span> | </span><button>Rotate log</button></div>')
print("<pre>")
print('<pre style="overflow-wrap: initial; overflow-x: auto; white-space: pre;">[..]\n' + escapeHtml(open(os.path.join(cgi_path, "web-page-cache-hit.log")).read()[-415:] or "No log") + "</pre>")
print("</body></html>")
return 0
if lget(args.args, 1) == "show":
if lget(args.args, 2) == "status":
if args.json:
print(json.dumps({"status": "error", "title": "Check web page cache", "message": "A web page contains uncached links."})) # XXX add report
return 0
print("Check web page cache: ERROR: A web page contains uncached links.") # XXX add report
return 0
if lget(args.args, 1) is None:
print("Check web page cache: ERROR: A web page contains uncached links.") # XXX add report
return 1
return 2
def promise_slowQuery():
parser = argparse.ArgumentParser()
parser.add_argument("--cgi", action="store_true", help="Run this script as a CGI")
parser.add_argument("--json", action="store_true", help="Set output as json")
parser.add_argument("args", nargs="*", metavar="ARGS", default=[])
args = parser.parse_args()
if args.cgi:
if form.has_key("display_log"):
display_log = form["display_log"].value
if display_log != "mariadb":
setHeader("Status", "404 Not Found")
sendHeaders()
renderer._printResourceNotFound()
return 0
if form.has_key("grep"):
grep = form["grep"].value
with open(os.path.join(cgi_path, "mariadb_slowquery.log")) as f:
setHeader("Status", "200 OK")
setHeader("Content-Type", "text/plain")
sendHeaders()
i = 1
for line in f:
if grep in line:
sys.stdout.write("% 5d: %s" % (i, line))
i += 1
return 0
with open(os.path.join(cgi_path, "mariadb_slowquery.log")) as f:
setHeader("Status", "200 OK")
setHeader("Content-Type", "text/plain")
sendHeaders()
sys.stdout.write(f.read())
return 0
setHeader("Status", "200 OK")
sendHeaders()
print("<!DOCTYPE html><html><head>")
renderer._printHeadCss()
print("</head><body>")
print('<header><a href="?" class="as-button">Parent page</a><a href="" class="as-button">Refresh</a></header>')
print("<h1>ERP5 slow query status</h1>")
print("<p>This page shows a report about mariadb slow queries. If the amount of slow queries reaches a defined threshold, then the status of this promise change to state BAD.</p>")
print("<p>Index:</p>")
print('<ul>')
print(' <li><a href="#slow-query-report">Slow query report</a></li>')
print(' <li><a href="#last-log">Last log</a></li>')
print('</ul>')
print('<h2 id="slow-query-report">Slow query report</h2>')
print('<p><a href="?href=slow-query&feeds=report"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | <button>Rerun</button></p>' % rssIconDataUri)
print('<pre style="overflow-wrap: initial; overflow-x: auto; white-space: pre;">' + escapeHtml(open(os.path.join(cgi_path, "mariadb_slowquery_pt-query-digest.log")).read() or "No report") + "</pre>")
#print("<pre>\n...\npercona toolkit report here\n...\n</pre>")
print('<h2 id="last-log">Last log</h2>')
QUERY_STRING = os.getenv("QUERY_STRING")
query_list = parseQueryString(QUERY_STRING)
print('<p style="display: inline-block;"><a href="?href=slow-query&display_log=mariadb&feeds=bunch-of-lines"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | ' % rssIconDataUri)
print('<a href="?%s" download="mariadb_slowquery.log" class="as-button">Download</a> | </p>' % (QUERY_STRING + ("&" if QUERY_STRING else "") + "display_log=mariadb"))
print('<form style="display: inline-block;" method="get" action="?">')
for query in query_list:
print('<input name="%s" type="hidden" value="%s" />' % (escapeHtml(query[0]), escapeHtml(query[1])))
print('<input name="display_log" type="hidden" value="mariadb" />')
print('<input name="grep" type="text" /><input type="submit" value="Search" /></form>')
print('<div style="display: inline-block;"><span> | </span><button>Rotate log</button></div>')
try:
print('<pre style="overflow-wrap: initial; overflow-x: auto; white-space: pre;">[..]\n' + escapeHtml(open(os.path.join(cgi_path, "mariadb_slowquery.log")).read()[-1024:] or "No log") + "</pre>")
except Exception, e:
print("<p>An error occured durring log reading</p><pre>" + escapeHtml(repr(e)) + "</pre>")
print("</body></html>")
return 0
if lget(args.args, 1) == "show":
if lget(args.args, 2) == "status":
if args.json:
print(json.dumps({"status": "error", "title": "Slow query", "message": "..."})) # XXX add report
return 0
print("Slow query: OK: 5 slow queries today.") # XXX add report
return 0
if lget(args.args, 1) is None:
print("Slow query: OK: 5 slow queries today.") # XXX add report
return 1
return 2
def promise_logSupervisor():
parser = argparse.ArgumentParser()
parser.add_argument("--cgi", action="store_true", help="Run this script as a CGI")
parser.add_argument("--json", action="store_true", help="Set output as json")
parser.add_argument("args", nargs="*", metavar="ARGS", default=[])
args = parser.parse_args()
if args.cgi:
# if form.has_key("display_log"):
# display_log = form["display_log"].value
# if display_log != "mariadb":
# setHeader("Status", "404 Not Found")
# sendHeaders()
# renderer._printResourceNotFound()
# return 0
# if form.has_key("grep"):
# grep = form["grep"].value
# with open(os.path.join(cgi_path, "mariadb_slowquery.log")) as f:
# setHeader("Status", "200 OK")
# setHeader("Content-Type", "text/plain")
# sendHeaders()
# i = 1
# for line in f:
# if grep in line:
# sys.stdout.write("% 5d: %s" % (i, line))
# i += 1
# return 0
# with open(os.path.join(cgi_path, "mariadb_slowquery.log")) as f:
# setHeader("Status", "200 OK")
# setHeader("Content-Type", "text/plain")
# sendHeaders()
# sys.stdout.write(f.read())
# return 0
setHeader("Status", "200 OK")
sendHeaders()
print("<!DOCTYPE html><html><head>")
renderer._printHeadCss()
print("</head><body>")
print('<header><a href="?" class="as-button">Parent page</a><a href="" class="as-button">Refresh</a></header>')
print("<h1>ERP5 log supervisor</h1>")
print("<p>This page gives access to all ERP5 log files. If a log file goes too big, the status of this supervisor is change to BAD.</p>")
print('<p><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></p>' % rssIconDataUri)
print("<p>Index:</p>")
print('<ul>')
print(' <li><a href="#log-file-size">Log file size</a></li>')
print(' <li><a href="#slappart1-mariadb-slow-query-log">instance 1: Mariadb slow query log</a></li>')
print(' <li><a href="#slappart1-mariadb-log">instance 1: Mariadb log</a></li>')
print(' <li><a href="#slappart6-zope-0-event">instance 6: Zope 0 event log</a></li>')
print(' <li><a href="#slappart6-zope-0-access">instance 6: Zope 0 access log</a></li>')
print('</ul>')
print('<h2 id="log-file-size">Log file size</h2>')
print("<ul>")
print(' <li style="color: red; font-weight: bold;">0.9 GB: instance 1: Mariadb slow query log | <button>Compress & backup</button></li>')
print(" <li>10 MB: instance 6: Zope 0 access log</li>")
print(" <li>2 MB: instance 6: Zope 0 event log</li>")
print(" <li>0 B: instance 1: Mariadb log</li>")
print("</ul>")
QUERY_STRING = os.getenv("QUERY_STRING")
query_list = parseQueryString(QUERY_STRING)
print('<h2 id="slappart1-mariadb-slow-query-log">instance 1: Mariadb slow query log</h2>')
print('<p style="display: inline-block;"><a href="?href=log-supervisor&display_log=slappart1-mariadb-slow-query&feeds=bunch-of-lines"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | ' % rssIconDataUri)
print('<a href="?%s" download="mariadb_slowquery.log" class="as-button">Download</a> | </p>' % (QUERY_STRING + ("&" if QUERY_STRING else "") + "display_log=slappart1-mariadb-slow-query"))
print('<form style="display: inline-block;" method="get" action="?">')
for query in query_list:
print('<input name="%s" type="hidden" value="%s" />' % (escapeHtml(query[0]), escapeHtml(query[1])))
print('<input name="display_log" type="hidden" value="slappart1-mariadb-slow-query" />')
print('<input name="grep" type="text" /><input type="submit" value="Search" /></form>')
print('<div style="display: inline-block;"><span> | </span><button>Rotate log</button></div>')
try:
print('<pre style="overflow-wrap: initial; overflow-x: auto; white-space: pre;">[..]\n' + escapeHtml(open(os.path.join(cgi_path, "mariadb_slowquery.log")).read()[-1024:] or "No log") + "</pre>")
except Exception, e:
print("<p>An error occured durring log reading</p><pre>" + escapeHtml(repr(e)) + "</pre>")
print('<h2 id="slappart1-mariadb-log">instance 1: Mariadb log</h2>')
print('<p style="display: inline-block;"><a href="?href=log-supervisor&display_log=slappart1-mariadb&feeds=bunch-of-lines"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | ' % rssIconDataUri)
print('<a href="?%s" download="mariadb.log" class="as-button">Download</a> | </p>' % (QUERY_STRING + ("&" if QUERY_STRING else "") + "display_log=slappart1-mariadb"))
print('<form style="display: inline-block;" method="get" action="?">')
for query in query_list:
print('<input name="%s" type="hidden" value="%s" />' % (escapeHtml(query[0]), escapeHtml(query[1])))
print('<input name="display_log" type="hidden" value="slappart1-mariadb" />')
print('<input name="grep" type="text" /><input type="submit" value="Search" /></form>')
print('<div style="display: inline-block;"><span> | </span><button>Rotate log</button></div>')
print("<p>Empty log</p>")
print('<h2 id="slappart6-zope-0-event">instance 6: Zope 0 event log</h2>')
print('<p style="display: inline-block;"><a href="?href=log-supervisor&display_log=slappart6-zope-0-event&feeds=bunch-of-lines"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | ' % rssIconDataUri)
print('<a href="?%s" download="zope-0-event.log" class="as-button">Download</a> | </p>' % (QUERY_STRING + ("&" if QUERY_STRING else "") + "display_log=slappart6-zope-0-event"))
print('<form style="display: inline-block;" method="get" action="?">')
for query in query_list:
print('<input name="%s" type="hidden" value="%s" />' % (escapeHtml(query[0]), escapeHtml(query[1])))
print('<input name="display_log" type="hidden" value="slappart6-zope-0-event" />')
print('<input name="grep" type="text" /><input type="submit" value="Search" /></form>')
print('<div style="display: inline-block;"><span> | </span><button>Rotate log</button></div>')
print("<p>XXX</p>")
print('<h2 id="slappart6-zope-0-access">instance 6: Zope 0 access log</h2>')
print('<p style="display: inline-block;"><a href="?href=log-supervisor&display_log=slappart6-zope-0-access&feeds=bunch-of-lines"><img src="%s" style="height: 10mm; width: 10mm; vertical-align: bottom;" alt="RSS feed"/></a> | ' % rssIconDataUri)
print('<a href="?%s" download="zope-0-Z2.log" class="as-button">Download</a> | </p>' % (QUERY_STRING + ("&" if QUERY_STRING else "") + "display_log=slappart6-zope-0-access"))
print('<form style="display: inline-block;" method="get" action="?">')
for query in query_list:
print('<input name="%s" type="hidden" value="%s" />' % (escapeHtml(query[0]), escapeHtml(query[1])))
print('<input name="display_log" type="hidden" value="slappart6-zope-0-access" />')
print('<input name="grep" type="text" /><input type="submit" value="Search" /></form>')
print('<div style="display: inline-block;"><span> | </span><button>Rotate log</button></div>')
print("<p>XXX</p>")
print("</body></html>")
return 0
if lget(args.args, 1) == "show":
if lget(args.args, 2) == "status":
if args.json:
print(json.dumps({"status": "error", "title": "Slow query", "message": "..."})) # XXX add report
return 0
print("Slow query: OK: 5 slow queries today.") # XXX add report
return 0
if lget(args.args, 1) is None:
print("Slow query: OK: 5 slow queries today.") # XXX add report
return 1
return 2
def promise_logout():
# XXX handle parameters
unsetCookiePassword()
setHeader("Status", "200 OK")
sendHeaders()
renderer.printLoginForm()
def promise_monitorStatus():
# XXX handle parameters
if form.has_key("feeds"):
feed = form["feeds"].value
if feed != "promises-status":
setHeader("Status", "404 Not Found")
sendHeaders()
renderer._printResourceNotFound()
return 0
setHeader("Status", "200 OK")
setHeader("Content-Type", "application/atom+xml")
sendHeaders()
with open(os.path.join(cgi_path, "monitor-status-rss.xml")) as f:
print f.read()
return 0
setHeader("Status", "200 OK")
sendHeaders()
print("<!DOCTYPE html>\n<html>\n <head>")
renderer._printHeadCss()
print(' <link rel="alternate" href="?href=monitor-status&feeds=promises-status" title="Promises status" type="application/atom+xml" />')
print(" </head>\n <body>")
print(' <header><a href="?href=logout" class="as-button">Logout</a><a href="" class="as-button">Refresh</a></header>')
print(" <h1>ERP5 Monitoring interface</h1>")
print(" <h2>System health status</h2>")
print(" <p>This interface allow to see the status of several features, it may show problems and sometimes provides a way to fix them.</p>")
print(" <p>Red square means the feature has a problem, green square means it is ok.</p>")
print(" <p>You can click on a feature below to get more precise information.</p>")
print(" <table><tbody>")
def hardcodePromiseStatus(p, l, r, c):
print(" <tr><td><a href=\"%s\">%s</a></td><td>%s</td><td><a href=\"%s\"><div style=\"background-color: %s; height: 10mm; width: 10mm;\"></div></a></td></tr>" % (escapeHtml(l), escapeHtml(p), escapeHtml(r), escapeHtml(l), c))
def tableSeparator():
print(" <tr><td colspan=\"3\"><hr/></td></tr>")
print(" <tr style=\"margin-bottom: 3%%;\"><td></td><td></td><td><a href=\"?href=monitor-status&feeds=promises-status\"><img src=\"%s\" style=\"height: 10mm; width: 10mm;\" /></a></td></tr>" % rssIconDataUri)
hardcodePromiseStatus("Monitor password", "/index.cgi?href=monitor-password", "Password changed once", "green")
tableSeparator()
hardcodePromiseStatus("Web page cache", "/index.cgi?href=check-web-page-http-cache-hit", "Some web pages are not well cached", "red")
tableSeparator()
hardcodePromiseStatus("Slow query", "/index.cgi?href=slow-query", "5 slow queries today", "green")
tableSeparator()
hardcodePromiseStatus("Log supervisor", "/index.cgi?href=log-supervisor", "1 log file is too big", "red")
print(" </tbody></table>")
print(" </body>\n</html>")
return 0
promises = {
"monitor-status": promise_monitorStatus,
"check-web-page-http-cache-hit": promise_checkWebPageHttpCacheHit,
"monitor-password": promise_monitorPassword,
"slow-query": promise_slowQuery,
"log-supervisor": promise_logSupervisor,
"logout": promise_logout,
}
#############
# Rendering #
#############
class Renderer(object):
def printLoginForm(self, error_message=None):
print("<!DOCTYPE html>\n<html>\n <head>")
self._printHeadCss()
print(" </head>\n <body>")
print(" <h1>ERP5 Monitoring interface</h1>")
if error_message:
print(" <p>%s</p>" % escapeHtml(error_message))
print(" <p>Please enter the monitor_password in the next field to access the data</p>")
print("""\
<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 -->
<button type="submit">Access</button>
</form>""")
print(" </body>\n</html>\n")
def printEnviron(self): # XXX temporarily
print("<!DOCTYPE html><html><head></head><body><h2>Environ</h2><pre>")
for item in os.environ.items():
print(escapeHtml("%s: %s" % item))
print("</pre><h2>Form</h2><pre>")
for key in form.keys():
print(escapeHtml("%s: %s" % (key, form[key].value)))
print("</pre><h2>Argv</h2><pre>")
print(escapeHtml(", ".join(sys.argv)))
print("</pre></body></html>")
def printError(self): # XXX temporarily
raise ValueError("Tristan Error")
def printCreatePasswordForm(self):
print("<!DOCTYPE html>\n<html>\n <head>")
print(' <script type="application/javascript" src="static/jquery-1.10.2.min.js"></script>')
self._printHeadCss()
print(" </head>\n <body>")
print("<h1>ERP5 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_2">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 -->
<button id="register-button" type="submit" disabled>Access</button>
</form>
<script type="application/javascript" src="static/monitor-register.js"></script>
</body></html>
""")
def _printResourceNotFound(self):
print("<!DOCTYPE html><html><head></head><body><p>Resource not found</p></body></html>")
def _printHeadCss(self):
print(' <link rel="stylesheet" href="static/pure-min.css">')
print(' <link rel="stylesheet" href="static/style.css">')
print(""" <style>
body { width: 80vw; margin: auto; }
/* h1 { align-text: center; margin: auto; } */
td { padding: 0 2%; }
input {
box-sizing: border-box;
min-height: 10mm;
min-width: 10mm;
}
button {
box-sizing: border-box;
min-height: 10mm;
min-width: 10mm;
background-color: lightgray;
background: linear-gradient(180deg, #F6F6F6 0%, #DDDDDD 100%);
border-radius: 2px;
border-style: solid;
border-width: 1px;
border-color: #A4A4A4;
}
a.as-button {
display: inline-block;
box-sizing: border-box;
min-height: 10mm;
min-width: 10mm;
padding: 0.5em 0.5em;
text-align: center;
text-decoration: initial;
}
a.as-button {
color: black;
background-color: lightgray;
background: linear-gradient(180deg, #F6F6F6 0%, #DDDDDD 100%);
border-radius: 2px;
border-style: solid;
border-width: 1px;
border-color: #A4A4A4;
}
a.as-button:active, button:active {
background-color: white;
background: linear-gradient(0deg, #F6F6F6 0%, #DDDDDD 100%);
}
a.as-button:hover, button:hover {
border-color: #777777;
}
</style>""")
renderer = Renderer()
#######
# CGI #
####### #######
def crypt(word, salt="$$"):
header_dict = {}
def setHeader(header, value):
header_dict[header] = value
def sendHeaders():
for header, value in header_dict.items():
sys.stdout.write("%s: %s\r\n" % (header, value.replace("\n", "\n ")))
sys.stdout.write("\r\n")
######################
# Password functions #
######################
def encryptPassword(word, salt="$$"):
salt = salt.split("$") salt = salt.split("$")
algo = salt[0] or 'sha1' algo = salt[0] or 'sha1'
if algo in hashlib.algorithms: if algo in hashlib.algorithms:
...@@ -45,7 +661,7 @@ def crypt(word, salt="$$"): ...@@ -45,7 +661,7 @@ def crypt(word, salt="$$"):
return "%s$%s$%s$%s" % (algo, rounds, salt, return "%s$%s$%s$%s" % (algo, rounds, salt,
base64.b64encode(h, "./").rstrip("=")) base64.b64encode(h, "./").rstrip("="))
def is_password_set(): def isPasswordSet():
if not os.path.exists(monitor_password_path): if not os.path.exists(monitor_password_path):
return False return False
hashed_password = open(monitor_password_path, 'r').read() hashed_password = open(monitor_password_path, 'r').read()
...@@ -55,14 +671,13 @@ def is_password_set(): ...@@ -55,14 +671,13 @@ def is_password_set():
return False return False
return True return True
def set_password(raw_password): def setPassword(raw_password):
hashed_password = crypt(raw_password) hashed_password = encryptPassword(raw_password)
subprocess.check_call(monitor_apache_password_command + " %s" % raw_password, subprocess.check_call(monitor_apache_password_command + " %s" % raw_password,
shell=True) shell=True)
open(monitor_password_path, 'w').write(hashed_password) open(monitor_password_path, 'w').write(hashed_password)
def checkWithSetPassword(raw_password):
def check_password(raw_password):
""" """
Returns a boolean of whether the raw_password was correct. Handles Returns a boolean of whether the raw_password was correct. Handles
encryption formats behind the scenes. encryption formats behind the scenes.
...@@ -70,56 +685,9 @@ def check_password(raw_password): ...@@ -70,56 +685,9 @@ def check_password(raw_password):
if not os.path.exists(monitor_password_path) or not raw_password: if not os.path.exists(monitor_password_path) or not raw_password:
return False return False
hashed_password = open(monitor_password_path, 'r').read() hashed_password = open(monitor_password_path, 'r').read()
return hashed_password == crypt(raw_password, hashed_password) return hashed_password == encryptPassword(raw_password, hashed_password)
### End of password functions
def getCookiePassword():
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') cookie_string = os.environ.get('HTTP_COOKIE')
if cookie_string: if cookie_string:
cookie.load(cookie_string) cookie.load(cookie_string)
...@@ -129,62 +697,67 @@ def get_cookie_password(): ...@@ -129,62 +697,67 @@ def get_cookie_password():
pass pass
return None return None
def set_cookie_password(password): def setCookiePassword(password):
cookie['password'] = password cookie['password'] = password
print cookie, "; Path=/; HttpOnly" print cookie, "; Path=/; HttpOnly"
def unsetCookiePassword():
cookie['password'] = ""
print cookie, "; Path=/; expires=Thu, 01-Jan-1970 12:34:56 GMT; HttpOnly"
# Beginning of response def handleSentPasswordIfNecessaryAndGetPasswordIfCorrect():
print "Content-Type: text/html" if "password_2" in form and "password" in form:
password_2 = form['password_2'].value
password = None password_1 = form['password'].value
password = getCookiePassword()
# Check if user is logged if not isPasswordSet() or checkWithSetPassword(password):
if "password_2" in form and "password" in form: if password_2 == password_1:
password_2 = form['password_2'].value password = password_1
password_1 = form['password'].value setPassword(password)
password = get_cookie_password() setCookiePassword(password)
if not is_password_set() or check_password(password): return password
if password_2 == password_1: return None
password = password_1 if "password" in form:
set_password(password) password = form['password'].value
set_cookie_password(password) if isPasswordSet() and checkWithSetPassword(password):
elif "password" in form: setCookiePassword(password)
password = form['password'].value return password
if is_password_set() and check_password(password): return None
set_cookie_password(password) password = getCookiePassword()
else: return password if isPasswordSet() and checkWithSetPassword(password) else None
password = get_cookie_password()
print '\n' #########
# Tools #
#########
if not is_password_set():
return_document(monitor_password_script_path) def escapeHtml(text):
elif not check_password(password): return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;").replace("'", "&apos;")
print "<html><head>"
print """ def lget(lyst, index, default=None):
<link rel="stylesheet" href="static/pure-min.css"> try:
<link rel="stylesheet" href="static/style.css">""" return lyst[index]
print "</head><body>" except RangeError:
if password is None: return default
print "<h1>This is the monitoring interface</h1>"
else: def parseQueryString(string):
print "<h1>Error</h1><p>Wrong password</p>" parameter_list = string.split("&")
print """ for index, parameter in enumerate(parameter_list):
<p>Please enter the monitor_password in the next field to access the data</p> split = parameter.split("=")
<form action="/index.cgi" method="post" class="pure-form-aligned"> parameter_list[index] = (split[0], "=".join(split[1:]))
Password : <input type="password" name="password"> return parameter_list
<button type="submit" class="pure-button pure-button-primary">Access</button>
</form> rssIconDataUri = "".join([
</body></html>""" "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwhRE9DVFlQR",
# redirection to the required script/page "SBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cu",
else: "dzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM",
print "9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPS",
if "posting-script" in form: "IxMjhweCIgaGVpZ2h0PSIxMjhweCIgdmlld0JveD0iMCAwIDI1NiAyNTYiPgo8cmVjd",
forward_form() "CB3aWR0aD0iMjU2IiBoZWlnaHQ9IjI1NiIgeD0iMCIgIHk9IjAiICBmaWxsPSIjRjQ5",
elif "script" in form: "QzUyIi8+CjxjaXJjbGUgY3g9IjY4IiBjeT0iMTg5IiByPSIyNCIgZmlsbD0iI0ZGRiI",
return_document() "vPgo8cGF0aCBkPSJNMTYwIDIxM2gtMzRhODIgODIgMCAwIDAgLTgyIC04MnYtMzRhMT",
else: "E2IDExNiAwIDAgMSAxMTYgMTE2eiIgZmlsbD0iI0ZGRiIvPgo8cGF0aCBkPSJNMTg0I",
html_base = jinja2.Template(open('{{ index_template }}').read()) "DIxM0ExNDAgMTQwIDAgMCAwIDQ0IDczIFYgMzhhMTc1IDE3NSAwIDAgMSAxNzUgMTc1",
print "eiIgZmlsbD0iI0ZGRiIvPgo8L3N2Zz4K",
print html_base.render(tree=make_menu(), default_page="{{ default_page }}", monitor_rewrite=monitor_rewrite) ])
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