Check_MK with SMS Notification using SMSEagle

The following Python script can be used for Check_MK to send SMS alerts using SMSEagle devices. Just copy it as site user into the folder ~/local/share/check_mk/notifications and make it executeable. Further details can be found here: Check_MK Notifications and SMS Eagle API.

su - mysite
cp /var/tmp/notify_smseagle ~/local/share/check_mk/notifications
chmod 755 ~/local/share/check_mk/notifications/notify_smseagle
omd reload

A short message will only be sent, when the user has entered a valid phone number as pager address, according to PhoneRegex. Be careful when copying the Python code, because that language highly depends on how the block indentation with white space is done.

#!/usr/bin/env python
# SMS (using SMSEagle failover)

"""
Check_MK SMS Notification
=========================

Alerting via multiple SMSEagle devices, defined in EagleHosts. Uses PhoneNumber
as fallback for sending SMS when NOTIFY_CONTACTPAGER is not defined. If all
SMSEagle hosts fail to send the SMS, the alert is sent to MailTo.

Changelog:
----------
2018-09-05: Try multiple mail servers. Restrict mobile number to +41 or 0041.
2018-08-28: Don't send if NOTIFY_CONTACTPAGER is invalid format. 
2018-08-27: Added NOTIFY_NOTIFICATIONTYPE.
2018-08-23: First release
"""

import urllib
import urllib2
import smtplib
import re
import sys
import socket
from os import environ
from email.mime.text import MIMEText



### Configuration Parameters

EagleHosts    = [ '1.2.3.4', '5.6.7.8', '9.10.11.12' ]
EagleLogin    = 'myuser'
EaglePassword = 'mypassword'
PhoneRegex    = '^(\+|00)41\d+$'

MailFrom      = 'monitoring@example.com'
MailTo        = 'monitoring@example.com'
MailHosts     = [ 'localhost', 'smtp1.example.com', 'smtp2.example.com' ]
MailPort      = 25


# ----------------------------------------------------------------------------
# Complain 
# ----------------------------------------------------------------------------

def complain(error):
    print error
    msg = MIMEText(error)
    msg['To'] = MailTo
    msg['From'] = MailFrom
    msg['Subject'] = 'Check_MK: SMS Notification Error'
    MessageSent  = False

    for host in MailHosts:
        if not MessageSent:
            try:
                server = smtplib.SMTP(host, MailPort)
                server.sendmail(MailFrom, MailTo, 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:
                MessageSent = True
                break
    return



# ----------------------------------------------------------------------------
# Format Message 
# ----------------------------------------------------------------------------

def FormatMessage():
    """
    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 sendEagleSMS(to,message):
    """
    Sending SMS via SMSEagle HTTP API. Uses hosts defined in list EagleHosts.
    Upon failure an email with the error is sent and next host is used.
    """
    query_args   = { 'login':EagleLogin, 'pass':EaglePassword, 'to':to,
                     'message':message }
    encoded_args = urllib.urlencode(query_args)
    MessageSent  = False
    ErrorMessage = ''

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



# ----------------------------------------------------------------------------
# Main
# ----------------------------------------------------------------------------

if not 'NOTIFY_CONTACTPAGER' in environ:
    complain('Environment variable NOTIFY_CONTACTPAGER missing')
else:
    PhoneNumber = environ['NOTIFY_CONTACTPAGER']
    if re.match(PhoneRegex, PhoneNumber):
        EagleMessage = FormatMessage()
        sendEagleSMS(PhoneNumber, EagleMessage)