viernes, febrero 15, 2008

Alarma telefonica para servidores

El sueño de todo proveedor de servicios de internet es ofrecer la mayor cantidad de time-up's en sus servidores, ojalá el 100%. Pero es prácticamente imposible. Lo que es posible es contar con métodos de alerta temprana por fallas.
Lo más usual es tener habilitado un monitor de servicios que avise, ya sea vía mail o SMS, si algún imprevisto ocurre. Un problema se presenta si ese imprevisto ocurre a las 4 a.m. y estamos durmiendo (y no revisando el mail) y no escuchamos la alarma del SMS; o peor, el SMS se retrasa por problemas de congestión en la red de nuestro proveedor de servicio celular.
Para solucionar ésto, una alternativa es que nuestro monitor nos llame. ¡Sí!, nos llame al celular e insista hasta que contestemos :)

Mi propuesta es utilizar el servicio de VoIP de algun proveedor y un sintetizador de textos (Festival), para convertir a nuestro monitor de servicios en una alarma parlante:

Lo primero, instalar un cliente SIP en modo texto. Mi elección fue PJSIP. Para instalarlo en FreeBSD lo descargamos del link anterior y lo descomprimimos (en mi caso, en /usr/local/). Luego:

# cd /usr/local/pjproject-0.8.0
# ./configure

en este punto es necesario parchear el archivo pjproject-0.8.0/pjlib/include/pj/compat/socket.h:

Eliminar las siguientes lineas:

- #if defined(PJ_HAS_NETINET_IN_H) && PJ_HAS_NETINET_IN_H != 0
- # include
- #endif

Y continuar:

# gmake dep
# gmake clean
# gmake

OJO GMAKE no make.

Una vez terminado el proceso es necesario crear un archivo de configuración (conf) con los datos de nuestra cuenta SIP:

########Ejemplo de archivo de configuracion "conf" ###################
# This is a comment in the config file.
--id sip:XXXX@sip.proveedor.dom
--registrar sip:sip.proveedor.dom
--realm *
--username XXXX
--password LA_PASSWD_AQUI
########################################################

Y esta listo para funcionar, a continuación comparto con uds el Script que se ejecuta cuando ocurre una alarma en uno de los servidores:

#!/usr/bin/perl

open(my $in, "<", "/usr/local/www/data/report.txt") or die "NOOOT!: $!"; open(my $out, ">", "/usr/local/pjsip/bin/mensaje.txt") or die "NOOOT!: $!";
open(my $in2, "<", "dnscache.txt") or die "NOOOOOT!!: $!"; while (<$in>) {
if (/NO activo en\s(\d+\.\d+\.\d+\.\d+)\s\w+\s(\d+)/) {
$ip = $1;
$puerto = $2;
while (<$in2>) {
if (/$ip\s+([\w\-\d]+)/) {
print $out "Problema en el servidor $1 puerto $puerto";
}
}
}}


close $in;
close $out;
close $in2;
system("sed -i -e 's/\\./ /g' /usr/local/pjsip/bin/mensaje.txt");

use IPC::Open3;
open(my $log, ">", "/usr/local/pjsip/bin/log.txt") or die "NOOOT!: $!";
my($a,$b,$c);
open3($a, $b, $c,'festival --tts /usr/local/pjsip/bin/mensaje.txt');
print $log "$b";

open($temp, "ps aux |grep pjsua-i386-unknown-freebsd6.0 |grep -v 'grep' |") || die "NOOOT!!!!: $!";
while (<$temp>) {
#print "$_";
if (/\w+\s([\d]+)/) {
#print "$1";
`kill -9 $1`;
}
}
close($temp);

my $ok=1;

sub llamada {
my($wtr, $rdr, $err);
$pid = open3($wtr, $rdr, $err,'pjsua-i386-unknown-freebsd6.0 --config-file /usr/local/pjsip/bin/conf --play-file /usr/local/pjsip/bin/mensaje.wav --auto-play --null-audio --duration=30 sip:xxxxxxxxxx\@sip.proveedor.dom');

while (<$rdr>) {
#print "$_";
if (/DISCONNECTED/) {
print $wtr "q\n";
}
if (/CONFIRMED/) {
$ok=0;
}
}
}
while ($ok) {
llamada();
}

Este script es llamado por el script vigia instalado en el cron, si no existe falla de sistema este script no es llamado.

Como pueden ver el script lo primero que hace es buscar en el reporte de alarma, que se actualiza cada 5 minutos por medio de un cron, la o las lineas que indiquen que un servidor "NO" esta activo busca la ip de dicho servidor en el archivo dnscache.txt y guarda en una variable el nombre de dicho servidor (cuando se prestan muchos servicios es normal que un servidor tenga mas de una ip por lo tanto es mas util el nombre que la misma), luego construye un mensaje con el nombre del servidor y el numero de puerto del servicio que fallo.

