Check_MK with SMS Notification using SMSEagle

The following Python script can be used for Check_MK to send SMS alerts using SMSEagle devices. A short message will only be sent, when the user has entered a valid phone number as pager address, according to PHONE_REGEX. Be careful when copying the Python code, because that language highly depends on how the block indentation with white space is done. Also syntax and library names change with different Python versions. It was my first Python script to learn that language.

Further details about Check_MK and SMSEagle:

Installation

cd /tmp
git clone https://github.com/nies-ch/smseagle-check_mk
su - mysite
cp /tmp/smseagle-check_mk/notify_smseagle.py ~/local/share/check_mk/notifications
chmod 755 ~/local/share/check_mk/notifications/notify_smseagle.py
omd reload

Script

Latest version from Github repository: github.com/nies-ch/smseagle-check_mk

#!/usr/bin/env python3

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

EAGLE_HOSTS    = [ '1.2.3.4', '5.6.7.8', '9.10.11.12' ]
EAGLE_LOGIN    = 'eagleuser'
EAGLE_PASSWORD = 'eaglepassword'
EAGLE_TIMEOUT  = 10
PHONE_REGEX    = '^(\+|00)41\d+$'
MAIL_FROM      = 'check_mk@example.com'
MAIL_TO        = 'my-email@example.com'
MAIL_HOSTS     = [ 'localhost', 'smtp1.example.com', 'smtp2.example.com' ]
MAIL_PORT      = 25


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'] = MAIL_TO
    msg['From'] = MAIL_FROM
    msg['Subject'] = 'Check_MK: SMS Notification Error'
    message_sent  = False

    for host in MAIL_HOSTS:
        if not message_sent:
            try:
                server = smtplib.SMTP(host, MAIL_PORT)
                server.sendmail(MAIL_FROM, MAIL_TO, msg.as_string())
                server.quit()
            except socket.error as e:
                print("Could not connect to " + host + ": " + str(e))
            except smtplib.SMTPException as e:
                print("Sending email failed: " + str(e))
            except:
                print("Unknown error:", sys.exc_info()[0])
            else:
                message_sent = True
                break
    return


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


def send_eagle_sms(to,message):
    """
    Sending SMS via SMSEagle HTTP API. Uses hosts defined in list EAGLE_HOSTS.
    Upon failure an email with the error is sent and next host is used.
    """
    query_args   = { 'login':EAGLE_LOGIN, 'pass':EAGLE_PASSWORD, 'to':to,
                     'message':message }
    encoded_args = urllib.parse.urlencode(query_args)
    message_sent  = False

    for host in EAGLE_HOSTS:
        url =  'http://%s/index.php/http_api/send_sms?%s' % (host, encoded_args)
        if not message_sent:
            try:
                result = urllib.request.urlopen(url,None,EAGLE_TIMEOUT).read()
            except urllib.request.HTTPError as e:
                complain('Sending SMS via SMSEagle %s failed: %s' 
                          % (host, str(e.code))) 
            except urllib.request.URLError as e:
                complain('Sending SMS via SMSEagle %s failed: %s'
                          % (host, str(e.args)))
            else:    
                if result.startswith('OK;'):
                    message_sent = True
                    print('SMS successfully sent via %s to %s.' % (host, to))
                    break
                else:
                    message_sent = False
                    complain('Sending SMS via SMSEagle %s failed: %s' 
                             % (host, result.rstrip()))
            
    return


if not 'NOTIFY_CONTACTPAGER' in environ:
    complain('Environment variable NOTIFY_CONTACTPAGER missing')
else:
    phone_number = environ['NOTIFY_CONTACTPAGER']
    if re.match(PHONE_REGEX, phone_number):
        eagle_message = format_message()
        send_eagle_sms(phone_number, eagle_message)