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

index.cgi +1

parent f9853052
......@@ -46,7 +46,7 @@ recipe = slapos.recipe.template
url = ${:_profile_base_location_}/monitor.cfg.in
output = ${buildout:directory}/monitor.cfg
filename = monitor.cfg
md5sum = 12a46157fa882da1d17fcf3d168a3a95
md5sum = 60ab90ef68879e7e1204b3087b05a66c
mode = 0644
[monitor-bin]
......@@ -70,7 +70,7 @@ mode = 0644
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = e759977b21c70213daa4c2701f2c2078
md5sum = 1e17f3c1850a3bda25409e2fdc0e3db8
destination = ${buildout:parts-directory}/monitor-index
filename = index.cgi.in
mode = 0644
......
......@@ -6,12 +6,13 @@ import Cookie
import base64
import hashlib
import hmac
import jinja2
import os
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()
cookie = Cookie.SimpleCookie()
......@@ -25,10 +26,625 @@ monitor_apache_password_command = "{{ apache_update_command }}"
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("$")
algo = salt[0] or 'sha1'
if algo in hashlib.algorithms:
......@@ -45,7 +661,7 @@ def crypt(word, salt="$$"):
return "%s$%s$%s$%s" % (algo, rounds, salt,
base64.b64encode(h, "./").rstrip("="))
def is_password_set():
def isPasswordSet():
if not os.path.exists(monitor_password_path):
return False
hashed_password = open(monitor_password_path, 'r').read()
......@@ -55,14 +671,13 @@ def is_password_set():
return False
return True
def set_password(raw_password):
hashed_password = crypt(raw_password)
def setPassword(raw_password):
hashed_password = encryptPassword(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):
def checkWithSetPassword(raw_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
encryption formats behind the scenes.
......@@ -70,56 +685,9 @@ def check_password(raw_password):
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
return hashed_password == encryptPassword(raw_password, hashed_password)
def get_cookie_password():
def getCookiePassword():
cookie_string = os.environ.get('HTTP_COOKIE')
if cookie_string:
cookie.load(cookie_string)
......@@ -129,62 +697,67 @@ def get_cookie_password():
pass
return None
def set_cookie_password(password):
def setCookiePassword(password):
cookie['password'] = password
print cookie, "; Path=/; HttpOnly"
def unsetCookiePassword():
cookie['password'] = ""
print cookie, "; Path=/; expires=Thu, 01-Jan-1970 12:34:56 GMT; 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:
def handleSentPasswordIfNecessaryAndGetPasswordIfCorrect():
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):
password = getCookiePassword()
if not isPasswordSet() or checkWithSetPassword(password):
if password_2 == password_1:
password = password_1
set_password(password)
set_cookie_password(password)
elif "password" in form:
setPassword(password)
setCookiePassword(password)
return password
return None
if "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)
if isPasswordSet() and checkWithSetPassword(password):
setCookiePassword(password)
return password
return None
password = getCookiePassword()
return password if isPasswordSet() and checkWithSetPassword(password) else None
#########
# Tools #
#########
def escapeHtml(text):
return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;").replace("'", "&apos;")
def lget(lyst, index, default=None):
try:
return lyst[index]
except RangeError:
return default
def parseQueryString(string):
parameter_list = string.split("&")
for index, parameter in enumerate(parameter_list):
split = parameter.split("=")
parameter_list[index] = (split[0], "=".join(split[1:]))
return parameter_list
rssIconDataUri = "".join([
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwhRE9DVFlQR",
"SBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cu",
"dzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM",
"9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPS",
"IxMjhweCIgaGVpZ2h0PSIxMjhweCIgdmlld0JveD0iMCAwIDI1NiAyNTYiPgo8cmVjd",
"CB3aWR0aD0iMjU2IiBoZWlnaHQ9IjI1NiIgeD0iMCIgIHk9IjAiICBmaWxsPSIjRjQ5",
"QzUyIi8+CjxjaXJjbGUgY3g9IjY4IiBjeT0iMTg5IiByPSIyNCIgZmlsbD0iI0ZGRiI",
"vPgo8cGF0aCBkPSJNMTYwIDIxM2gtMzRhODIgODIgMCAwIDAgLTgyIC04MnYtMzRhMT",
"E2IDExNiAwIDAgMSAxMTYgMTE2eiIgZmlsbD0iI0ZGRiIvPgo8cGF0aCBkPSJNMTg0I",
"DIxM0ExNDAgMTQwIDAgMCAwIDQ0IDczIFYgMzhhMTc1IDE3NSAwIDAgMSAxNzUgMTc1",
"eiIgZmlsbD0iI0ZGRiIvPgo8L3N2Zz4K",
])
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