Наша сеть построена из достаточно большого количества управляемых коммутаторов.
В основном мы используем коммутаторы производителя D-Link.
А т.к. ПО, которое быстро гуглится, не дало нам внятного ответа на один единственный вопрос «Чем забирать конфигурационные файлы с коммутаторов D-Link?», то написал сам.
Здесь привел основу, которую можно легко научить собирать конфигурационные файлы и с любого другого оборудования (Видео-серверы AXIS, к примеру).
Суть такова: есть количество управляемых свичей, нужно с них собирать конфигурационные файлы.
Берем TFTP сервер, Perl и два модуля (Net::Telnet & File::Copy).
Так же есть файлик hosts.txt
Его вид такой:
Суть такова: айпи адрес и… «тип устройства».
Файлик обрабатывается подпрограммой parse();
В этой подпрограмме указывается какое содержимое переменной $cmd нужно сказать коммутатору что бы он отдал конфиг. файл TFTP.
А! Есть еще момент.
В старой и доброй традиции юниксового TFTPD нужно что бы файлик, который мы передаем на сервер, уже был на этом сервере.
Т.е. подпрограмма tftp_create() как раз и создает такой файлик нулевого размера.
Сам скрипт назван ololo.pl и что бы конфигурационные файлы забирались с коммутаторов автоматически, необходимо добавить его вызов в crontab.
В основном мы используем коммутаторы производителя D-Link.
А т.к. ПО, которое быстро гуглится, не дало нам внятного ответа на один единственный вопрос «Чем забирать конфигурационные файлы с коммутаторов D-Link?», то написал сам.
Здесь привел основу, которую можно легко научить собирать конфигурационные файлы и с любого другого оборудования (Видео-серверы AXIS, к примеру).
Суть такова: есть количество управляемых свичей, нужно с них собирать конфигурационные файлы.
Берем TFTP сервер, Perl и два модуля (Net::Telnet & File::Copy).
Так же есть файлик hosts.txt
Его вид такой:
12.23.45.54 dlink
24.21.23.54 dlink_simple
Суть такова: айпи адрес и… «тип устройства».
Файлик обрабатывается подпрограммой parse();
В этой подпрограмме указывается какое содержимое переменной $cmd нужно сказать коммутатору что бы он отдал конфиг. файл TFTP.
А! Есть еще момент.
В старой и доброй традиции юниксового TFTPD нужно что бы файлик, который мы передаем на сервер, уже был на этом сервере.
Т.е. подпрограмма tftp_create() как раз и создает такой файлик нулевого размера.
Сам скрипт назван ololo.pl и что бы конфигурационные файлы забирались с коммутаторов автоматически, необходимо добавить его вызов в crontab.
#!/usr/bin/perl
##########################################
##
## ololo.pl
## (C) Ilya Vasilyev, 2010
## nadz.goldman@gmail.com
##
##########################################
##########################################
use Net::Telnet;
use File::Copy;
$cmd;
$host;
$type;
$conn;
# айпи тфтп сервера
$tftp_ip = "12.2.2.3";
# логин+пароль свича
$username = "bak";
$passwd = "bak";
# директория тфтп-сервера, в которую кидаются/из которой берутся файлы, прилетевшие на тфтп
$tftp_path = "/tftp";
# рабочая директория скрипта
$main_path = "/home/bak/ololo";
# так у меня выглядит дата
$date = `/bin/date "+%Y-%m-%d"`;
# это для винды
#$date = `date /T`;
# так выглядит имя файла конфигурации, прилетевшего со свича
$filename = $host."-".$date;
####################################################################################
# вызов подпрограммы для распарсивания файла с хостами
parse();
# выполнение бэкапа
execute();
# перенос в директорию бэкапа
mov_bak();
# подпрограмма переноса
sub mov_bak()
{
# обрезаем фигню всякую
chomp( $date );
# создаем директорию на текущую дату для бэкапа
system( "mkdir -p ".$main_path."/bak/".$date );
# двигаем туда прилетевшие к нам конфиги
system( "mv ".$tftp_path."/*_".$date." ".$main_path."/bak/".$date );
# скидываем в файл список пустых файлов - это те свичи, до которых мы либо не достучались, либо с них ничего не прилетело
system( "find ".$main_path."/bak/ -empty -exec ls {} \\; > ".$main_path."/NOT_BACKUP.txt " );
}
sub put_conf()
{
# на будущее =))
# here I put new conf to switch
}
# подпрограмма соединения со свичом по телнету
sub connect_()
{
my $temp;
$temp = length( $host );
# если вдруг переменная $host оказалась пуста, значит какой-то ахтунг произошел и скрипт умирает
if( $temp == 0 ){ die "No ip address ( func::connect_ ) !\n Exiting...\n"; }
# опции соединения
$conn = new Net::Telnet( Timeout => 5 , Errmode => 'return' , Dump_Log => 'DUMP.LOG' );
$conn->open( Host=>$host );
# допиливаю вывод ошибок
$msg = $conn -> errmsg;
$prev = $conn -> errmsg( @msgs );
foreach $prev( @msgs ){ print "$prev\n"; }
# создание дампов
$dump = $conn -> dump_log;
$dump = $conn -> dump_log( $dump );
$dump = $conn -> dump_log( $main_path.'/dump/DUMP.LOG' );
# ожидаем строки UserName/PassWord и дождавшись, скидываем туда логин и пароль
# Можно и вот так: $conn -> waitfor( '/username[: ]*$/i' ); , но эт потом...
# Просто потому что некоторые свичи пишут login или сразу password
$conn -> waitfor( '/ame[: ]*$/' );
$conn -> print( $username );
$conn -> waitfor( '/ord[: ]*$/' );
$conn -> print( $passwd );
}
# дисконнектимся
sub disconnect()
{
$conn -> print( "logout" );
$conn -> close;
undef( $conn );
copy( $main_path.'/dumps/DUMP.LOG', $main_path.'/dumps/DUMP.LOG-'.$host );
}
# собственно здесь мы и забираем конфиг
sub get_conf()
{
my $temp;
$temp = length( $host );
# если вдруг переменная $host оказалась пуста, значит какой-то ахтунг произошел и скрипт умирает
if( $temp == 0 ){ die "No ip address ( func::get_conf ) !\n Exiting...\n"; }
# создаем файлик в директории тфтп сервера
tftp_create();
# говорим свичу команду на отправку конфига
$conn -> print( $cmd );
# ждем - иногда свичи тупят, если сразу отвалится, то глупости будут
sleep( 15 );
}
# подпрограмма создания файла в каталоге тфтп
sub tftp_create
{
my $temp;
$temp = length( $host );
# если вдруг переменная $host оказалась пуста, значит какой-то ахтунг произошел и скрипт умирает
if( $temp == 0 ){ die "No ip address ( func::tftp_create ) !\n Exiting...\n"; }
# создаем файл
system( "touch $tftp_path"."/"."$filename" );
# устанавливаем права
system( "chmod 0666 $tftp_path"."/"."$filename" );
# ждем...
sleep( 2 );
}
# подпрограмма выполнения
sub execute
{
my $i;
# ищем файлик со свичами цисок
if( -f $main_path."/cisco.txt" )
{
open( cs , "< ".$main_path."/cisco.txt" ) or print "While executing, can not open cisco.txt";
while( defined( $i = ))
{
print( "Yeeehaaa!!! It is CISCO!! =)) \n\n" );
}
close( cs );
}
# ищем файлик с длинками
if( -f $main_path."/dlink.txt" )
{
open( dl , "< ".$main_path."/dlink.txt" ) or print "While executing, can not open dlink.txt";
while( defined( $i =
))
{
chomp( $i );
$host = $i;
$filename = $host."_".$date;
# ВОТ эта команда будет сказана свичю после соедиенения и атворизации
$cmd = "upload cfg_toTFTP $tftp_ip $filename";
# для дебага =)
#print( "Host: $host\nfile: $filename cmd: $cmd" );
# соеденились
connect_();
# забрали
get_conf();
# ушли
disconnect();
}
close( dl );
}
# А! Вот эта штука... Потому что длинки разные, то и набор команд у них разный.
# сейчас как раз пилю что бы этой ереси с кучей файлов не было
if( -f $main_path."/dlink_simple.txt" )
{
open( dl_simple , "< ".$main_path."/dlink_simple.txt" ) or print "While executing, can not open dlink_simple.txt";
# upload configuration
while( defined( $i = ))
{
chomp( $i );
$host = $i;
$filename = $host."_".$date;
$cmd = "upload configuration $tftp_ip $filename";
#print( "Host: $host\nfile: $filename cmd: $cmd" );
connect_();
get_conf();
disconnect();
}
close( dl_simple );
}
return();
}
# подпрограмма парсинга
sub parse
{
my $i;
open( cs , "+> ".$main_path."/cisco.txt" ) or print( "Can not open cisco.txt\n" );
open( dl , "+> ".$main_path."/dlink.txt" ) or print( "Can not open dlink.txt\n" );
open( dl_simple , "+> ".$main_path."/dlink_simple.txt" ) or print( "Can not open dlink_simple.txt\n" );
open( err_txt , "+> ".$main_path."/error.txt" ) or print( "Can not open error.txt\n" );
open( fh , "< ".$main_path."/hosts.txt" ) or die "Can not open hosts.txt!\n";
flock( fh , 2 ) or die "Can not flock hosts.txt!\n";
while( defined( $i = ))
{
( $host, $type ) = split( / /, $i );
if( $type =~ /cisco/i )
{
#print "host = $host ... type = $type";
print cs "$host\n";
}
elsif( $type =~ /^dlink$/i )
{
#print "host = $host ... type = $type";
print dl "$host\n";
}
elsif( $type =~ /^dlink_simple$/i )
{
print dl_simple "$host\n";
}
else
{
print err_txt "$host $type\n";
}
}
close( fh );
close( cs );
close( dl );
close( err_txt );
close( dl_simple );
return();
}