2016-10-23 05:05:28 +02:00
|
|
|
#!/usr/bin/python3
|
2007-07-21 09:42:54 +02:00
|
|
|
|
2016-10-23 03:14:48 +02:00
|
|
|
"""
|
|
|
|
=head1 NAME
|
2007-07-21 09:42:54 +02:00
|
|
|
|
2016-10-23 03:14:48 +02:00
|
|
|
monit_parser - Monit status parser plugin for munin.
|
2007-07-21 09:42:54 +02:00
|
|
|
|
2016-10-23 03:14:48 +02:00
|
|
|
|
|
|
|
=head1 APPLICABLE SYSTEMS
|
|
|
|
|
2016-10-23 05:05:28 +02:00
|
|
|
Any system being able to query monit servers via http.
|
2016-10-23 03:14:48 +02:00
|
|
|
|
|
|
|
Monit needs to be configured with the httpd port enabled, e.g.:
|
|
|
|
|
|
|
|
set httpd port 2812
|
|
|
|
|
2017-01-21 00:46:32 +01:00
|
|
|
Optionally monit authentication can be configured, e.g.:
|
2016-10-23 05:05:28 +02:00
|
|
|
|
2017-01-21 00:46:32 +01:00
|
|
|
set httpd port 2812
|
|
|
|
allow munin:s3cr3t read-only
|
2016-10-23 03:14:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
|
2016-10-23 05:05:28 +02:00
|
|
|
By default the monit instance at localhost is queried:
|
2016-10-23 03:14:48 +02:00
|
|
|
|
|
|
|
[monit_parser]
|
2016-10-23 05:05:28 +02:00
|
|
|
env.port 2812
|
|
|
|
env.host localhost
|
2016-10-23 03:14:48 +02:00
|
|
|
|
2017-01-21 00:46:32 +01:00
|
|
|
Optionally monit authentication can be configured, e.g.:
|
|
|
|
|
|
|
|
[monit_parser]
|
|
|
|
env.username munin
|
|
|
|
env.password s3cr3t
|
|
|
|
|
2016-10-23 03:14:48 +02:00
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
|
|
|
Todd Troxell <ttroxell@debian.org>
|
|
|
|
Lars Kruse <devel@sumpfralle.de>
|
|
|
|
|
|
|
|
|
|
|
|
=head1 MAGIC MARKERS
|
|
|
|
|
|
|
|
family=auto
|
|
|
|
capabilities=autoconf
|
|
|
|
|
|
|
|
=cut
|
|
|
|
"""
|
2007-07-21 09:42:54 +02:00
|
|
|
|
2016-10-23 05:05:28 +02:00
|
|
|
import xml.dom.minidom
|
|
|
|
import os
|
2016-10-23 01:27:25 +02:00
|
|
|
import sys
|
2016-10-23 05:05:28 +02:00
|
|
|
import urllib.request
|
2017-01-21 00:46:32 +01:00
|
|
|
import base64
|
2016-10-23 05:05:28 +02:00
|
|
|
|
|
|
|
MONIT_XML_URL = ("http://{host}:{port}/_status?format=xml"
|
|
|
|
.format(host=os.getenv("host", "localhost"),
|
|
|
|
port=os.getenv("port", "2812")))
|
2016-10-23 01:27:25 +02:00
|
|
|
|
2007-07-21 09:42:54 +02:00
|
|
|
|
|
|
|
def sanitize(s):
|
2018-03-27 04:55:14 +02:00
|
|
|
ok_chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
|
|
|
return "".join([char for char in s if char in ok_chars])
|
2016-10-23 03:20:05 +02:00
|
|
|
|
|
|
|
|
2016-10-23 05:05:28 +02:00
|
|
|
def get_monit_status_xml():
|
2016-10-23 03:20:05 +02:00
|
|
|
try:
|
2017-01-21 00:46:32 +01:00
|
|
|
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)
|
2016-10-23 05:05:28 +02:00
|
|
|
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)
|
2016-10-23 03:20:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
def parse_processes():
|
2016-10-23 05:05:28 +02:00
|
|
|
dom = get_monit_status_xml()
|
2016-10-23 03:20:05 +02:00
|
|
|
procs = {}
|
2016-10-23 05:05:28 +02:00
|
|
|
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
|
2016-10-23 03:20:05 +02:00
|
|
|
return procs
|
|
|
|
|
|
|
|
|
|
|
|
action = sys.argv[1] if (len(sys.argv) > 1) else None
|
|
|
|
|
|
|
|
if action == 'autoconf':
|
|
|
|
try:
|
2016-10-23 05:05:28 +02:00
|
|
|
get_monit_status_xml()
|
2016-10-23 03:20:05 +02:00
|
|
|
print("yes")
|
2016-10-23 05:05:28 +02:00
|
|
|
except RuntimeError:
|
2016-10-23 03:20:05 +02:00
|
|
|
print("no (failed to request monit status)")
|
|
|
|
elif action == 'config':
|
|
|
|
procs = parse_processes()
|
2016-10-23 01:27:50 +02:00
|
|
|
print('graph_title Per process stats from Monit')
|
2016-10-23 05:05:28 +02:00
|
|
|
print('graph_vlabel usage of memory [kB] or cpu [%]')
|
2017-02-23 00:15:13 +01:00
|
|
|
print('graph_category munin')
|
2007-07-21 09:42:54 +02:00
|
|
|
for process in procs:
|
|
|
|
for stat in procs[process]:
|
2016-10-23 05:05:28 +02:00
|
|
|
print("monit_%s_%s.label %s.%s" % (sanitize(process), stat, process, stat))
|
2015-06-08 17:10:04 +02:00
|
|
|
if stat == 'total_memory':
|
2016-10-23 03:20:05 +02:00
|
|
|
# the allocated memory may never be zero
|
2016-10-23 05:05:28 +02:00
|
|
|
print("monit_%s_%s.warning 1:" % (sanitize(process), stat))
|
2016-10-23 03:20:05 +02:00
|
|
|
else:
|
|
|
|
for process, stats in parse_processes().items():
|
|
|
|
for stat_key, stat_value in stats.items():
|
2016-10-23 05:05:28 +02:00
|
|
|
print("monit_%s_%s.value %s" % (sanitize(process), stat_key, stat_value))
|