Сначала хочу немного вернуться назад. В первой части я не написал, для чего вообще нужен MIB браузер и сами MIB модули, ведь многие как-то и без всего этого обходятся и вполне себе мониторят свои сети. Как правило для этого используется цифровой OID вида «.1.3.6.1.4.1.171.11.113.1.3.2.2.3″ и тематические форумы пестрят запросами «А подскажите OID для того чтобы …». При желании можно и самому найти нужный OID сделав walk где-то поближе к ветке private.
MIB браузер как раз и является тем инструментом, который позволит Вам упростить работу с оборудованием. Это фактически тоже самое, что иметь иерархическую структуру в базе данных с быстрым и удобным поиском, индексами, типами данных. Вы получаете быстрый доступ ко всем датчикам и триггерам оборудования, с возможностью их создания/правки. Тем самым становится проще администрировать сети, выявлять ошибки и быстрее реагировать на неисправности. Особенно это важно при работе с новыми моделям, ранее неизвестными Вам.
Конечно тут многое зависит от вендоров, вернее от качества предоставляемых ими MIB и реализации snmp на железе. Зачастую в модулях не хватает описаний нужных индексов, индексы не соответствуют реально отдаваемым значениям и т.д. Бывают вообще ситуации за гранью логики, — меня есть gepon оборудование одного китайского производителя, у которого в ветке enterprises два разных вендора! Вот и попробуй найди нужные OID методом перебора. И не надо писать «вы все быдло, покупайте только циски». Я конечно утрирую, но зачастую комментарии звучат именно так. А циску я как-нибудь в другой раз обосрсужу. Если тема по работе с модулями MIB будет интересна, возможно в будущем я вернусь к ней.
Как-то так. В первой части мы подготовили данные для формирования дерева с помощью jsTree. Загрузим данные(имеющим тонкую душевную организацию, лучше отойти от экранов):
#тут намешан perl, js, html ... #не нравится? проходи мимо. sub make_tree { my $self = shift; my ( $attr, $id ) = @_; my $result = ''; #тут определяем как будет работать наше дерево, задаем параметры #которые потом передадим в JS my %all; $all{core}{themes} = ( { variant => 'medium', responsive => 'true' } ) if !$attr->{core}->{themes}; $all{plugins} = ( $attr->{plugins} ) ? $attr->{plugins} : 'search'; $all{search} = ( $attr->{search} ) ? $attr->{search} : ( { case_insensitive => 'true', show_only_matches => 'false' } ); #здесь цепляем хеш с подготовленными ранее данными %all = ( %all, %$attr ); #перекодируем в JSON my $DATA = JSON->new->indent->encode( \%all ); #немного подчишаем, возможно есть другой способ #получить на выходе из json логические операторы без кавычек $DATA =~ s/"false"/false/g; $DATA =~ s/"true"/true/g; $DATA =~ s/\"\*|\*\"/ /g; $DATA =~ s/"/'/g; #подключаем стили и библиотеку(хотя никто не мешает #поключить в любом другом месте) и готовим DIV для нашего дерева $result .= qq{ <link rel='stylesheet' href='/styles/lte_adm/plugins/jstree/themes/default/style.min.css' /> <script type='text/javascript' src='/styles/lte_adm/plugins/jstree/jstree.min.js'></script> <div id='MY_TREE' align='left'></div> }; #заливаем наши данные в js $result .= qq( <script> jQuery('#MY_TREE').jstree($DATA); </script> ); #уфф, всё, рисуем дерево return $result; }
Картинка под спойлером:

Ах да, всё это рисуется на каркасе AdminLTE, в теме по-умолчанию, отсюда такие цвета и иконки. На кнопочку «Модули» не обращаем внимания, у Вас её не будет.
Что дальше. Давайте для начала вспомним, как у нас будет выглядеть mib браузер:

это 2 функциональных и один информационный блок:
-
Непосредственно само дерево, с которым мы будем работать.
-
Блок данных, возвращаемый устройством. В зависимости от типа данных, можно производить какие-либо манипуляции.
-
Здесь будет подробная информация о выбранных идентификаторах.
Дерево у нас уже есть. Нарисуем информационный блок:
#в хеше %lang у меня локализация sub nms_show { my ($attr) = @_; $snmpparms{UseSprintValue} = 1; #я рисую через готовый API, тут уж кто во что my $table = $html->table( { ID => 'SNMP_SHOW', caption => $label, } ); #Набиваем информационный блок по-максимуму, мало ли что в будущем пригодится $table->addrow( $html->b('objectID'), $SNMP::MIB{ $attr->{OID} }{objectID} ); $table->addrow( $html->b( $lang{TYPE} ), $SNMP::MIB{ $attr->{OID} }{type} ) if $SNMP::MIB{ $attr->{OID} }{type}; $table->addrow( $html->b('Module'), $SNMP::MIB{ $attr->{OID} }{moduleID} ); $table->addrow( $html->b('Varbinds'), "@{$SNMP::MIB{ $attr->{OID} }{varbinds}}" ) if $SNMP::MIB{ $attr->{OID} }{varbinds};; $table->addrow( $html->b( $lang{ACCESS} ), $SNMP::MIB{ $attr->{OID} }{access} ); $table->addrow( $html->b('Syntax'), $SNMP::MIB{ $attr->{OID} }{syntax} ) if $SNMP::MIB{ $attr->{OID} }{syntax}; $table->addrow( $html->b( $lang{RANGE} ), "$SNMP::MIB{$attr->{OID}}{ranges}[0]{low} .. $SNMP::MIB{$attr->{OID}}{ranges}[0]{high}" ) if $SNMP::MIB{ $attr->{OID} }{ranges}[0]; $table->addrow( $html->b( $lang{DESCRIBE} ), $SNMP::MIB{ $attr->{OID} }{description} ) if $SNMP::MIB{ $attr->{OID} }{description}; $table->addrow( $html->b('Reference'), $SNMP::MIB{ $attr->{OID} }{reference} ) if $SNMP::MIB{ $attr->{OID} }{reference}; $table->addrow( $html->b('Index(es)'), "@{$SNMP::MIB{$attr->{OID}}{indexes}}" ) if $SNMP::MIB{ $attr->{OID} }{indexes}[0]; $table->addrow( $html->b('Value List'), oid_enums( $attr->{OID}, { STR => 1 } ) ) if keys %{ $SNMP::MIB{ $attr->{OID} }{enums} }; return $table->show(); } #тут разворачиваем идентификаторы имеющие enums sub oid_enums { my ( $oid, $attr ) = @_; my %enums; my $str = ''; foreach my $el ( keys %{ $SNMP::MIB{$oid}{enums} } ) { $enums{ $SNMP::MIB{$oid}{enums}{$el} } = $el; } if ($attr) { foreach my $key ( sort { $a <=> $b } keys %enums ) { $str .= "$key = $enums{$key} </br>"; } return $str; } return %enums; }
Заглянул в свой код, который отрисовывает 2-й блок, и ужаснулся. У меня там и простой walk, и get, и gettable, и snmpset. Без поллитры и сам пожалуй не разберусь, поэтому попробую упростить:
#Привожу пример только для snmpget sub mibs_browser { my ($attr) = @_; if ( $FORM{OID} ) { #Обновляем информацию о идентификаторе print nms_show( { OID => $FORM{OID} } } ); if ( $FORM{GET} ) { $snmpparms{UseSprintValue} = 1; #Будем считать, что в этом месте нам уже известен IP оборудования #и мы его получаем в хеше $obj my $sess = SNMP::Session->new( DestHost => $obj->{ip}, %snmpparms ); my $iid = $attr->{IID} || 0; my $result = $sess->get( [ $FORM{OID}, $iid ] ); #Проверяем на ошибки if ( $sess->{ErrorNum} ) { return $html->message( 'err', $lang{ERROR}, $sess->{ErrorStr} ); } my $result_tbl = $html->table( {} ); $result_tbl->addrow( $html->b( $lang{RESULT} ), $result ); print $result_tbl->show(); return 1; } elsif ( ... ) { #ну и дальше обработчики различных событий } #выходим return 1 } #создаем блок куда будут отрисовываться 2-й и 3-й блоки my $res = $html->element('div', '', { id => 'RESULT'}); #Рисуем наше дерево my $tree = $html->element( 'div', mibs_tree()); #Ну и сваливаем все это в один блок print $html->element( 'div', $tree . $res, { class => 'row' } ); return 1; }
Блок 'RESULT‘ будет обновляться после нажатия на идентификатор в дереве. Для этого добавим обработчик. JavaScrpt для меня по-прежнему за гранью добра и зла, и если у Вас есть лучшие варианты реализации, — не стесняемся, пишем в комментариях:
//$ID в данном случае уникальный идентификатор, //благодаря которому мы сможем узнать IP уст-ва function renewLeftBox(itemName,Action,id,iid){ iid = iid ? iid : 0 ; var url = 'index.cgi?OID=' + itemName + '&IID=' + iid + '&' + Action + '=$ID'; jQuery('#RESULT').load(url); }; jQuery('#MY_TREE').on("changed.jstree", function (e, data) { renewLeftBox(data.instance.get_node(data.selected[0]).id,'SHOW', '$ID') });
В библиотеке jsTree мы подключили плагин 'contextmenu'. С его помощью мы будем опрашивать наше оборудование. Еще немного JS:
//Пример мне кажется достаточно простой //по подобию можно создавать свои менюшки function customMenu(node) { var items = {}; //Здесь и далее, я проверяю тип ноды, ну и в зависимости от этого //возвращаю нужное контекстное меню if (node.type === 'scalar') { items.Get = { label: 'Get', icon : 'fa fa-angle-down', action: function () { renewLeftBox(node.id,'GET'); } } } if (node.type === 'row' || node.type === 'table' || node.type === 'indexes') { items.Walk = { label: 'Walk', icon : 'fa fa-angle-double-down', action: function () { renewLeftBox(node.id,'WALK'); } } } if (node.type === 'table') { items.Table = { label: 'Table', icon : 'fa fa-table', action: function () { renewLeftBox(node.id,'TABLE'); } } } return items; }
Пока писал статью, посетила меня шальная мысль, оформить браузер отдельным модулем, чтобы иметь возможность интегрировать его в любой другой проект. Оценил объем работы, попинал свою апатию, — ну его нафиг, не мальчик уже. Но всегда буду рад помочь, тем кто заинтересуется.
ссылка на оригинал статьи https://habr.com/ru/post/560454/
Добавить комментарий