A continuacion el script invoca a Festival, para que nos lea el mensaje y lo deje en un archivo .wav single channel/mono, 16bit signed PCM, como? Casi olvido hablar de festival. Bueno para instalar como de costumbre vamos al port de nuestro FreeBSD consultamos en Freshports si es necesario actualizar los ports, y ejecutamos los siguiente pasos:

#cd /usr/ports/audio/festival/
#make install clean

#cd /usr/ports/audio/festvox-el11/
#make install clean

Este ultimo instalara la voz de hombre en español, para instalar una voz de mujer es necesario instalar festvox-hvs, como el echo de ser hombre o mujer la voz no era una de mis prioridades simplemente instale el11, ya que hvs depende de festival+OIG que no es compatible con festival por lo tanto era re-compilar etc...

Configuraciones Festival:

Editar el archivo /usr/local/share/festival/lib/siteinit.scm y agregar lo siguiente:

(set! voice_default 'voice_el_diphone)
(Parameter.set 'Audio_Method 'audio_Command)
(Parameter.set 'Audio_Command "/usr/local/bin/sox -t raw -r $SR -sw -c 1 $FILE /usr/local/pjsip/bin/mensaje.wav")

La primera linea es para definir el uso de la voz en español y las otras son para que genere el archivo .wav, para ello es necesario tener instalado sox (/usr/ports/audio/sox) previamente.

Una vez finalizada la configuracion de festival volvamos al script, si algo malo pasara en la ejecucion de festival podriamos leerlo en el archivo log.txt, a continuacion verifica si existe otra instancia de pjsip ejecutandose en el servidor de ser asi la mata y le da curso a esta alarma que problablemente sea mas importante, define una variable ok, y procede a definir la subrutina que utilizara a pjsip para efectuar la llamada de alerta, podemos ver que se trata de una llamada simple vasta con cambiar xxxxxxxxxx\@sip.proveedor.dom por el numero al que queramos avisar y el programa tratara de llamar hasta que le contesten gracias al bucle while del final del programa. Al responder la llamada escucharemos una agradeble voz media robotizada que nos dira que servidor tiene problemas y en que puerto, y no podremos decir que no lo escuchamos ya que se trata de un sistema bastante insistente.

Saludos

10 comentarios:

Anónimo dijo...

jejeje
...que aplicado con la práctica!

Buena, justo el sábado un amigo me había preguntado algo parecido pa aplicarlo con unos sensores. Le voi a a linkear tu post. :D

Nos estamos viendo
Un abrazo

VasKo

German dijo...

Jaja, claro que la práctica ya pasó, quizá quieras cambiar el nombre (y de paso la URL) del blog. Ah, y una revisión del corrector ortográfico en el FireFox tampoco vendría mal ;)

¿Qué pasa si el teléfono está ocupado/apagado?

Salu2

Claudio Castro dijo...

El corrector ortografico se viene jejeje.

Si el telefono esta ocupado no es problema por que el script sigue intentando hasta que se realiza una comunicacion efectiva, ahora si esta apagado y tiene buzon de voz, eso podria ser un problema ya que podria confundir al script y "pensar" que la llamada fue contestada, ahora en servidores de produccion es inaceptable que el celular de monitoreo este apagado, de todas formas tendria que monitorear una llamada contestada por el buzon de voz para ver si existe alguna flag que lo identifique, y de esta forma advertir al script.

Saludos y gracias por el comentario.

Nombre a Mostrar dijo...

wena...

el blog más computin al ke me he metido hasta el momento...

jajajjajajaj.

saludos...

Jonathan.

AlejandroK dijo...

Tenes idea como hacer para que el pjsip no empieza a reproducir el wav cuando este sonando , sino cuando la llamada es atendida?

Claudio Castro dijo...

mm que raro a mi me funciona correctamente es decir no reproduce el wav sino hasta que contestan el fono.

Ulver dijo...

solo un alcance

sip:09telefonodesoportecon8digitos@provedor.sip.tld


me di varios tumbos con eso ...

Claudio Castro dijo...

Ulver la forma de marcado va a depender de tu proveedor de telefonia ip, es por eso que no lo detalle, para mantenerlo mas "internacional" jeje

Muchas gracias por el comentario, me alegra saber que a alguien le gusto lo suficiente como para aplicarlo.

Saludos

Ulver dijo...

ahh olvidadaba para frases estáticas sirve harto ...

http://tts.loquendo.com/ttsdemo/

Claudio Castro dijo...

en la nueva version de sox (14) fue deprecada la opcion -w, en ese caso deben usar -2, de esta forma:

Editar el archivo /usr/local/share/festival/lib/siteinit.scm y agregar lo siguiente:

(set! voice_default 'voice_el_diphone)
(Parameter.set 'Audio_Method 'audio_Command)
(Parameter.set 'Audio_Command "/usr/local/bin/sox -t raw -r $SR -s -2 -c 1 $FILE /usr/local/pjsip/bin/mensaje.wav")