Nagios Meldungen über Growl

Growl ist eine kleine OS X App mit der man sich Status Informationen von verschiedenen Programmen anzeigen lassen kann. Growl ist hauptsächlich auf lokale Prozesse fokusiert bietet aber auch die Möglichkeit Meldungen über das Netzwerk zu empfangen. Tao of Mac hat dazu passend etwas PHP Code veröffentlicht um aus Webanwendungen Growl Nachrichten verschicken zu können, daraus kann man sehr schnell etwas machen womit dann auch Nagios umgehen kann.

Die Skripte

netgrowl.php

Die Version von Tao of Mac konnte ich leider nicht 1:1 übernommen, sondern musste um ein paar Zeilen kürzen, die Datei liegt bei mir unter /usr/local/lib/netgrowl.php

<?
define( 'GROWL_UDP_PORT', 9887 );
define( 'GROWL_PROTOCOL_VERSION', 1 );
define( 'GROWL_TYPE_REGISTRATION', 0 );
define( 'GROWL_TYPE_NOTIFICATION', 1 );
 
class GrowlRegistrationPacket { // {{{
  var $m_szApplication;
  var $m_aNotifications;
  var $m_szPassword;
  var $m_szData;
 
  function GrowlRegistrationPacket(
    $szApplication = "growlnotify",
    $szPassword = "" ) {
 
    $this->m_szApplication  = utf8_encode($szApplication);
    $this->m_szPassword     = $szPassword;
    $this->m_aNotifications = array();
  } // GrowlRegistrationPacket
 
  function addNotification(
    $szNotification = "Command-Line Growl Notification",
    $bEnabled = True) {
 
    $this->m_aNotifications[$szNotification] = $bEnabled;
  } // addNotification
 
  function payload() {
    $szEncoded = $szDefaults = "";
    $nCount = $nDefaults = 0;
    foreach( $this->m_aNotifications as $szName => $bEnabled ) {
      $szName = utf8_encode( $szName );
      $szEncoded .= pack( "n", strlen($szName) ) . $szName;
      $nCount++;
      if( $bEnabled ) {
        $szDefaults .= pack( "c", $nCount-1 );
        $nDefaults++;
      }
    }
    $this->m_szData = pack( "c2nc2",
                            GROWL_PROTOCOL_VERSION,
                            GROWL_TYPE_REGISTRATION,
                            strlen($this->m_szApplication),
                            $nCount,
                            $nDefaults );
    $this->m_szData .= $this->m_szApplication . $szEncoded . $szDefaults;
 
    if( $this->m_szPassword )
       $szChecksum = pack( "H32", md5( $this->m_szData . $this->m_szPassword ) );
    else
       $szChecksum = pack( "H32", md5( $this->m_szData ));
    $this->m_szData .= $szChecksum;
    return $this->m_szData;
  } // payload
} // GrowlNotificationPacket }}}
 
class GrowlNotificationPacket { // {{{
  var $m_szApplication;
  var $m_szNotification;
  var $m_szTitle;
  var $m_szDescription;
  var $m_szData;
 
  function GrowlNotificationPacket(
    $szApplication = "growlnotify",
    $szNotification =  "Command-Line Growl Notification",
    $szTitle = "Title",
    $szDescription = "Description",
    $nPriority = 0,
    $bSticky = False,
    $szPassword = "" ) {
 
    $this->m_szApplication  = utf8_encode($szApplication);
    $this->m_szNotification = utf8_encode($szNotification);
    $this->m_szTitle        = utf8_encode($szTitle);
    $this->m_szDescription  = utf8_encode($szDescription);
 
    $nFlags = ($nPriority & 7) * 2;
    if( $nPriority < 0 )
      $nFlags |= 8;
    if( $bSticky )
      $nFlags |= 256;
    $this->m_szData = pack( "c2n5",
                            GROWL_PROTOCOL_VERSION,
                            GROWL_TYPE_NOTIFICATION,
                            $nFlags,
                            strlen($this->m_szNotification),
                            strlen($this->m_szTitle),
                            strlen($this->m_szDescription),
                            strlen($this->m_szApplication) );
    $this->m_szData .= $this->m_szNotification;
    $this->m_szData .= $this->m_szTitle;
    $this->m_szData .= $this->m_szDescription;
    $this->m_szData .= $this->m_szApplication;
    if( $szPassword )
       $szChecksum = pack( "H32", md5( $this->m_szData . $szPassword ) );
    else
       $szChecksum = pack( "H32", md5( $this->m_szData ));
    $this->m_szData .= $szChecksum;
  } // GrowlNotificationPacket
 
