~# apt-get install perl
~# apt-get install rrdtool
===== Script en Perl =====
El script realiza los siguientes pasos:
- abre una conexión telnet al dispositivo que interesa monitorear
- inicia una sesión con la contraseña del dispositivo
- envía los comandos necesarios
- guarda el resultado en una variable por cada resultado obtenido
- utiliza expresiones regulares para capturar y guardar los valores que después se van a graficar
- actualiza la base de datos round-robin
#!/usr/bin/perl
use Net::Telnet ();
use RRDs;
$host = '192.168.100.1';
$pass = '[administrator password, "admin" by default]';
$RRD_FILE="/mnt/hdd/web/html/rrdtool/TL8816.rrd";
$STEP = 300;
$HEARTBEAT = 600;
$t = new Net::Telnet ( Timeout => 10,
Errmode => 'die',
Dump_log => '/mnt/hdd/web/html/rrdtool/dump.log',
Input_log => '/mnt/hdd/web/html/rrdtool/input.log');
# Open and login
$t->open($host);
$t->waitfor('/Password: $/i');
$t->print($pass);
$t->waitfor('/TP-LINK> $/i');
# make lists with the responses and close connection
@result_line_near = $t->cmd('wan adsl linedata near');
@result_line_far = $t->cmd('wan adsl linedata far');
@result_chan = $t->cmd('wan adsl chandata');
$t->close();
# initialize vars
$snr_down="U";
$snr_up="U";
$att_down="U";
$att_up="U";
$pwr_down="U";
$bitrate_up="U";
$bitrate_down="U";
# take the values matching the conditions
while(@result_line_near)
{
if (@result_line_near[0] =~ /noise margin downstream:\s+(\d*.\d*)\s+/)
{
$snr_down=$1;
}
if (@result_line_near[0] =~ /attenuation downstream:\s+(\d*.\d*)\s+/)
{
$att_down=$1;
}
shift(@result_line_near)
}
while(@result_line_far)
{
if (@result_line_far[0] =~ /noise margin upstream:\s+(\d*.\d*)\s+/)
{
$snr_up=$1;
}
if (@result_line_far[0] =~ /attenuation upstream:\s+(\d*.\d*)\s+/)
{
$att_up=$1;
}
if (@result_line_far[0] =~ /output power downstream:\s+(\d*.\d*)\s+/)
{
$pwr_down=$1;
}
shift(@result_line_far)
}
while(@result_chan)
{
if (@result_chan[0] =~ /near-end interleaved channel bit rate:\s+(\d*.\d*)\s+/)
{
$bitrate_down=$1;
}
if (@result_chan[0] =~ /far-end interleaved channel bit rate:\s+(\d*.\d*)\s+/)
{
$bitrate_up=$1;
}
shift(@result_chan);
}
# Debug options
#print " snrdown: $snr_down \n snrup: $snr_up \n attdown: $att_down \n attup: $att_up \n pwrdown: $pwr_down \n bitratedown: $bitrate_down \n bitrateup: $bitrate_up \n";
# if $RRD_FILE doesn't exist, create it
if (not -e $RRD_FILE)
{
RRDs::create("$RRD_FILE",
"--start=N",
"--step=$STEP",
"DS:snrd:GAUGE:$HEARTBEAT:0:U",
"DS:snru:GAUGE:$HEARTBEAT:0:U",
"DS:attd:GAUGE:$HEARTBEAT:0:U",
"DS:attu:GAUGE:$HEARTBEAT:0:U",
"DS:powd:GAUGE:$HEARTBEAT:0:U",
"DS:rated:GAUGE:$HEARTBEAT:0:U",
"DS:rateu:GAUGE:$HEARTBEAT:0:U",
"RRA:AVERAGE:0.5:1:1000",
"RRA:AVERAGE:0.5:6:1000",
"RRA:AVERAGE:0.5:24:1000",
"RRA:AVERAGE:0.5:288:1000");
}
# update the database
RRDs::update("$RRD_FILE","N:$snr_down:$snr_up:$att_down:$att_up:$pwr_down:$bitrate_down:$bitrate_up");
Guardar el código en algún directorio. El nombre no importa, en mi caso se llama 'linechan.pl'.
Algunas aclaraciones sobre el código:
''$STEP'' está en segundos y por defecto toma el valor 300. Es importante que el cron corra el script cada ''$STEP'' para que las mediciones sean correctas, sobre todo si se usan contadores del tipo 'COUNTER' o 'DERIVE' que utilizan el tiempo de ''$STEP'' para calcular los valores que se van a representar después.
''$HEARTBEAT'' está en segundos e indica que si no llega ningún dato válido cada ''$HEARTBEAT'', entonces en la base de datos se inserta un ''unknown'' en vez de inventar un valor (e.g. cero).
''Dump_log'' e ''Input_log'' son útiles para debug, muestran la última respuesta que envió el dispositivo interrogado. Se pueden omitir para reducir la escritura en disco.
''shift()'' desplaza la lista. Aparentemente si la respuesta fuese una cadena ''$chain'' en vez de una lista ''@list'', se podría omitir el ''while()'', el ''if()'' y el ''shift()'', ya que se puede crear la nueva variable asignando el valor que devuelve la búsqueda con regex.
''Debug options'' se pueden habilitar para mostrar en la consola los valores de las variables.
La documentación de RRDtool está acá: http://oss.oetiker.ch/rrdtool/doc/index.en.html
y un tutorial detallado explicando el uso: http://oss.oetiker.ch/rrdtool/tut/rrdtutorial.en.html
Ahora hay que crear la tarea para que la ejecute crontab cada ''$STEP'' segundos.
===== Cron =====
Simplemente hay que decirle que ejecute el script en el lapso de tiempo de ''$STEP''. En mi caso son 300 segundos, lo que equivale a 5 minutos.
Editar el crontab...
~# crontab -e
y anexar
*/5 * * * * perl /path/to/script/linechan.pl
donde '*/5' indica que corre cada 5 minutos.
Una vez guardado no es necesario reiniciar.
Ya debería estar guardando los valores en la base de datos cada ''$STEP''. Falta poder visualizar los gráficos.
===== Configurando CGI =====
Common Gateway Interface (CGI) funciona en Lighttpd sin necesidad de instalar plugins, solamente hay que habilitar el módulo CGI, incluir el archivo de configuración y asegurarse que el intérprete del lenguaje esté instalado (i.e. para interpretar python debería estar instalado python).
Crear ''/etc/lighttpd/conf.d/cgi.conf'' y agregar:
server.modules += ( "mod_cgi" )
cgi.assign = ( ".pl" => "/usr/bin/perl",
".cgi" => "/usr/bin/perl",
".rb" => "/usr/bin/ruby",
".erb" => "/usr/bin/eruby",
".py" => "/usr/bin/python",
".php" => "/usr/bin/php-cgi" )
index-file.names += ( "index.pl", "default.pl",
"index.rb", "default.rb",
"index.erb", "default.erb",
"index.py", "default.py",
"index.php", "default.php" )
En el archivo de configuración de Lighttpd, ''/etc/lighttpd/lighttpd.conf'' agregar:
include "conf.d/cgi.conf"
de esta manera, lighttpd llama al intérprete cada vez que le piden abrir por ejemplo un archivo .cgi.
==== Script CGI ====
Es muy simple, solamente hay que leer la documentación de [[http://oss.oetiker.ch/rrdtool/doc/rrdcgi.en.html|rrdcgi]] para configurar los gráficos.
En mi caso, quedó de la siguiente manera
#!/usr/bin/rrdcgi
Line Stats for TD8816
TD8816 ADSL modem line and channel stats
Line Stats for SNR
.png
--lazy
--start -
--end now
DEF:snrdown=/mnt/hdd/web/html/rrdtool/TL8816.rrd:snrd:AVERAGE
DEF:snrup=/mnt/hdd/web/html/rrdtool/TL8816.rrd:snru:AVERAGE
AREA:snrdown#2A3CFF22:
AREA:snrup#00FF0022:
LINE1:snrdown#0000BB:"Downstream [db]"
LINE1:snrup#00BB00:"Upstream [db]"
>
Line Stats for Attenuation
.png
--lazy
--start -
--end now
DEF:attdown=/mnt/hdd/web/html/rrdtool/TL8816.rrd:attd:AVERAGE
DEF:attup=/mnt/hdd/web/html/rrdtool/TL8816.rrd:attu:AVERAGE
AREA:attdown#8030F022:
AREA:attup#0A551822:
LINE1:attdown#8030F0:"Downstream [db]"
LINE1:attup#0A5518:"Upstream [db]"
>
Line Stats for Power
.png
--lazy
--start -
--end now
DEF:powdn=/mnt/hdd/web/html/rrdtool/TL8816.rrd:powd:AVERAGE
AREA:powdn#0011AA22:
LINE1:powdn#0011AA:"Downstream Power [dBm]"
>
Line Stats for Bitrate
.png
--lazy
--start -
--end now
DEF:ratedown=/mnt/hdd/web/html/rrdtool/TL8816.rrd:rated:AVERAGE
DEF:rateup=/mnt/hdd/web/html/rrdtool/TL8816.rrd:rateu:AVERAGE
AREA:ratedown#00A27722:
AREA:rateup#A2770022:
LINE1:ratedown#00A277:"Downstream [Kbps]"
LINE1:rateup#A27700:"Upstream [Kbps]"
>
Vale aclarar que ''
En el [[http://oss.oetiker.ch/rrdtool/tut/rrdtutorial.en.html|tutorial de rrdtool]] también aparecen ejemplos de configuración de los gráficos.