Erfahrungsbericht eines hessischen Bayern :)
Mobiltelefone sind ne schöne Sache, vor allem wenn man den Sysadmin erreichen will *G*
Und nachdem unser Nagios wächst, gedeiht und immer mehr an Bedeutung im Unternehmen gewonnen hat, muss ein ordentliche Lösung für die Alarmierung von Bereitschaftsdiensten, Eskalationen etc. implementiert werden um die Krawattenträge sanft zu stimmen.
Nagios kann das meiste schon, lediglich den direkten Kontakt zu Mobiltelefonen hat es bisher gescheut … das ändern wir jetzt.
Nachdem ich für 150 € ein GSM Modem beim Händler meines Vertrauens erstanden habe (Falcom SAMBA 55 USB) mache ich mich dran und besorge mir die SMSTOOLS von Stefan Frings.
Info: SMS Server Tools is originally created by Mr. Stefan Frings.
Developing of version 2.x is freezed couple of years ago. Bugs are fixed if any critical one found.
Current and actively developed version is SMSTOOLS3 by Mr. Keijo „Keke“ Kasvi.
Von Falcom gibts auch noch GSM Modems die mit serieller Schnittstelle angeboten werden, sind zwar teuerer als die USB Geräte, dafür hat fast jedes OS Support für COM Ports, und mann muss sich nich mit USB Treibern rumschlagen.
Info: Es gibt mehrere Samba Modems .. ich hab das Samba 55 benutzt, das ist das Triband ding. Das 75er (Quadband) benutzt nen andern Chip für die USB Kommunikation und funzt anscheinend ned so unter Linux.
Evtl kann man mal bei Falcom anfragen was Sie auf die Idee gebracht hat mal wieder was zu ändern an Ihren Produkten.
Noch ne Info: Der Support für das Falcom Samba 55 ist per Default erst ab Kernel 2.6.14 im Mainstream Kernel enthalten. Wenn Ihr's mit ne früheren Version versucht, müsst ihr das ftdi_sio Modul patchen und neu backen … Vendor ID 0x0f94, Product ID 0x0005 müssen noch in das Modul eingebaut werden. Mit minimalen C Kenntnissen absolut kein Problem ;)
Kaum ist der Source ausgepackt wird er per
make -s
compiled und per
make -s install
unter /usr/local/bin/ installiert.
Ich lege nun noch das Config file unter /etc/smsd.conf ab, das ich wie folgt zusammengebastelt habe:
Man beachte das man hier seine eigene pin benutzen muss !
devices = GSM1 logfile = /var/log/smsd.log loglevel = 5 whitelist = /etc/sms-users eventhandler= /usr/local/bin/sms_incoming.pl sent = /var/spool/sms/sent [GSM1] device = /dev/ttyUSB0 incoming = yes cs_convert = yes pin = 0000 mode = nw baudrate = 115200 rtscts = yes
Und lege noch eine „Whitelist“ mit erlaubten SMS Empfängern an, schliesslich soll ja nicht jeder hier rum sms'en :)
[basti@lnx024200209 bin]# cat /etc/sms-users # SMS Server Config @ 01.09.05 - 16:21 # # do not edit, this file is script generated !! ### BEGIN USERs ### 4916327xyz # Sebastian Schubert OA-SM-NS
Die Initstrings für die Verschiedenen GSM Modems sind in der Hardwareliste auf Stefan Frings Seite http://www.meinemullemaus.de/smstools/hardwarecomp.html zu finden.
Da ich unter meiner Distri (CentOS) alle Runlevelscripte mit chkconfig verwalte, erstelle ich mir noch ein chkconfig-Konformes initscript das ich unter /etc/init.d/sms ablege
[root@lnx024200209 bin]# cat /etc/init.d/sms #! /bin/sh # chkconfig: 345 99 01 # description: SMS Tools Daemon # This script can be used to start/stop smsd # as a daemon in Linux and Solaris. case "$1" in start) find /var/spool/sms -name '*.LOCK' -exec rm {} \; /usr/local/bin/smsd & ;; stop) pkill smsd ;; restart|reload) $0 stop $0 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac
Wenn ich nun mit chkconfig –add sms das Initscript registriere, kann ich per service sms start meine SMSTOOLS loslaufen lassen.
Wenn nun der smsd läuft können wir versuchen eine SMS abzuschicken
/usr/local/bin/sendsms 49163276xxx 'Testsms'
Kurz darauf sollte in /var/log/smsd.log eine Zeile auftauchen die in etwa so aussieht
2005-09-15 17:02:40,5,putsms (GSM1): SMS sent, To: 49163276xxx
Und das Taschentelefon sollte dir deinen „Lieblings Jamba SMS Ton“ vordüdeln
Jetzt machen wir uns dran Nagios das simsen beizubringen und editieren mit unserem Lieblingseditor die $NAGIOSDIR/etc/misccommands.cfg und fügen folgendes hinzu:
# 'notify-by-sms' command definition
define command{
command_name notify-by-sms
command_line /usr/local/bin/sms_nagios.pl $CONTACTEMAIL$ '$SERVICEDESC$ auf $HOSTNAME$ State: $SERVICESTATE$ @$DATETIME$ Info: $OUTPUT$'
}
# 'host-notify-by-sms' command definition
define command{
command_name host-notify-by-sms
command_line /usr/local/bin/sms_nagios.pl $CONTACTEMAIL$ "Host $HOSTALIAS$ is $HOSTSTATE$ @$DATETIME$ Info: $OUTPUT$"
}
Dann legen wir uns im Nagios einen Contact an, der zu jeder Tages- und Nachtzeit (24×7) gern SMS erhält.
# 'Basti-Handy' contact definition
define contact{
contact_name basti
alias Basti-Handy
service_notification_period 24x7
host_notification_period 24x7
service_notification_options w,u,c,r
host_notification_options d,u,r
service_notification_commands notify-by-sms
host_notification_commands host-notify-by-sms
email 49163276xxx
}
Man beachte das die Handynummer im Feld email steht und die notification commands auf unsere kürzlich angelegten xxx-notfiy-by-sms verweisen.
Bevor wir jetzt nagios HUP'en (Neustarten für die die catdie mit kill -l nix anfagen können) sollten wir aber mal genau schauen was wir da im misccommand angegeben haben … ganz richtig - ein Perlscript ?!?
Warum werden Perl Scripts benutzt um Handlen der SMS und nicht direkt sendsms angefeuert um die SMS zu versenden?
Naja.. wenn ich bei einem Massenausfall mit SMS zugebombt werde.
Daher habe ich mir einen Wrapper gebaut, der den SMS Status für mein Handy in einer Datenbank erfasst und dann entscheidet ob ich eine SMS bekomme oder nicht.
Abgesehn davon ist bei uns halt Perl als Standard für solche codings definiert
#!/usr/bin/perl -w # hier einstellen nach wie vielen sekunden der flood lock entfernt werden soll my $numsec='300'; # 5minuten #Declaration of Perl Modules to use. use strict; use DBI; use DBD::mysql; use Net::SMTP; #Declaration of used Constants/Variables my ($msg_body, $msg_sender , $msg_rcpt, $sthm, $sql, @row, $sthm2, @lockedrow, $sql_todo, $smtp); #check ob wir richtig aufgerufen werden: die unless ( scalar(@ARGV)==2 ) ; #Database Setup #mysql server my $DBuser="sms"; my $DBpass="xxx"; my $dbhm=DBI->connect("dbi:mysql:smsd:localhost","$DBuser","$DBpass", { PrintError => 1, } ); unless ( $dbhm ){ die("connection funzt ned!"); } my $dbhm2=DBI->connect("dbi:mysql:smsd:localhost","$DBuser","$DBpass", { PrintError => 1, } ); ## end database #main - read incoming sms message and queue it to smsd $msg_sender="nagios"; $msg_rcpt=shift(); $msg_body=shift(); my $msg_body_160 = substr($msg_body,0,160); ## delete old flood lock $sql = "DELETE FROM floodprotection WHERE lastsend < DATE_SUB(now(),INTERVAL $numsec SECOND)"; $sthm=$dbhm->prepare($sql); $sthm->execute(); $sql_todo="SELECT count(*) as counter FROM floodprotection WHERE phonenumber = $msg_rcpt "; $sthm2=$dbhm2->prepare($sql_todo); $sthm2->execute(); @lockedrow=$sthm2->fetchrow_array(); unless ($msg_body =~ m/SMS Ack/g) { # Wichtig damit SMS Ack's zurück kommen exit if ($lockedrow[0] == 1) ; } # now send the sms's system("/usr/local/bin/sendsms $msg_rcpt '$msg_body_160'"); # sms sent set up the flood lock $sql_todo ="INSERT INTO floodprotection values ( '' , $msg_rcpt , now() ) "; $sthm2=$dbhm2->prepare($sql_todo); $sthm2->execute();
Der Datenbank Table wird wie folgt angelegt:
CREATE TABLE floodprotection ( id int(10) NOT NULL AUTO_INCREMENT, phonenumber bigint(15) NOT NULL DEFAULT '0', lastsend timestamp(14) NOT NULL, PRIMARY KEY (id), UNIQUE KEY phonenumber (phonenumber) ) TYPE=MyISAM;
Schön .. jetzt bekommen wir hoffentlich unsere SMS .. aber wäre es nicht schön wenn ich per SMS gleich auf den Alert ragieren kann ??
Können wir .. SMSTOOLS nimmt für uns freundlicherweise alles SMS entgegen und wenn wir wollen kann es sogar gleich ein Programm zur Verarbeitung starten - wir haben das in unserer Config ja schon fertig eingetragen.
eventhandler= /usr/local/bin/sms_incoming.pl
hies es ja in der /etc/smsd.conf.
Damit bei uns die Revision auch immer alles schön nachvollziehen kann, wird jede gesendete und empfangen SMS in einer DB abgelegt - schliesslich SMS't bei uns nicht nur Nagios
Das macht bei uns das sms_incoming.pl
#!/usr/bin/perl -w #Declaration of Perl Modules to use. use strict; use DBI; use DBD::mysql; #Declaration of used Constants/Variables my ($msg_body, $msg_sender , $msg_rcpt, $sthm, $sql, $name, $msg_ts, $msg_ts1); #Database Setup #mysql server my $DBuser="sms"; my $DBpass="xxxxxx"; my $dbhm=DBI->connect("dbi:mysql:smsd:localhost","$DBuser","$DBpass", { PrintError => 1, } ); unless ( $dbhm ){ die("connection funzt ned!"); } my $dbhm2=DBI->connect("dbi:mysql:smsd:localhost","$DBuser","$DBpass", { PrintError => 1, } ); # check for incoming sms: opendir(DIR,"/var/spool/sms/incoming") or die "Can't open the current directory: $!\n"; my @names = readdir(DIR) or die "Unable to read current dir:$!\n"; closedir(DIR); foreach $name (@names) { next if ($name eq "."); # skip the current directory entry next if ($name eq ".."); # skip the parent directory entry if ($name =~ m/GSM/) { # is this a file named "core"? open(SMS,"/var/spool/sms/incoming/$name"); while (<SMS>) { chomp; if ($_ =~ /^From:/) { $msg_sender=$_; $msg_sender=~ s/^From://g; $msg_sender=~ s/^\s+//g; next; } if ($_ =~ /^Sent:/) { $msg_ts=$_; $msg_ts=~ s/^Sent://g; $msg_ts=~ s/^\s+//g; next; } if ($_ =~ /^Received:/) { $msg_ts1=$_; $msg_ts1=~ s/^Received://g; $msg_ts1=~ s/^\s+//g; next; } next if ($_ =~ /^From_SMSC/); next if ($_ =~ /^Subject/); next if ($_ =~ /^Received/); next if ($_ =~ /^$/); $msg_body=$_ ; } close(SMS); system("mv /var/spool/sms/incoming/$name /var/spool/sms/processed_incoming/$name"); $sql = "INSERT INTO sms_log (type, sent, received, sender, receiver, msgtext) VALUES ('received', '$msg_ts' , '$msg_ts1' , '$msg_sender' , 'MNSS' , '$msg_body' )"; $sthm=$dbhm->do($sql); } } exit;
Die Tabelle wurde wie folgt angelegt:
CREATE TABLE `sms_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `type` varchar(16) DEFAULT NULL, `sent` datetime DEFAULT NULL, `received` datetime DEFAULT NULL, `sender` varchar(255) DEFAULT NULL, `receiver` varchar(255) DEFAULT NULL, `status` char(3) DEFAULT NULL, `msgid` char(3) DEFAULT NULL, `msgtext` varchar(160) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) TYPE=MyISAM ;
Ein Cronjob liest nun die unbearbeiteten Incoming sms aus der Datenbank und sucht sich die raus, die Nagios betreffen.
Danach führt es die gewünschte Aktion aus.
Anmerkung: Nachdem unsere ganze Nagios Config, die Personaldaten etc. alle per SQL abfragbar sind, können wir nun abfragen wem die Handynummer gehört und entsprechend ein ACK ausführen. Bitte beachtet, das je nach euerer Implementierung (Config in SQL oder in Flatfiles) ein Script zum Acknoledgen ganz anders gestrickt sein kann/muss !! Dieses Script ist nur ein Beispiel wie es bei uns funktioniert ;)
#!/usr/bin/perl -w # User def. Vars my $comment='SMS Acknoledgement by'; my $nagios_cmd = "/usr/local/nagios/var/rw/nagios.cmd"; #Declaration of Perl Modules to use. use strict; use DBI; use DBD::mysql; #Declaration of used Constants/Variables my ($msg_body, $msg_sender , $msg_rcpt, $sthm, $sql, @row, $sthm2, @row2, $sql_todo, $smtp, $name, $msg_ts, $msg_ts1, $hostname, $service, $acked); #Database Setup #mysql server my $DBuser="sms"; my $DBpass="xxxxxx"; my $dbhm=DBI->connect("dbi:mysql:smsd:localhost","$DBuser","$DBpass", { PrintError => 1, } ); unless ( $dbhm ){ die("connection funzt ned!"); } my $dbhm2=DBI->connect("dbi:mysql:smsd:localhost","$DBuser","$DBpass", { PrintError => 1, } ); # check for users that may have sent an sms: $sql = "SELECT a.id, a.sender FROM smsd.sms_log a, nagios_config.contacts b WHERE a.type = 'received' AND a.status IS NULL AND a.sender = b.email"; $sthm=$dbhm->prepare($sql); $sthm->execute(); while (@row = $sthm->fetchrow_array() ) { # check the pending sms's $sql_todo = "SELECT msgtext FROM smsd.sms_log WHERE id = $row[0]"; $sthm2=$dbhm2->prepare($sql_todo); $sthm2->execute(); @row2=$sthm2->fetchrow_array(); $msg_body=$row2[0]; $sql_todo = "SELECT DISTINCT a.persnr_kovo,a.vname, a.name FROM mita.names a, smsd.aliases b WHERE a.persnr_kovo = b.persnr and b.mobilenumber = $row[1] "; $sthm2=$dbhm2->prepare($sql_todo); $sthm2->execute(); @row2=$sthm2->fetchrow_array(); my $vnam=$row2[2]; my $nam=$row2[1]; my $persnr=$row2[0]; # now process the message: next unless ($msg_body =~ /ack/i); # host: if ($msg_body =~ m/^Ack Host .* is/i) { $msg_body=~ /^Ack Host (.*) is .*/i; $hostname=$1; $sql_todo="SELECT DISTINCT host_name FROM nagios_config.hosts WHERE alias = '$hostname'"; $sthm2=$dbhm2->prepare($sql_todo); $sthm2->execute(); @row2=$sthm2->fetchrow_array(); my $host=$row2[0]; open(CMD,">>".$nagios_cmd); print CMD "[".time()."] ADD_HOST_COMMENT;$host;1;$vnam $nam;ACKNOLEDGEMENT: $comment $vnam $nam\n"; print CMD "[".time()."] ACKNOWLEDGE_HOST_PROBLEM;$host;1;$comment $vnam $nam\n"; close(CMD); $acked="1"; } #service : if ($msg_body =~ m/State:/i) { $msg_body=~ /^Ack (.*) auf (.*) State:.*/; $service=$1; $hostname=$2; $sql_todo="SELECT DISTINCT host_name FROM nagios_config.hosts WHERE alias = '$hostname'"; $sthm2=$dbhm2->prepare($sql_todo); $sthm2->execute(); @row2=$sthm2->fetchrow_array(); my $host=$row2[0]; open(CMD,">>".$nagios_cmd); print CMD "[".time()."] ADD_SVC_COMMENT;$host;$service;1;$vnam $nam;ACKNOLEDGEMENT: $comment $vnam $nam\n"; print CMD "[".time()."] ACKNOWLEDGE_SVC_PROBLEM;$host;$service;1;$comment $vnam $nam\n"; close(CMD); $acked="1"; } if ($acked) { $sql_todo="UPDATE smsd.sms_log SET status='processed' WHERE id = $row[0] "; $sthm2=$dbhm2->do($sql_todo); } }
Besonders bei O2 muss man auf einige „Time Out“ werte achten.
Das häufigste Einwahlproblem ist die Verzögerung beim Login, die erst nach 38
Sekunden positiv beantwortet wird. Bei der Konfiguration der verwendeten
Software ist auf eine entsprechende Protokollverzögerung unbedingt zu achten.
Wie auch beim Einwählen ist beim Versenden eine Verzögerung eingebaut, eine
Bestätigung über das Versenden der Nachricht wird erst nach 26 Sekunden
versendet. Darauf ist bei der Konfiguration der Software unbedingt zu achten.
Bricht die Software die Verbindung vor dem Ablauf der 26 Sekunden ab, so wird die
Kurznachricht verworfen.
Als anhang nochmal 2 PDF von O2 wo mehr drin stehen.
Wenn ihr noch Anregungen habt, nur her damit ;) ich bin unter mailto:basti@2-die-4.tk zu erreichen)