2
0
mirror of https://github.com/munin-monitoring/contrib.git synced 2018-11-08 00:59:34 +01:00
contrib-munin/plugins/monit/monit_parser
Gerald Turner 4fa3811c12
Add optional preemptive HTTP Basic Authentication to HTTP request in order to
support monit configuration like "set httpd port 2812 allow munin:s3cr3t
read-only"
2017-01-20 15:46:32 -08:00

127 lines
3.5 KiB
Python
Executable File

#!/usr/bin/python3
"""
=head1 NAME
monit_parser - Monit status parser plugin for munin.
=head1 APPLICABLE SYSTEMS
Any system being able to query monit servers via http.
Monit needs to be configured with the httpd port enabled, e.g.:
set httpd port 2812
Optionally monit authentication can be configured, e.g.:
set httpd port 2812
allow munin:s3cr3t read-only
=head1 CONFIGURATION
By default the monit instance at localhost is queried:
[monit_parser]
env.port 2812
env.host localhost
Optionally monit authentication can be configured, e.g.:
[monit_parser]
env.username munin
env.password s3cr3t
=head1 AUTHOR
Todd Troxell <ttroxell@debian.org>
Lars Kruse <devel@sumpfralle.de>
=head1 MAGIC MARKERS
family=auto
capabilities=autoconf
=cut
"""
import xml.dom.minidom
import os
import sys
import urllib.request
import base64
MONIT_XML_URL = ("http://{host}:{port}/_status?format=xml"
.format(host=os.getenv("host", "localhost"),
port=os.getenv("port", "2812")))
def sanitize(s):
OK_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789"
return "".join([char for char in s if char in OK_CHARS])
def get_monit_status_xml():
try:
req = urllib.request.Request(url=MONIT_XML_URL)
if os.getenv("password"):
auth_str = "%s:%s" % (os.getenv("username"), os.getenv("password"))
auth_bytes = bytes(auth_str, "utf-8")
auth_base64_bytes = base64.b64encode(auth_bytes)
auth_base64_str = str(auth_base64_bytes, "ascii")
auth_value = "Basic %s" % auth_base64_str
req.add_header("Authorization", auth_value)
conn = urllib.request.urlopen(req)
except urllib.error.URLError as exc:
conn = None
if conn is None:
raise RuntimeError("Failed to open monit status URL: {}".format(MONIT_XML_URL))
else:
return xml.dom.minidom.parse(conn)
def parse_processes():
dom = get_monit_status_xml()
procs = {}
for item in dom.getElementsByTagName("service"):
if item.getAttribute("type") == "3":
# daemon with memory usage and CPU
name = item.getElementsByTagName("name")[0].childNodes[0].data
memory_usage = item.getElementsByTagName("memory")[0].getElementsByTagName(
"kilobytetotal")[0].childNodes[0].data
cpu_usage = item.getElementsByTagName("cpu")[0].getElementsByTagName(
"percenttotal")[0].childNodes[0].data
procs[name] = {}
procs[name]["total_memory"] = memory_usage
procs[name]["total_cpu"] = cpu_usage
return procs
action = sys.argv[1] if (len(sys.argv) > 1) else None
if action == 'autoconf':
try:
get_monit_status_xml()
print("yes")
except RuntimeError:
print("no (failed to request monit status)")
elif action == 'config':
procs = parse_processes()
print('graph_title Per process stats from Monit')
print('graph_vlabel usage of memory [kB] or cpu [%]')
print('graph_category monit')
for process in procs:
for stat in procs[process]:
print("monit_%s_%s.label %s.%s" % (sanitize(process), stat, process, stat))
if stat == 'total_memory':
# the allocated memory may never be zero
print("monit_%s_%s.warning 1:" % (sanitize(process), stat))
else:
for process, stats in parse_processes().items():
for stat_key, stat_value in stats.items():
print("monit_%s_%s.value %s" % (sanitize(process), stat_key, stat_value))