Что делать на работе, если не знаешь, чем бы еще заняться? Конечно же писать на Хабр!
Благодаря нашим доблестным законодателям, дальнейшее развитие бизнеса самостоятельно нерентабельно и мы уходим под более крупного оператора. Вот у меня и сложилась такая ситуация, что смысла дорабатывать, переписывать и исправлять свои старые проекты - нет, у "крупняка" все сервисы свои. Сижу, курю. А потом думаю, а чего сидеть-то, напишу-ка я на Хабр. Статья прошла модерацию, «И тут Остапа понесло...».
Итак, о чем будет эта статья. Все кто занимаются сетями, рано или поздно сталкиваются с MIB. Для тех, кому лень переходить по ссылке, это такая база данных, содержащая информацию об объекте, в нашем случае - сетевом устройстве. На хабре было несколько статей, посвященным работе с MIB и возникающим при этом вопросах. Мне понравилась статья SNMP MIBs и как их готовить, где автор для работы с MIB использовал инструмент от D-Link - утилиту D-View. Сразу скажу, зная качество MIB от этого вендора - использовать в реальных проектах D-View не рекомендую. Однако она дает представление, о типичном интерфейсе подобного программного обеспечения. Как ни странно, программ для работы непосредственно с MIB, сходных по функционалу хотя бы с D-View - не так много. Я бы даже сказал - очень мало. Описывать все их плюсы и минусы я не собираюсь. Здесь я хочу показать мою реализацию, наверняка не самую лучшую, но писалось "для себя" и функционал допиливался по мере необходимости.
Итак, вся серверная часть будет на Perl и библиотеке SNMP.pm. Пожалуй разобью статью на две части, - во второй будет описание клиентской части. Начнем пожалуй с загрузки нужных нам MIB:
sub load_mibs {
my ($attr, $Nms) = @_;
#Если MIB Вашего оборудования располагаются в каталоге, отличном от
#стандартного(с моей точки зрения - это правильный подход), указываем здесь
my $MIB_search_path = '../modules/Nms/mibs';
#Добавляем свой путь во внутренний лист библиотеки
SNMP::addMibDirs($MIB_search_path);
SNMP::addMibDirs($MIB_search_path . '/private');
#Здесь уже можно загрузить все модули, но при работе с реальным уст-ом
#я загружаю только нужные мне.
if ( $attr->{ALL} ) {
SNMP::addMibFiles( glob( $MIB_search_path . '/private' . '/*' ) );
SNMP::initMib();
}
#Пусть это будет DES3200-28
elsif ( $attr->{SYS_ID} ) {
my @mods = ('EQUIPMENT-MIB', 'DES3200-28-L3MGMT-MIB', 'CABLE-DIAG-MIB');
#Здесь, в отличии от первого варианта, загрузятся только нужные MIB
SNMP::loadModules(@mods);
SNMP::initMib();
}
return 1;
}
Сразу несколько пояснений: - первое, загрузка только нужных модулей, значительно ускоряет дальнейшую работу с деревом OID; - второе, не обязательно указывать все необходимые модули, в правильно "приготовленном" MIB используются ссылки на нужные модули, и они подгрузятся автоматически, например так:
IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
OBJECT-IDENTITY, Counter32, Gauge32, Integer32, mib-2
FROM SNMPv2-SMI
DisplayString, TimeStamp, TimeInterval, TestAndIncr,
AutonomousType, TEXTUAL-CONVENTION
FROM SNMPv2-TC
MODULE-COMPLIANCE, OBJECT-GROUP
FROM SNMPv2-CONF;
то есть указывается, что и откуда импортировать.
Поехали дальше, дерево с OID у нас уже есть и находится в хеше %SNMP::MIB. В принципе, можно его уже в таком виде отдать клиенту, и распарсить какой-нибудь JS библиотекой. Но мы добрые, - не дадим зависнуть клиентской машинке и приготовим данные сервером. Для отрисовки дерева я буду использовать библиотеку jsTree, следующий код подготавливает данные:
sub mibs_tree {
my ($attr) = @_;
my %labels;
my @tree_arr;
foreach my $oid ( sort keys(%SNMP::MIB) ) {
#Определяем ветку дерева, либо корень.
my $prev_id =
( $SNMP::MIB{$oid}{parent} )
? $SNMP::MIB{$oid}{parent}{objectID}
: '#';
#Ну и дальше мы определяем типы OID и навешиваем атрибуты для jsTree
my $icon = '';
my %type;
if ( $SNMP::MIB{$oid}{children}[0]{indexes}[0] ) {
$type{type} = 'table';
}
elsif ($SNMP::MIB{$oid}{parent} && $SNMP::MIB{$oid}{parent}{indexes}[0]){
$type{type} = 'row';
}
elsif ( $SNMP::MIB{$oid}{type} ) {
$type{type} = 'scalar';
}
elsif ( $SNMP::MIB{$oid}{indexes}[0] ) {
$type{type} = 'indexes';
}
else {
$type{type} = 'folder';
}
push @tree_arr,
(
{
id => $SNMP::MIB{$oid}{objectID},
text => $SNMP::MIB{$oid}{label},
parent => $prev_id,
%type
}
);
}
}
my %types = (
table => { icon => 'fa fa-table' },
row => { icon => 'fa fa-columns' },
scalar => { icon => 'fa fa-paragraph' },
indexes => { icon => 'fa fa-list-ul' },
folder => { icon => 'fa fa-folder-o' },
);
return make_tree(
{
plugins => [ 'types', 'search', 'contextmenu' ],
contextmenu => { items => '*customMenu*' },
types => \%types,
core => { data => \@tree_arr }
}
);
}
На этом пожалуй пока остановлюсь, так как дальше будет уже много JS и HTML. Для затравки покажу, что должно получится в результате:
Пишу, пока есть настроение и не факт, что продолжение будет. Поэтому дам ссылку на мою старенькую репку на github. Код рабочий, правда без комментариев, думаю имеющим опыт работы с Perl, не составит труда выдернуть нужные куски.