Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Системное программирование > Telnet скрипт для извлечения данных


Автор: sh1kima26 16.12.2014, 11:01
Стоит задача подсчета абонентов на сетевом оборудовании и отображения собранных данных в Zabbix.
Командой show vpls mac-table count instance PPPoE-хххх получаем таблицу с количеством абонентов (хххх - хостнейм железки).
указанная команда вываливает таблицу из которой нам нужно только

nnn MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__
где nnn - сумарное число маков в домене ххх

Смысл такой:
по telnet скрипт заходит на железку
логин
пароль
conf t
show vpls mac-table count
вываливается таблица маков (например переменная MT), из которой он должен взять суммарное значение, т.е. должно применяться условие типа "если в переменной МТ имеется текст "MAC address learned in routing instance", то вывести из переменной МТ строку "nnn MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__" и записать в переменную sumMac (или файл который бы цеплялся заббиксом)
end

Как то так я это представляю.
за основу думаю можно взять http://www.lissyara.su/articles/freebsd/coding/zyxel_configuration/

Автор: ginnie 16.12.2014, 14:18
sh1kima26, у Вас что-то не получается, есть какие-то вопросы или Вы ожидаете, что кто-то напишет код за Вас? 

Автор: sh1kima26 16.12.2014, 14:57
ginnie, в жизни не занимался написанием скриптов, по этому да, прошу написать скрипт. Логика ясная, от чего оттолкнуться есть, знаний в языке нет, по этому я и прошу транслировать предпологаемую мной логику в скрипт. 
Или по карйней мере мне бы хотелось узнать как по уакзанному выше примеру организовать сбор требуемой информации из лога. 

Автор: sh1kima26 17.12.2014, 08:30
Вообще начал изучать язык, раз уж появилась нужда, понял что тут придется использовать регулярные выражения, но все еще не понял как выдрать из текста нужное слово.
Вот у меня будет лог файл в котором последней строкой будет:
nnn MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__
Мне нужно извлечь и записать в другой файл (или сделать так чтобы в логе сохранялось только требуемое значение) nnn - целое число разной длинны (вроде \d).

Вот думаю оттолкнутсья от такого примера
Код

$s = "1+2-3*4";
if ($s =~ /(\d)(?=-)/)  # Найти цифру за которой стоит '-'
    {
        print "$1\n";   # Результат '2'
   }
else { print "ошибка поиска\n";}


Только у меня будет текст из которого нужно извлечь первое число после которого стоит пробел (\s).

Код

$s = "nnn MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__";
if ($s =~ /(\d)(?=\s)/)  # Найти цифру за которой стоит '\s'(пробел)
    {
        print "$1\n"; 
   }
else { print "ошибка поиска\n";}


Только тут не указывается, что нужно найти первое число после котороего стоит пробел. Какой идентификатор будет указывать именно на первое совпадение? А может и не стоит замарачиваться, ведь в требуемой строке только nnn является целым числом (xxx может являться сочетанием букв и цифр)

Автор: sh1kima26 17.12.2014, 10:06
Код

$s = "nnn MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__";
if ($s =~ /^(\d+)(?=\s)/) # Найти цифру за которой стоит '\s'(пробел)
    {
        print "$1\n"; 
   }
else { print "ошибка поиска\n";}

Вот так получается можно выловить нужное мне число.
Но как  сказать скрипту, что искомое значение находится именно в последней строке лога?

Добавлено через 11 минут и 47 секунд
Вообще я еще не разобрался как собственно последнюю строку лога занести в переменную. Т.е. сначала должно быть условие типа

если существует строка содержащая "nnn MAC address learned in routing instance" то занести ее в переменную $s

А далее уже

$s = "nnn MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__";
if ($s =~ /^(\d)(?=\s)/)  # Найти цифру за которой стоит '\s'(пробел)
    {
        print "$1\n"; 
   }
else { print "ошибка поиска\n";}

