diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c99020..640243b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +In Development +-------------- + +Control panel: + +* Munin system monitoring graphs are now zoomable. + v0.17b (March 1, 2016) ---------------------- diff --git a/management/daemon.py b/management/daemon.py index bf3c913..85a722a 100755 --- a/management/daemon.py +++ b/management/daemon.py @@ -1,10 +1,10 @@ #!/usr/bin/python3 import os, os.path, re, json - +import subprocess from functools import wraps -from flask import Flask, request, render_template, abort, Response, send_from_directory +from flask import Flask, request, render_template, abort, Response, send_from_directory, make_response import auth, utils, multiprocessing.pool from mailconfig import get_mail_users, get_mail_users_ex, get_admins, add_mail_user, set_mail_password, remove_mail_user @@ -504,6 +504,64 @@ def munin(filename=""): if filename == "": filename = "index.html" return send_from_directory("/var/cache/munin/www", filename) +@app.route('/munin/cgi-graph/') +@authorized_personnel_only +def munin_cgi(filename): + """ Relay munin cgi dynazoom requests + /usr/lib/munin/cgi/munin-cgi-graph is a perl cgi script in the munin package + that is responsible for generating binary png images _and_ associated HTTP + headers based on parameters in the requesting URL. All output is written + to stdout which munin_cgi splits into response headers and binary response + data. + munin-cgi-graph reads environment variables as well as passed input to determine + what it should do. It expects a path to be in the env-var PATH_INFO, and a + querystring to be in the env-var QUERY_STRING as well as passed as input to the + command. + munin-cgi-graph has several failure modes. Some write HTTP Status headers and + others return nonzero exit codes. + Situating munin_cgi between the user-agent and munin-cgi-graph enables keeping + the cgi script behind mailinabox's auth mechanisms and avoids additional + support infrastructure like spawn-fcgi. + """ + + COMMAND = 'su - munin --preserve-environment --shell=/bin/bash -c /usr/lib/munin/cgi/munin-cgi-graph "%s"' + # su changes user, we use the munin user here + # --preserve-environment retains the environment, which is where Popen's `env` data is + # --shell=/bin/bash ensures the shell used is bash + # -c "/usr/lib/munin/cgi/munin-cgi-graph" passes the command to run as munin + # "%s" is a placeholder for where the request's querystring will be added + + if filename == "": + return ("a path must be specified", 404) + + query_str = request.query_string.decode("utf-8", 'ignore') + + env = {'PATH_INFO': '/%s/' % filename, 'QUERY_STRING': query_str} + cmd = COMMAND % query_str + code, binout = utils.shell('check_output', + cmd.split(' ', 5), + # Using a maxsplit of 5 keeps the last 2 arguments together + input=query_str.encode('UTF-8'), + env=env, + return_bytes=True, + trap=True) + + if code != 0: + # nonzero returncode indicates error + app.logger.error("munin_cgi: munin-cgi-graph returned nonzero exit code, %s", process.returncode) + return ("error processing graph image", 500) + + # /usr/lib/munin/cgi/munin-cgi-graph returns both headers and binary png when successful. + # A double-Windows-style-newline always indicates the end of HTTP headers. + headers, image_bytes = binout.split(b'\r\n\r\n', 1) + response = make_response(image_bytes) + for line in headers.splitlines(): + name, value = line.decode("utf8").split(':', 1) + response.headers[name] = value + if 'Status' in response.headers and '404' in response.headers['Status']: + app.logger.warning("munin_cgi: munin-cgi-graph returned 404 status code. PATH_INFO=%s", env['PATH_INFO']) + return response + # APP if __name__ == '__main__': diff --git a/setup/munin.sh b/setup/munin.sh index 0cee9ba..b1c5c8b 100755 --- a/setup/munin.sh +++ b/setup/munin.sh @@ -7,7 +7,8 @@ source /etc/mailinabox.conf # load global vars # install Munin echo "Installing Munin (system monitoring)..." -apt_install munin munin-node +apt_install munin munin-node libcgi-fast-perl +# libcgi-fast-perl is needed by /usr/lib/munin/cgi/munin-cgi-graph # edit config cat > /etc/munin/munin.conf <