  function payload() {
    return $this->m_szData;
  } // payload
} // GrowlNotificationPacket }}}
?>

Das original netgrowl.php wurde unter einer BSD Lizenz veröffentlicht.

nagios_reg_growl.php

Die Datei muss für jeden neuen Client einmal von Hand ausgeführt werden: „nagios_reg_growl.php “. Damit wird die App „Nagios“ bei Growl registriert und so können auf dem Client dann noch einige Einstellungen zu den einzelnen Nachrichten Typen hinterlegt werden.

Bei mir liegt die Datei unter /usr/local/bin/nagios_reg_growl.php

#!/usr/bin/php
<?
require_once("/usr/local/lib/netgrowl.php");
 
$s = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
$p = new GrowlRegistrationPacket("Nagios", $_SERVER['argv'][2]);
 
// $SERVICESTATE$
$p->addNotification("OK");
$p->addNotification("WARNING");
$p->addNotification("UNKNOWN");
$p->addNotification("CRITICAL");
 
// $HOSTSTATE$
$p->addNotification("UP");
$p->addNotification("DOWN");
$p->addNotification("UNREACHABLE");
 
$szBuffer = $p->payload();
 
socket_sendto( $s, $szBuffer, strlen($szBuffer), 0x100, $_SERVER['argv'][1], GROWL_UDP_PORT );
?>

nagios_send_growl.php

Das ist jetzt das Script das die eigentliche Arbeit macht: „nagios_send_growl.php “.

Bei mir liegt das Script dann unter /usr/local/bin/nagios_send_growl.php

#!/usr/bin/php
<?
require_once("/usr/local/lib/netgrowl.php");
 
$s = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
 
$p = new GrowlNotificationPacket("Nagios", $_SERVER['argv'][3], $_SERVER['argv'][4], $_SERVER['argv'][5], -2, True, $_SERVER['argv'][2] );
$szBuffer = $p->payload();
socket_sendto( $s, $szBuffer, strlen($szBuffer), 0x100, $_SERVER['argv'][1], GROWL_UDP_PORT );
socket_close( $s );
?>

Nagios Konfiguration

Wenn alle Skripte funktionieren und die Registrierung auf dem Growl Client funktioniert hat, fehlt nur noch die Einbindung in Nagios.

commands.cfg

define command {
        command_name    notify-by-growl
        command_line    /usr/local/bin/nagios_send_growl.php $CONTACTADDRESS2$ $SERVICESTATE$ "$HOSTALIAS$ $SERVICEDESC$ $SERVICESTATE$" "Notification Type: $NOTIFICATIONTYPE$ Service: $SERVICEDESC$ Address: $HOSTALIAS$ / $HOSTADDRESS$"
        }
 
define command {
        command_name    host-notify-by-growl
        command_line    /usr/local/bin/nagios_send_growl.php $CONTACTADDRESS2$ $HOSTSTATE$ "$HOSTALIAS$ $SERVICEDESC$ $SERVICESTATE$" "Notification Type: $NOTIFICATIONTYPE$ Host: $HOSTALIAS$ State: $HOSTSTATE$ for $HOSTDURATION$ Address: $HOSTADDRESS$"
        }

contacts.cfg

Bei jedem Kontakt der per Growl informiert werden will müssen dann noch folgen Anpassungen gemacht werden:

service_notification_commands     notify-by-growl,.....
host_notification_commands        host-notify-by-growl,.....
address2                          <IP des Rechners mit Growl> <Growl Passwort>

Im Beispiel habe ich jetzt „address2“ verwendet, prinzipel gehten alle sechs adress? Makros, bei einer Änderung sollte man nur darauf achten das auch die beiden by-growl Kommandos angepasst werden..