#!/usr/bin/env python
# Templated Emails with included Graphs
# This script creates a very beautiful mail in multipart format with
# attached graphs and such neat stuff. Sweet!
#
# Argument 1: Full system path to the pnp4nagios index.php for fetching
# the graphs. Usually auto configured in OMD.
# Argument 2: HTTP-URL-Prefix to open multisite. When provided, several
# links are added to the mail.
import os, re, sys, subprocess, pystache
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.image import MIMEImage
opt_debug = '-d' in sys.argv
class GraphException(Exception):
pass
def prepare_contents(context):
renderer = pystache.Renderer(search_dirs=[
context["OMD_ROOT"] + "/local/share/check_mk/notifications/mailstache_templates",
context["OMD_ROOT"] + "/share/check_mk/notifications/mailstache_templates"
])
if context['WHAT'] == 'HOST':
tmpl_subj = renderer.load_template("host_subject")
tmpl_txt = renderer.load_template("host_txt")
tmpl_html = renderer.load_template("host_html")
else:
tmpl_subj = renderer.load_template("service_subject")
tmpl_txt = renderer.load_template("service_txt")
tmpl_html = renderer.load_template("service_html")
context["SUBJECT"] = renderer.render(tmpl_subj, context)
# Render text
result_txt = renderer.render(tmpl_txt, context)
# Change newlines to HTML
context["LONGHOSTOUTPUT"] = context["LONGHOSTOUTPUT"].replace("\\n", "
")
context["LONGSERVICEOUTPUT"] = context["LONGSERVICEOUTPUT"].replace("\\n", "
")
# Render HTML
result_html = renderer.render(tmpl_html, context)
return result_txt, result_html
def multipart_mail(target, subject, content_txt, content_html, attach = []):
m = MIMEMultipart('related', _charset='utf-8')
alt = MIMEMultipart('alternative')
# The plain text part
txt = MIMEText(content_txt, 'plain', _charset='utf-8')
alt.attach(txt)
# The html text part
html = MIMEText(content_html, 'html', _charset='utf-8')
alt.attach(html)
m.attach(alt)
# Add all attachments
for what, name, contents, how in attach:
if what == 'img':
part = MIMEImage(contents, name = name)
else:
part = MIMEApplication(contents, name = name)
part.add_header('Content-ID', '<%s>' % name)
# how must be inline or attachment
part.add_header('Content-Disposition', how, filename = name)
m.attach(part)
m['Subject'] = subject
m['To'] = target
return m
def send_mail(m, target):
p = subprocess.Popen(["/usr/sbin/sendmail", "-i", target ], stdin = subprocess.PIPE)
p.communicate(m.as_string())
return True
def fetch_pnp_data(context, params):
try:
# Autodetect the path in OMD environments
path = "%s/share/pnp4nagios/htdocs/index.php" % context['OMD_ROOT']
php_save_path = "-d session.save_path=%s/tmp/php/session" % context['OMD_ROOT']
except:
# Non-omd environment - use plugin argument 1
path = context.get('PARAMETER_1', '')
php_save_path = "" # Using default path
if not os.path.exists(path):
raise GraphException('Unable to locate pnp4nagios index.php (%s)' % path)
return os.popen('REMOTE_USER="%s" php %s %s "%s"' % (context['CONTACTNAME'], php_save_path, path, params)).read()
def fetch_num_sources(context):
svc_desc = context['WHAT'] == 'HOST' and '_HOST_' or context['SERVICEDESC']
infos = fetch_pnp_data(context, '/json?host=%s&srv=%s&view=0' %
(context['HOSTNAME'], svc_desc))
if not infos.startswith('[{'):
raise GraphException('Unable to fetch graph infos, got: "%s"' % infos)
return infos.count('source=')
def fetch_graph(context, source, view = 1):
svc_desc = context['WHAT'] == 'HOST' and '_HOST_' or context['SERVICEDESC']
graph = fetch_pnp_data(context, '/image?host=%s&srv=%s&view=%d&source=%d' %
(context['HOSTNAME'], svc_desc, view, source))
if graph[:8] != '\x89PNG\r\n\x1a\n':
raise GraphException('Unable to fetch the graph, got: "%s"' % graph)
return graph
def main():
# gather all options from env
context = dict([
(var[7:], value.decode("utf-8"))
for (var, value)
in os.environ.items()
if var.startswith("NOTIFY_")])
context['HOSTNOTES'] = os.environ.get("NAGIOS_HOSTNOTES")
context['HOSTNOTESURL'] = os.environ.get("NAGIOS_HOSTNOTESURL")
context['SERVICENOTES'] = os.environ.get("NAGIOS_SERVICENOTES")
context['SERVICENOTESURL'] = os.environ.get("NAGIOS_SERVICENOTESURL")
# Fetch graphs for this object. It first tries to detect how many sources
# are available for this object. Then it loops through all sources and
# fetches retrieves the images. If a problem occurs, it is printed to
# stderr (-> notify.log) and the graph is not added to the mail.
try:
num_sources = fetch_num_sources(context)
except GraphException, e:
sys.stderr.write('Unable to fetch graph infos: %s\n' % e)
num_sources = 0
# If argument 2 is given, we know the base url to the installation and can add
# links to hosts and services. ubercomfortable!
if context.get('PARAMETER_2'):
base_url = context['PARAMETER_2'].rstrip('/')
host_url = base_url + context['HOSTURL']
context['LINKEDHOSTNAME'] = '%s' % (host_url, context['HOSTNAME'])
context['HOSTLINK'] = '\nLink: %s' % host_url
if context['WHAT'] == 'SERVICE':
service_url = base_url + context['SERVICEURL']
context['LINKEDSERVICEDESC'] = '%s' % (service_url, context['SERVICEDESC'])
context['SERVICELINK'] = '\nLink: %s' % service_url
else:
context['LINKEDHOSTNAME'] = context['HOSTNAME']
context['LINKEDSERVICEDESC'] = context.get('SERVICEDESC', '')
context['HOSTLINK'] = ''
context['SERVICELINK'] = ''
attachments = []
graph_code = ''
for source in range(0, num_sources):
try:
content = fetch_graph(context, source)
except GraphException, e:
sys.stderr.write('Unable to fetch graph: %s\n' % e)
continue
if context['WHAT'] == 'HOST':
svc_desc = '_HOST_'
else:
svc_desc = context['SERVICEDESC'].replace(' ', '_')
# replace forbidden windows characters < > ? " : | \ / *
for token in ["<", ">", "?", "\"", ":", "|", "\\", "/", "*"] :
svc_desc = svc_desc.replace(token, "x%s" % ord(token))
name = '%s-%s-%d.png' % (context['HOSTNAME'], svc_desc, source)
attachments.append(('img', name, content, 'inline'))
context['GRAPH_%d' % source] = name
graph_code += '' % name
if graph_code:
context['GRAPH_CODE'] = (
'