Автор: sh1kima26 17.12.2014, 10:45
проглядел, интересующая меня строка
nnn MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__
будет самой первой после того как скрипт выполнит команду, следовательно нужно научить скрипт выводить нужную цифру из самой первой строки полученной информации 

Автор: alezzz 19.12.2014, 09:54
sh1kima26, вы можете показать кусок лога или весь? а то непонятно причем тут первая/последняя строка, если строка 'nnn MAC address learned ...' в логе встречается только 1 раз, то не важно где она. К тому что уже сделано вами такие замечения:

Код

use strict;

my $s = "111 MAC address learned in routing instance PPPoE-xxx bridge domain __PPPoE-xxxx__";
if ($s =~ /^(\d+) MAC address learned/)  # Найти цифру за которой стоит '\s'(пробел)
    {
        print "$1\n"; 
   }
else { print "ошибка поиска\n";}

1. Ищите число, но в тестовой строке используете nnn вместо числа.
2. \d - это одна цифра, одна и более - это \d+.

Автор: sh1kima26 22.12.2014, 08:57
alezzz, это я для наглядности писал nnn, подразумевая, что оно может быть разным.
Вообще, вышло вот так, но все нет времени протестировать

Код

#!/usr/bin/perl
 
use Net::Telnet;
use strict;
use warnings;
 
my $user = "admin";
my $pass = "12345";
 
open(my $iplist, "iplist.txt");
open(my $log, ">>log.txt");
open(my $counts, ">>counts.txt");
open(my $cmds, "commands");
 
my @commands = <$cmds>;
 
while (my $host = <$iplist>) 
{
   chomp($host);
   my $th = new Net::Telnet(Timeout => 15, Telnetmode => 1,Errmode => "return");
 
   print "\n======================= START =======================\n";
   print "[+] Connecting to: ".$host."\n";
   print "=====================================================\n";
   print $log "\n======================= START =======================\n";
   print $log "[+] Connecting to: ".$host."\n";
   print $log "=====================================================\n";
   
   $th->open($host);
   $th->waitfor('/login|user name/i');
   $th->print($user);
   
   $th->waitfor('/password/i');
   $th->print($pass);
                    
   my $i = 1;
   foreach my $cmd (@commands)
   {
 
      $th->waitfor('/[$#]/');
 
      my @out = $th->cmd($cmd);
 
      print @out;
      print $log @out;
      
      foreach my $line (@out)
      {
         if ($line =~ /^(\d+)(?= MAC address learned)/)
         {
             print $counts $host.": ".$i.",".$1."\n"; 
             $i++;
         }
      }      
      
   }
      
   
}
 
close($iplist);
close($log);
close($counts);
close($cmds);

Автор: alezzz 22.12.2014, 15:41
Должно работать, если с telnet-ом никаких косяков не будет. Пишите если будут проблемы после тестирования.

Автор: sh1kima26 30.12.2014, 09:07
alezzz, 
дошли таки до тестирования. Стопорится на
При запуске с FreeBSD
======================= START =======================
[+] Connecting to: ".$host."\n";
=====================================================
сначала указывал на строку open(my $cmds, "commands");
переименовали commands в commands.txt
стопорится теперь там же, но просто без указания строки.

При запуске через командную строку выдает

readline() on closed filehandle $cmds at /usr/local/etc/zabbix22/zabbix/externalscripts/MAC_summary_script_v1.pl line 15.
readline() on closed filehandle $iplist at /usr/local/etc/zabbix22/zabbix/externalscripts/MAC_summary_script_v1.pl line 17.

15 строка это commands, 17 while (my $host = <$iplist>) 

Порекомендовали в open () писать полные пути к файлам. Но по техническим причинам снова не омжем протестировать, о результатах напишу позже.

Автор: Loki 10.2.2015, 03:41
а по snmp девайс такой статистики не отдает, зачем именно телнет?

Автор: alezzz 10.2.2015, 11:15
sh1kima26, напишите полные пути, или поместите скрипт и файлы в одну папку и запускайте скрипт оттуда.

Loki, может не давать, например смотрю walk-ом DES-1210, никаких dynamic macs. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)