Check_MK mit SMS Notifikation über SMSEagle
Das Python Skript dient dem Versenden von SMS Meldungen von Check_MK mittels SMSEagle Geräten. Eine SMS wird nur dann versendet, wenn der Benutzer eine gültige Telefonnummer als Pager-Adresse eingetragen hat und sie auf die PHONE_REGEX passt. Vorsicht beim Kopieren von Python-Code, da bei dieser Skriptsprache die Logik aufgrund von Texteinzügen basiert, was anfällig ist. Auch ändern sich Syntax und Bibliotheksnamen mit verschiedenen Python-Versionen. Das war mein erstes Python-Skript um mich mit dieser Sprache vertraut zu machen, von der heutzutage jeder zu schwärmen scheint.
Mehr Details zu Check_MK und SMSEagle:
Skript
Aktuellste Version aus dem Github Repository: github.com/nies-ch/smseagle-check_mk
#!/usr/bin/env python3
# =============================================================================
# NOTIFY VIA SMS USING SMSEAGLE FAILOVER
# =============================================================================
import json
import urllib.request
import urllib.parse
import smtplib
import re
import sys
import socket
from os import environ
from email.mime.text import MIMEText
# -----------------------------------------------------------------------------
# Configuration Parameters in JSON file
# -----------------------------------------------------------------------------
CONFIG_FILE = environ['HOME'] + '/.notify_smseagle.json'
# -----------------------------------------------------------------------------
# read_jsonfile
# -----------------------------------------------------------------------------
def read_jsonfile(file):
data = []
with open(file) as json_file:
data = json.load(json_file)
# Defaults
data["eagle_timeout"] = 10 if not "eagle_timeout" in data else data["eagle_timeout"]
return data
# ----------------------------------------------------------------------------
# Complain
# ----------------------------------------------------------------------------
def complain(error):
"""
Complain about errors via email. If that fails, just print the error
message to stdout.
"""
print(error)
msg = MIMEText(error)
msg['To'] = cfg['mail_to']
msg['From'] = cfg['mail_from']
msg['Subject'] = 'Check_MK: SMS Notification Error'
MessageSent = False
for mail_host in cfg['mail_hosts']:
if not MessageSent:
try:
server = smtplib.SMTP(mail_host['host'], mail_host['port'])
server.sendmail(cfg['mail_from'], cfg['mail_to'], msg.as_string())
server.quit()
except socket.error as e:
print("Could not connect to " + mail_host['host'] + ": " + str(e))
except smtplib.SMTPException as e:
print("Sending email failed: " + str(e))
except:
print("Unknown error:", sys.exc_info()[0])
else:
MessageSent = True
break
return
# ----------------------------------------------------------------------------
# Format Message
# ----------------------------------------------------------------------------
def format_message():
"""
Format the SMS message using the environment variables given by Check_MK.
See https://mathias-kettner.com/cms_notifications.html for details.
"""
if 'NOTIFY_WHAT' in environ:
if environ['NOTIFY_WHAT'] == 'HOST':
msg = "%s %s: %s (%s)" % (
environ['NOTIFY_NOTIFICATIONTYPE'],
environ['NOTIFY_HOSTNAME'],
environ['NOTIFY_HOSTOUTPUT'],
environ['NOTIFY_SHORTDATETIME'])
elif environ['NOTIFY_WHAT'] == 'SERVICE':
msg = "%s %s: %s %s (%s)" % (
environ['NOTIFY_NOTIFICATIONTYPE'],
environ['NOTIFY_HOSTNAME'],
environ['NOTIFY_SERVICEDESC'],
environ['NOTIFY_SERVICEOUTPUT'],
environ['NOTIFY_SHORTDATETIME'])
else:
msg = "Unknown notification method: " + environ['NOTIFY_WHAT']
else:
msg = "Environment variable NOTIFY_WHAT not defined."
return msg
# ----------------------------------------------------------------------------
# Send Eagle SMS
# ----------------------------------------------------------------------------
def send_eagle_sms(to, message):
"""
Sending SMS via SMSEagle HTTP API. Uses hosts defined in list cfg['eagle_hosts'].
Upon failure an email with the error is sent and next host is used.
"""
MessageSent = False
ErrorMessage = ''
for eagle_host in cfg['eagle_hosts']:
query_args = {
'to': to,
'message': message }
if 'access_token' in eagle_host:
query_args['access_token'] = eagle_host['access_token']
else:
query_args['login'] = eagle_host['login']
query_args['pass'] = eagle_host['pass']
encoded_args = urllib.parse.urlencode(query_args)
url = eagle_host['api_send_sms'] + '?' + encoded_args
if not MessageSent:
try:
result = urllib.request.urlopen(url, None, cfg['eagle_timeout']).read()
except urllib.request.HTTPError as e:
complain('Sending SMS via SMSEagle %s failed: %s'
% (eagle_host['api_send_sms'], str(e.code)))
except urllib.request.URLError as e:
complain('Sending SMS via SMSEagle %s failed: %s'
% (eagle_host['api_send_sms'], str(e.args)))
else:
if result.startswith(b'OK;'):
MessageSent = True
print('SMS successfully sent via %s to %s.' % (eagle_host['api_send_sms'], to))
break
else:
MessageSent = False
complain('Sending SMS via SMSEagle %s failed: %s'
% (eagle_host['api_send_sms'], result.rstrip()))
return
# ----------------------------------------------------------------------------
# Main
# ----------------------------------------------------------------------------
cfg = read_jsonfile(CONFIG_FILE)
if not 'NOTIFY_CONTACTPAGER' in environ:
complain('Environment variable NOTIFY_CONTACTPAGER missing')
else:
phone_number = environ['NOTIFY_CONTACTPAGER']
if re.match(cfg['phone_regex'], phone_number):
eagle_message = format_message()
send_eagle_sms(phone_number, eagle_message)