Глава 7. Мониторинг сетей при помощи Python - Часть 1

Представим себе, что вы получаете вызов в 2 часа по полуночи ранним утром. Человек на другом конце провода спрашивает, Привет, мы столкнулись со сложной проблемой, которая влияет на нашу работу. Мы полагаем, что она может быть вызвана сетью. Можешь ли ты проверить это для нас? Что мы должны проверить в первую очередь? Естественно, мы должны взглянуть на ваш инструментарий мониторинга и убедиться имелись ли некие существенные изменения в замерах за последние несколько часов. на протяжении всей данной книги мы обсуждали различные способы программного предсказания изменений в вашей сетевой среде с целью сохранять вашу сетевую среду работающей настолько гладко, насколько это возможно.

Однако, сетевые среды не статичны. Далеки от этого, они, вероятно, одна из самых изменчивых частей всей вашей инфраструктуры. По определению, некая сеть соединяет различные части вместе, постоянно осуществляя обмен вперёд и назад. Имеется множество перемещаемых частей, которые могут вызвать останов работы вашей сети ожидаемым способом: отказ оборудования, баги в программном обеспечении, ошибки персонала, невзирая на его лучшие намерения и тому подобное. Нам необходим способ быть уверенным, что наша сетевая среда работает как ожидалось и что мы успешно будем уведомлены, если что- то пойдёт не так.

В последующих двух главах мы рассмотрим различные способы осуществления задач сетевого мониторинга. Многие из тех инструментов, которые мы рассматривали до сих пор могут быть связаны воедино или напрямую управляться из Python. Как и всё что мы рассматривали до настоящего момента, сетевой мониторинг должен работать с двумя частями. Первое, мы должны знать какую информацию может передавать наше оборудование. Второе, нам необходимо определить какую полезную информацию мы можем толковать из неё.

Мы рассмотрим ряд инструментов, которые позволят нам эффективно мониторить нашу сетевую среду:

  • Simple Network Management Protocol (SNMP).

  • Визуализацию Matplotlib и pygal.

  • MRTG и Cacti.

Этот перечень не исчерпывающий и, несомненно, нет недостатка в коммерческих производителях в данном сегменте. Однако основы сетевого мониторинга, которые мы рассмотрим, хорошо обслуживаются как средствами с открытым исходным кодом, так и коммерческим инструментарием.

Установка лаборатории

Наша лаборатория для данной главы аналогична той, которая была в последней главе, с единственной разницей: оба сетевых устройства являются приборами с IOSv. Это проиллюстрировано тут:

 

Рисунок 7.1



Для создания обмена в нашей сетевой среде будут применяться два имеющихся хоста Ubuntu с тем, чтобы мы могли наблюдать некие не нулевые счётчики.

SNMP

SNMP является стандартным протоколом, применяемым для сбора информации и управления устройствами. Хотя этот стандарт и позволяет вам применять SNMP для управления устройствами, по моей практике большинство сетевых администраторов предпочитает оставлять SNMP только как механизм для сбора некоторой информации. Поскольку SNMP работает поверх UDP, который не устанавливает соединение и рассматривается как относительно слабо защищённый механизм в версиях 1 и 2, внесение изменений с применением SNMP, как правило, осложняет работу сетевых администраторов. Версия 3 SNMP добавила криптографическую безопасность и новые понятия и терминологии в данный протокол, однако способ, каким она приспосабливается различается у производителей сетевых устройств.

SNMP широко применяется при мониторинге сетевых сред и появился в 1988 как часть RFC 1065. Все операции являются прямолинейными с отправкой диспетчером сети запросов GET и SET к устройству, а само устройство с имеющимся агентом SNMP отвечает определённой информацией на запрос. Наиболее широко распространённым стандартом является SNMPv2c, который определяется в RFC 1901 - RFC 1908. Он применяет некую простейшую схему безопасности на основе сообщества для сохранности. Он также ввёл некие новые свойства, такие как возможность получения больших информационных массивов. приводимая ниже схема отображает имеющиеся операции верхнего уровня для SNMP.

 

Рисунок 7.2


Операции SNMP (Источник)

Вся располагающаяся в определённом устройстве информация структурирована как База упраляющей информации (MIB, Management Information Base). Эта MIB применяет иерархическое пространство имён, содержащее некий Идентификатор объекта (OID, Object IDentifier), представляющий информацию, которая может быть считана и возвращена запрашивающей стороне. Когда мы обсуждаем применение SNMP для запросов информации устройств, мы на самом деле говорим об использовании состояния управления для определённого OID, который представляет позже нам эту информацию. Вам потребуется приложить некие усилия для объединения основной общей информации в некую единую структуру OID; однако окончательный выход всех ваших усилий зависит от того насколько успешно эти термины были указаны. По крайней мере, исходя из своего опыта, я обычно должен проверять по документации поставщика как определить тот OID, который нужен мне.

Некоторые из основополагающих моментов, которые помкогут выполнить эти действия:

  • Сама реализация в значительной степени зависит от того объёма информации, который может предоставить сам агент устройства. Это, в свою очередь зависит от того, как производитель трактует SNMP: как основную или как добавочную функцию.

  • Агентам SNMP обычно необходимо время ЦПУ от управляющего механизма для возвращения некоторого значения. Это не только не эффективно для устройств, скажем, с большими таблицами BGP, но также невозможно применять для повторяющихся запросов данных.

  • Самому пользователю необходимо знать определённый OID для определения в запросе на данные.

Поскольку SNMP имеется уже давно, я полагаю, что у вас уже имеется некий опыт работы с ним. Перейдём непосредственно к нашему первому примеру.

Установка

Вначале давайте убедимся, что само управляемое SNMP устройство и агент работают в нашей установке. Сам пакет SNMP может быть установлен либо на имеющемся хосте в нашей лаборатории, либо на управляемом устройстве в нашей сетевой среде управления. Пока наш диспетчер имеет досягаемость через IP к определённому устройству и само управляемое устройство допускает соединение с ним, SNMP должен работать нормально.

В своей настройке я установил SNMP и на хосте Ubuntu, и в своей управляемой сетевой среде, а также на определённом хосте клиента в своей лаборатории для проверки безопасности:


 sudo apt-get install snmp
		

Имеется множество необязательных параметров, которые вы можете настраивать в своём сетевом устройстве, такие как ваши контакт, местоположение, идентификатор корпуса, а также размер пакета SNMP. Эти опции являются специфическими для устройства и вы должны свериться со имеющейся документацией для вашего устройства. Для устройств IOSv мы настроим список доступа чтобы ограничить только тем хостом, который желателен для опроса самого прибора, а также свяжем список доступа со строкой сообщества SNMP. В нашем случае мы будем применять слово secret для строки сообщества и permit_snmp как имя доступа к списку:


 !
ip access-list standard permit_snmp
 permit 172.16.1.173 log
 deny any log
!
!
snmp-server community secret RO permit_snmp
!
		

Строка сообщества SNMP выступает в роли некоторого совместно применяемого пароля для самого диспетчера и имеющегося агента, её необходимо включать всякий раз, когда вы желаете опрашивать это устройство.

Мы можем воспользоваться инструментами, например, имеющимся локатором MIB (http://tools.cisco.com/ITDIT/MIBS/servlet/index) для отыскания определённого OID для запроса к нему. В качестве альтернативы мы просто должны пройтись по всему дереву SNMP, начав с основной вершины корпоративного дерева Cisco в .1.3.6.1.4.1.9:


$ snmpwalk -v2c -c secret 172.16.1.189 .1.3.6.1.4.1.9
iso.3.6.1.4.1.9.2.1.1.0 = STRING: "
Bootstrap program is IOSv
"
iso.3.6.1.4.1.9.2.1.2.0 = STRING: "reload"
iso.3.6.1.4.1.9.2.1.3.0 = STRING: "iosv-1"
iso.3.6.1.4.1.9.2.1.4.0 = STRING: "virl.info"
...
		

Мы можем быть очень определёнными в отношении того OID, который нам требуется для запросов:


$ snmpwalk -v2c -c secret 172.16.1.189 .1.3.6.1.4.1.9.2.1.61.0
iso.3.6.1.4.1.9.2.1.61.0 = STRING: "cisco Systems, Inc.
170 West Tasman Dr.
San Jose, CA 95134-1706
U.S.A.
Ph +1-408-526-4000
Customer service 1-800-553-6387 or +1-408-526-7208
24HR Emergency 1-800-553-2447 or +1-408-526-7209
Email Address tac@cisco.com
World Wide Web http://www.cisco.com"
		

Последний подлежащий проверке момент должен состоять в том, чтобы убедиться что сам список доступа будет запрещать нежелательные запросы SNMP. Поскольку у нас имеется ключевое слово log как для элементов разрешения, так и для элементов запрета, для опроса данного устройства разрешён только 172.16.1.173:


*Mar 3 20:30:32.179: %SEC-6-IPACCESSLOGNP: list permit_snmp permitted 0
172.16.1.173 -> 0.0.0.0, 1 packet
*Mar 3 20:30:33.991: %SEC-6-IPACCESSLOGNP: list permit_snmp denied 0
172.16.1.187 -> 0.0.0.0, 1 packet
		

как вы можете видеть, самый большой вызов при установке SNMP состоит в отыскании правильного OID. Некоторые из имеющихся OID определяются в стандарте MIB-2; прочие находятся в части дерева своей корпорации. Однако наилучшей подсказкой является документация производителя. Имеется множество инструментов, которые могут оказать вам помощь, например, MIB Browser; вы можете добавить MIB (опять же, предоставленные производителями) в этот браузер и смотреть описание всех OID на основе корпоративной адресации. Такой инструмент, как Cisco's SNMP Object Navigator оказывается очень ценным, когда вам требуется найти правильный OID искомого вами объекта.

PySNMP

PySNMP является переносимым механизмом SNMP на чистом Python, реализованным разработкой Ilya Etingof (https://github.com/etingof). Он абстрагирует для вас множество подробностей SNMP, как это делают величайшие библиотеки, а также поддерживает и Python 2, и Python 3.

Для PySNMP требуется пакет PyASN1. Согласно Wikipedia: "ASN.1 является неким стандартом и системой обозначений, которые описывают правила и структуры для представления, кодирования передачи и декодирования данных в телекоммуникации и вычислительных сетях. - https://asn1js.org/"

PyASN1 обычно предоставляет некую обёртку Python поверх ASN.1. Давайте установим для начала этот пакет:


cd /tmp
git clone https://github.com/etingof/pyasn1.git
cd pyasn1/
sudo python3 setup.py install
		

Затем установим сам пакет PySNMP:


git clone https://github.com/etingof/pysnmp
cd pysnmp/
sudo python3 setup.py install
		
[Совет]Совет

На момент написания, имелся ряд ошибок, которые не были пока помещены в сам репозиторий PyPI. Эти пакаеты также могут быть установлены через pip; sudo pip3 install pysnmp автоматически установит pyasn1.

Давайте взглянем на то, как PySNMP запрашивает ту же самую контактную информацию, которую мы применяли в предыдущем примере, который слегка изменён из примера PySNMP по ссылке http://pysnmp.sourceforge.net/faq/response-values-mib-resolution.html. Мы импортируем все необходимые модули и для начала создадим некий объект CommandGenerator:


>>> from pysnmp.entity.rfc3413.oneliner import cmdgen
>>> cmdGen = cmdgen.CommandGenerator()
>>> cisco_contact_info_oid = "1.3.6.1.4.1.9.2.1.61.0"
		

Мы можем исполнить SNMP применив команду getCmd. Полученным результатом является распаковка в различные переменные; из них нас прежде всего заботит varBinds, которая содержит сам результат запроса:


>>> errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(
... cmdgen.CommunityData('secret'),
... cmdgen.UdpTransportTarget(('172.16.1.189', 161)),
... cisco_contact_info_oid
... )
>>> for name, val in varBinds:
... print('%s = %s' % (name.prettyPrint(), str(val)))
...
SNMPv2-SMI::enterprises.9.2.1.61.0 = cisco Systems, Inc.
170 West Tasman Dr.
San Jose, CA 95134-1706
U.S.A.
Ph +1-408-526-4000
Customer service 1-800-553-6387 or +1-408-526-7208
24HR Emergency 1-800-553-2447 or +1-408-526-7209
Email Address tac@cisco.com
World Wide Web http://www.cisco.com
>>>
		

Отметим, что полученные значения отклика являются объектами PyASN1. Имеющийся метод prettyPrint() преобразует некоторые из этих значений в читаемый человеком формат, однако, поскольку в нашем случае не все результаты могут быть преобразованы, мы выполним преобразование в строковое представление вручную.

Мы можем поместить некий сценарий, применённый в предыдущем интерактивном примере в pysnmp_1.py с проверкой соответствующих ошибок исли мы встретимся с проблемами. Мы также можем вулючить в свой метод getCmd() множество OID:


system_up_time_oid = "1.3.6.1.2.1.1.3.0"
cisco_contact_info_oid = "1.3.6.1.4.1.9.2.1.61.0"

errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(
 cmdgen.CommunityData('secret'),
 cmdgen.UdpTransportTarget(('172.16.1.189', 161)),
 system_up_time_oid,
 cisco_contact_info_oid
)
 	   

Результатом будет всего лишь распаковка и она перечисляется в нашем примере:


$ python3 pysnmp_1.py
SNMPv2-MIB::sysUpTime.0 = 16052379
SNMPv2-SMI::enterprises.9.2.1.61.0 = cisco Systems, Inc.
170 West Tasman Dr.
....
		

В следующем примере мы сохраним все полученные из нашего запроса значения с тем, чтобы мы могли выполнить прочие функции, такие как визуализация, для полученных данных. В нашем примере мы воспользуемся ifEntry внутри общего дерева MIB-2. Вы можете отыскать некий номер ресурса, соответствующий этому дереву ifEntry; вот некий снимок экрана с сайта Cisco SNMP Object Navigator, к которому мы обращались ранее:

 

Рисунок 7.3


OID дерево ifEntry SNMP

В качестве быстрой проверки мы можем проиллюстрировать соответствие всех интерфейсов устройствам:


$ snmpwalk -v2c -c secret 172.16.1.189 .1.3.6.1.2.1.2.2.1.2
iso.3.6.1.2.1.2.2.1.2.1 = STRING: "GigabitEthernet0/0"
iso.3.6.1.2.1.2.2.1.2.2 = STRING: "GigabitEthernet0/1"
iso.3.6.1.2.1.2.2.1.2.3 = STRING: "GigabitEthernet0/2"
iso.3.6.1.2.1.2.2.1.2.4 = STRING: "Null0"
iso.3.6.1.2.1.2.2.1.2.5 = STRING: "Loopback0"
		

Согласно документации, мы можем поставить соответствие значений ifOutOctets(10), ifInUcastPkts(11), ifOutOctets(16) и ifOutUcastPkts(17). Быстрой проверкой GigabitEthernet0/0 в имеющемся OID 1.3.6.1.2.1.2.2.1.17.1 можно сравнить значения в командной строке и в SNMP. Эти значения должны быть близкими, но не в точности равными, так как в проводах может иметься некий обмен:


# Вывод командной строки
iosv-1#sh int gig 0/0 | i packets
5 minute input rate 0 bits/sec, 0 packets/sec
5 minute output rate 0 bits/sec, 0 packets/sec
38532 packets input, 3635282 bytes, 0 no buffer
53965 packets output, 4723884 bytes, 0 underruns

# Вывод SNMP
$ snmpwalk -v2c -c secret 172.16.1.189 .1.3.6.1.2.1.2.2.1.17.1
iso.3.6.1.2.1.2.2.1.17.1 = Counter32: 54070
		

Когда мы запустим решение в промышленную эксплуатацию, мы будем записывать все результаты запрсоов в некую базу данных.

С целью упрощения примера, мы запишем полученные значения запроса в простой файл. В pysnmp_3.py мы определили различные OID, которые нам нужно опрашивать:


# Hostname OID
system_name = '1.3.6.1.2.1.1.5.0'

# Interface OID
gig0_0_in_oct = '1.3.6.1.2.1.2.2.1.10.1'
gig0_0_in_uPackets = '1.3.6.1.2.1.2.2.1.11.1'
gig0_0_out_oct = '1.3.6.1.2.1.2.2.1.16.1'
gig0_0_out_uPackets = '1.3.6.1.2.1.2.2.1.17.1'
		

Эти значения мы потребляем в своей функции snmp_query() совместно с именами хоста, сообщества и OID на входе:


def snmp_query(host, community, oid):
    errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(
    cmdgen.CommunityData(community),
    cmdgen.UdpTransportTarget((host, 161)),
    oid
    )
 	   

Все эти значения помещаются в некий словарь с различными ключами и записываются в некий файл с названием results.txt:


    result = {}
    result['Time'] = datetime.datetime.utcnow().isoformat()
    result['hostname'] = snmp_query(host, community, system_name)
    result['Gig0-0_In_Octet'] = snmp_query(host, community, gig0_0_in_oct)
    result['Gig0-0_In_uPackets'] = snmp_query(host, community, gig0_0_in_uPackets)
    result['Gig0-0_Out_Octet'] = snmp_query(host, community, gig0_0_out_oct)
    result['Gig0-0_Out_uPackets'] = snmp_query(host, community, gig0_0_out_uPackets)

    with open('/home/echou/Master_Python_Networking/Chapter7/results.txt', 'a') as f:
        f.write(str(result))
        f.write('\n')
 	   

На выходе будет некий файл с результатами, отображающими все номера, представленные на момент нашего запроса:


# Пример вывода
$ cat results.txt
{'hostname': 'iosv-1.virl.info', 'Gig0-0_In_uPackets': '42005', 'Time':
'2017-03-06T02:11:54.989034', 'Gig0-0_Out_uPackets': '59733',
'Gig0-0_In_Octet': '3969762', 'Gig0-0_Out_Octet': '5199970'}
		

Мы можем сделать этот сценарий исполняемым и подключить к расписанию заданий cron для исполнения каждые 5 минут:


$ chmod +x pysnmp_3.py

# Crontab configuration
*/5 * * * * /home/echou/Master_Python_Networking/Chapter7/pysnmp_3.py
		

Как уже упоминалось, в среде промышленной реализации мы бы помещали всю информацию в некую базу данных. В базе данных NoSQL мы можем применять время в качестве индекса (или ключа), так как оно всегда уникально, после чего следуют различные пары ключ- значение.

Мы подождём пока сценарий не исполнится несколько раз и перейдём к тому как мы можем применять Python для визуализации полученных данных.

Визуализация Python

мы собираем сетевые данные для своих целей получения инсайта нашей сетевой среды. Один из наилучших способов знать что означают имеющиеся данные это визуализировать их с помощью графиков. Это истинно практически для любых данных, но в особенности справедливо для временных последовательностей данных в контексте сетевого мониторинга. Сколько данных было передано по вашим проводам за самую последнюю неделю? Какое процентное соотношение составил протокол TCP во всём трафике? Именно эти значения мы можем тщательно выбрать с применением механизмов получения данных, таких как SNMP, и визуализировать при помощи некоторых популярных библиотек Python.

В данном разделе мы воспользуемся теми данными, которые мы накопили в последнем разделе SNMP и применим две популярные библиотеки Python - Matplotlib и Pygal - для их графического представления.

Matplotlib

Matplotlib (matplotlib.org) является некоторой библиотекой отрисовки для основной библиотеки Python и её математического расширения NumPy. Она может предоставлять рисунки типографского качества, такие как диаграммы, гистограммы, а также столбиковые графики в несколько строк кода.

[Замечание]Замечание

NumPy является неким расширением самого языка программирования Python. Это открытый исходный код и он широко применяется в различных проектах научных данных. Вы можете получить дополнительную информацию о нём на https://en.wikipedia.org/wiki/NumPy.

Установка

Вся установка может быть осуществлена с использованием конкретной системы управления пакетами Linux, зависящей от вашего дистрибутива:


$ sudo apt-get install python-matplotlib
$ sudo apt-get install python3-matplotlib
		

Первый пример Matplotlib

Для последующих примеров по умолчанию все рисунки отображаются в виде стандартного вывода; будет проще если вы попробуете их выводить на стандартный вывод. Если вы следовали за данной книгой с применением некоторой виртуальной машины, рекомендуется чтобы вы применяли ВМ Windows вместо SSH. Если у вас нет доступа к требуемому стандартному выводу, вы можете сохранять все рисунки и просматривать их после выгрузки (как мы это вскоре увидим). Отметим, что вам потребуется установить необходимую переменную $DISPLAY в некоторых из представленных далее графиков.

Некое построение линейного графика просто задаётся двумя списками чисел, которые относятся к значениям по оси x и по оси y:


>>> import matplotlib.pyplot as plt
>>> plt.plot([0,1,2,3,4], [0,10,20,30,40])
[<matplotlib.lines.Line2D object at 0x7f932510df98>]
>>> plt.ylabel('Something on Y')
<matplotlib.text.Text object at 0x7f93251546a0>
>>> plt.xlabel('Something on X')
<matplotlib.text.Text object at 0x7f9325fdb9e8>
>>> plt.show()
		

Данный график отобразит некую линию:

 

Рисунок 7.4


Линейный график Matplotlib

В качестве альтернативы, если у вас нет доступа к стандартному выводу или вам придётся вначале сохранить данный рисунок, вы можете воспользоваться методом savefig():


>>> plt.savefig('figure1.png')
или
>>> plt.savefig('figure1.pdf')
		

С помощью этих основных знаний по рисованию графиков мы теперь можем выводить графические результаты, которые мы получаем из запросов SNMP.

Результаты Matplotlib для SNMP

В нашем первом примере, а именно matplotlib_1.py, мы импортируем необходимый модуль dates вовнутрь pyplot. Мы будем применять модуль matplotlib.dates вместо модуля данных стандартной библиотеки Python из- за того способа, который требуется нам для применения данным модулем и заключающегося в том как Matplotlib будет внутренне преобразовывать все значения данных в значения с плавающей запятой.


import matplotlib.pyplot as plt
import matplotlib.dates as dates
 	   
[Совет]Совет

Matplotlib предоставляет сложные возможности отрисовки данных; вы можете дополнительные сведения о нём на matplotlib.org/api/dates_api.html.

Мы создадим два пустых списка, причём каждый из них представляет значения по оси x и по оси y. Отметим, что в строке 12 мы применяем встроенную функцию Python eval() для чтения своего ввода в качестве словаря вместо некоторой строки по умолчанию:


x_time = []
y_value = []

with open('results.txt', 'r') as f:
    for line in f.readlines():
        line = eval(line)
        x_time.append(dates.datestr2num(line['Time']))
        y_value.append(line['Gig0-0_Out_uPackets'])
 	   

Чтобы считать значения по оси x в пригодном для считывания человеком формате данных нам потребуется применить функцию plot_date() вместо plot(). Мы также слегка изменим имеющийся размер рисунка и развернём все значения по оси x с тем, чтобы могли считать все значения целиком:


plt.subplots_adjust(bottom=0.3)
plt.xticks(rotation=80)

plt.plot_date(x_time, y_value)
plt.title('Router1 G0/0')
plt.xlabel('Time in UTC')
plt.ylabel('Output Unicast Packets')
plt.savefig('matplotlib_1_result.png')
plt.show()
 	   

Наш окончательный результат будет отображён в Router1 Gig0/0 Unicast Output Packet следующим образом:

 

Рисунок 7.5


График Router1 Matplotlib

Отметим, что если вы предпочитаете сплошную линию вместо точек, вы можете воспользоваться третьим необязательным параметром в функции plot_date():


plt.plot_date(x_time, y_value, "-")
 	   

Мы можем повторить все шаги для оставшихся значений для вывода октетов, однонаправленных входящих пакетов, а также ввода как отдельных графиков. Однако, в нашем следующем примере, которым является matplotlib_2.py, мы отобразим как нарисовать множество графических значений в одном и том же временном диапазоне помимо дополнительных вариантов Matplotlib.

В данном случае мы создадим дополнительные списки и наполним их соответствующими значениями:


x_time = []
out_octets = []
out_packets = []
in_octets = []
in_packets = []

with open('results.txt', 'r') as f:
    for line in f.readlines():
...
        out_packets.append(line['Gig0-0_Out_uPackets'])
        out_octets.append(line['Gig0-0_Out_Octet'])
        in_packets.append(line['Gig0-0_In_uPackets'])
        in_octets.append(line['Gig0-0_In_Octet'])
 	   

Поскольку у нас имеются идентичные значения по оси x, мы просто можем добавлять все различные значения по оси y в один и тот же график:


# Применяем plot_date для отображения данных по оси x 
plt.plot_date(x_time, out_packets, '-', label='Out Packets')
plt.plot_date(x_time, out_octets, '-', label='Out Octets')
plt.plot_date(x_time, in_packets, '-', label='In Packets')
plt.plot_date(x_time, in_octets, '-', label='In Octets')
 	   

Кроме того дабавим решётку и легнду для данного графика:


plt.legend(loc='upper left')
plt.grid(True)
 	   

Окончательный результат будет комбинацией всех имеющихся значений в некотором отдельном графике. Отметим, что некоторые из значений в верхнем левом углу перекрываются текстом легенды. Вы можете изменить размер самого рисунка и/ или воспользоваться параметром pan/zoom для перемещения по графику чтобы увидеть все значения.

 

Рисунок 7.6


График Router1 Matplotlib со множеством линий

Имеется множество дополнительных графических опций, доступных в Matplotlib; мы несомненно не ограничены только вычерчиванием графиков. Например, мы можем воспользоваться следующими пробными данными для отрисовки имеющихся процентных значений различных типов обмена, которые мы видим в кабеле:


#!/usr/bin/env python3
# При мер из http://matplotlib.org/2.0.0/examples/pie_and_polar_charts/pie_demo_features.html
import matplotlib.pyplot as plt
# Долевой график, в котором все доли будут отранжированы и выведены против часовой стрелки:
labels = 'TCP', 'UDP', 'ICMP', 'Others'
sizes = [15, 30, 45, 10]
explode = (0, 0.1, 0, 0) # Выделить UDP
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)
ax1.axis('equal') # Эквивалентное соотношение сторон гарантирует что доли нарисованы в виде круга.

plt.show()
		

Приведённый выше код имеет результатом следующую долевую диаграмму из plt.show():

 

Рисунок 7.7


Долевой график Matplotlib

Дополнительные ресурсы Matplotlib

Matplotlib является одной из наилучших библиотек рисования Python, которая предоставляет рисунки типографского качества. Ку и у Python, у неё имеется цель сделать сложные задачи простыми. имея более 4 800 звёзд на GitHub, это, помимо всего прочего, один из наиболее популярных проектов с открытым исходным кодом. Он напрямую транслируется в исправления ошибок, пользовательское сообщество и всеобщее применение. Чтобы изучить данный пакет потребуется некоторое время, но оно окупит все усилия сторицей.

[Замечание]Замечание

В данном разделе мы всего лишь провели царапину по поверхности Matplotlib. Вы можете найти дополнительные ресурсы на Странице проекта Matplotlib и в GitHub репозитории Matplotlib.

В следующем разделе мы взглянем на другую популярную графическую библиотеку Python: Pygal.

Pygal

Pygal является некоторой динамической библиотекой составления графиков SVG, написанной на Python. Самое основное преимущество Pygal, по моему мнению, состоит в том что она просто и естественным путём создаёт формат масштабируемой векторной графики (SVG, Scalable Vector Graphics). Имеется множество преимуществ SVG над прочими графическими форматами, но два из основных состоят в том, что он дружественен к веб браузерам и что он предоставляет масштабируемость без ущерба для качества изображения. Другими словами, вы можете отображать все результирующие изображения в любом современном веб браузере и изменять его размер вперёд и назад без утраты подробностей данного графика.

Установка

Установка выполняется посредством pip:


$ sudo pip install pygal
$ sudo pip3 install pygal
		

Первый пример Pygal

Давайте взглянем на пример вычерчивания линии, продемонстрированный в документации Pygal, доступной по адресу: http://pygal.org/en/stable/documentation/types/line.html:


>>> import pygal
>>> line_chart = pygal.Line()
>>> line_chart.title = 'Browser usage evolution (in %)'
>>> line_chart.x_labels = map(str, range(2002, 2013))
>>> line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1])
<pygal.graph.line.Line object at 0x7fa0bb009c50>
>>> line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3])
<pygal.graph.line.Line object at 0x7fa0bb009c50>
>>> line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])
<pygal.graph.line.Line object at 0x7fa0bb009c50>
>>> line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5])
<pygal.graph.line.Line object at 0x7fa0bb009c50>
>>> line_chart.render_to_file('pygal_example_1.svg')
		
[Замечание]Замечание

В данном примере мы создаём некий линейный объект с x_labels, автоматически представляемых как строки для 11 блоков. Каждый из этих объектов может быть снабжён определённой пометкой и самим значением в виде некоторого списка, например, Firefox, Chrome и IE.

Вот просмотр получающегося в результате графика в Firefox:

 

Рисунок 7.8


Простой график Pygal

Мы можем применять тот же самый метод для вывода графических результатов SNMP, которые имеются у нас на руках. мы сделаем это в следующем разделе.

Результаты Pygal для SNMP

Для линейных графиков Pygal мы в основном можем следовать тому же самому шаблону, что и в нашем примере Matplotlib, в котором мы создали определённый список значений прочитав их из указанного файла. Нам больше нет нужды конвертировать свои значения по оси x в некий внутренний формат, как мы это делали для Matplotlib; однако, нам в действительности потребуется преобразовать все числа для каждого значения, которые мы получим в виде с плавающей запятой:


with open('results.txt', 'r') as f:
    for line in f.readlines():
        line = eval(line)
        x_time.append(line['Time'])
        out_packets.append(float(line['Gig0-0_Out_uPackets']))
        out_octets.append(float(line['Gig0-0_Out_Octet']))
        in_packets.append(float(line['Gig0-0_In_uPackets']))
        in_octets.append(float(line['Gig0-0_In_Octet']))
 	   

Мы можем воспользоваться тем же самым механизмом, который мы наблюдали при построении своего линейного графика:


line_chart = pygal.Line()
line_chart.title = "Router 1 Gig0/0"
line_chart.x_labels = x_time
line_chart.add('out_octets', out_octets)
line_chart.add('out_packets', out_packets)
line_chart.add('in_octets', in_octets)
line_chart.add('in_packets', in_packets)
line_chart.render_to_file('pygal_example_2.svg')
 	   

Окончательный вывод аналогичен тому, что мы уже наблюдали, однако данный результат представлен в формате SVG, который проще отображать в некоторой веб странице. Он может быть просмотрен из некоторого браузера следующим образом:

 

Рисунок 7.9


График Pygal Router 1 со множеством линий

В точности как и Matplotlib, Pygal предоставляет множество дополнительных возможностей для вычерчивания графиков. Например, для того чтобы перерисовать долевую диаграмму в Pygal, мы можем воспользоваться объектом pygal.Pie():


#!/usr/bin/env python3

import pygal

line_chart = pygal.Pie()
line_chart.title = "Protocol Breakdown"
line_chart.add('TCP', 15)
line_chart.add('UDP', 30)
line_chart.add('ICMP', 45)
line_chart.add('Others', 10)
line_chart.render_to_file('pygal_example_3.svg')
 	   

Результирующий файл SVG будет аналогичен тому PNG, который создавался Matplotlib:

 

Рисунок 7.10


Долевой график Pygal

Дополнительные ресурсы Pygal

Pygal предоставляет множество дополнительных индивидуально настраиваемых свойств и графических возможностей для тех данных, которые вы собираете из более базовых инструментов сетевого мониторинга, таких как SNMP. Мы продемонстрировали здесь простейшие линейный и долевой графики. Вы можете обнаружить дополнительную информацию о данном проекте тут:

В нашем следующем разделе мы продолжим тему сетевого мониторинга SNMP, однако для полностью укомплектованной системы сетевого наблюдения под названием Cacti.

Python для Cacti

В свои молодые годы, когда я работал сетевым инженером, мы применяли межплатформный инструментарий с открытым кодом Multi Router Traffic Grapher (MRTG) для проверки нагрузки обмена в сетевых соединениях. Это была одна из самых первых систем мониторинга сетевых сред высокого уровня с открытым исходным кодом, которая абстрагировалась для сетевых инженеров от подробностей SNMP, баз данных и HTML. Затем появился Round-Robin Database Tool (RRDtool). В своём первом выпуске в 1999 он назывался "Правильно сделанным MRTG". Он существенно улучшил производительность серверов базы данных и опрашивающих систем.

Выпущенный в 2001, Cacti, является инструментом сетевого мониторинга и графического отображения с открытым исходным кодом, разработанным как улучшенный интерфейс для RRDtool. Благодаря наследию MRTG и RRDtool вы обнаружите некоторые знакомые графические схемы, шаблоны и опросы SNMP. Будучи поставляемым в пакете инструментом, его установка и применение должны оставаться в рамках самого инструмента. Однако Cacti предлагает функциональность персональных запросов данных, которую мы мы можем применять для Python. В данном разделе мы рассмотрим как можно применять Python в качестве методики для Cacti.

Установка

Установка в Ubuntu незатейлива; установите Ubuntu под управлением ВМ:


$ sudo apt-get install cacti
		

Это включит последовательность шагов установки и настройки, включая действия для базы данных MySQL, веб сервера (Apache или lighthttpd), а также различных задач конфигурирования. После установки для начала работы перейдите на http://<ip>/cacti. Самый последний шаг состоит в регистрации с установленными по умолчанию именем пользователя и паролем (admin/admin); вы получите запрос на изменение установленного пароля.

После регистрации вы можете согласно документации добавить некое устройство и сопоставить его с каким- то шаблоном. Существует предварительно подготовленный шаблон Cisco, с которым вы можете продолжить. Cacti имеет хорошую документацию по добавлению устройств и созданию вашего собственного первого графика, поэтому мы быстро взглянем на некоторые снимки экрана, которые вам могут встретиться:

 

Рисунок 7.11



Опознавательная индикация, что ваш SNMP работает, с тем, чтобы вы могли наблюдать работоспособность данного устройства:

 

Рисунок 7.12



Для интерфейса обмена и прочей статистики вы можете добавлять графики:

 

Рисунок 7.13



Со временем вы начнёте отслеживать обмен как это отображается здесь:

 

Рисунок 7.14



Теперь мы готовы рассмотреть как применять сценарии Python для расширения функциональности Cacti по сбору данных.

Сценарий Python как источник входных данных

Имеются два документа, с которыми следует ознакомиться прежде чем начать применять наш сценарий Python в качестве источника ввода:

Будет интересно узнать какие варианты использования сценария Python применяются для расширения ввода данных? Один из вариантов использования мог бы состоять в обеспечении мониторинга ресурсов, не имеющих соответствующего OID. Скажем, вы бы желали знать сколько раз имеющийся список доступа permit_snmp разрешил доступ хосту 172.16.1.173 проведение некоторого запроса SNMP. Мы знаем, что мы можем видеть общее число соответствий через CLI:


iosv-1#sh ip access-lists permit_snmp | i 172.16.1.173
    10 permit 172.16.1.173 log (6362 matches)
		

Однако есть вероятность, что связанный с этим OID отсутствует (или мы можем притвориться, что его нет). Именно тут мы можем применить некий внешний сценарий для осуществления некоего вывода, который может быть употреблён самим хостом Cacti.

Мы можем повторно воспользоваться сценарием Pexpect, который мы уже обсуждали в Главе 2, Взаимодействие с сетевым устройством на нижнем уровне, chapter1_1.py. Мы переименуем его в cacti_1.py. Всё должно быть знакомо по первоначальному сценарию, за исключением того, что мы будем исполнять свою команду CLI и сохраним её вывод:


for device in devices.keys():
...
    child.sendline('sh ip access-lists permit_snmp | i 172.16.1.173')
    child.expect(device_prompt)
    output = child.before
...
 	   

Появится представленный ниже вывод в его сыром виде:


b'sh ip access-lists permit_snmp | i 172.16.1.173\r\n 10 permit 172.16.1.173 log (6428 matches)\r\n'
		

Мы можем воспользоваться функцией split() для данной строки чтобы оставить только общее число соответствий и вывести его в стандартный вывод в своём сценарии:


print(str(output).split('(')[1].split()[0])
 	   

Для проверки мы можем посмотреть некоторое число накапливаемых изменений, выполнив данный сценарий некоторое число раз:


$ ./cacti_1.py
6428
$ ./cacti_1.py
6560
$ ./cacti_1.py
6758
		

Мы можем сделать этот сценарий исполняемым и поместить его в местоположение по умолчанию сценариев Cacti:


$ chmod a+x cacti_1.py
$ sudo cp cacti_1.py /usr/share/cacti/site/scripts/
		

Документация Cacti предоставляет подробные шаги по тому как добавлять результаты сценария в общий график вывода. Эти шаги включают добавление самого сценария как некоторого метода ввода данных, добавление необходимого метода в источник данных и последующего создания некоторого графика для просмотра:

 

Рисунок 7.15



SNMP является общим методом предоставления служб сетевого мониторинга для ваших устройств. RRDtool с Cacti в качестве интерфейса предоставляет хорошую платформу для применения ко всем вашим сетевым устройствам через SNMP.

Выводы

В данной главе мы изучили как осуществлять сетевой мониторинг через SNMP. Мы настроили относящиеся к SNMP команды на ваших сетевых устройствах и воспользовались своей ВМ сетевого управления с системой зпросов SNMP для опроса имеющихся устройств. Мы применили модуль PySNMP для упрощения автоматизации своих запросом SNMP. Вы также изучили как сохранять результаты запросов в обычных файлах для применения в последующих примерах.

Позже в этой главе мы применили два различных пакета визуализации Python, а именно, Matplotlib и Pygal, для графического отображения результатов SNMP. Каждый пакет имеет свои собственные преимущества. Matplotlib является зрелым проектом с богатыми функциями, который широко применяется в научных данных. Pygal вырабатывает графики в формате SVG, которые являются гибкими и дружественными веб миру.

Ближе к концу данной главы мы взглянули на Cacti, некую систему сетевого мониторинга на основе SNMP, а также то, как применять Python для расширения возможностей мониторинга данной платформы.

В следующей главе мы продолжим обсуждать имеющиеся инструменты, которые могут применяться для мониторинга наших сетевых сред и получения их внутренней информации о том велёт ли себя наша сеть так, как это ожидалось. Мы рассмотрим потоковый мониторинг с применением NetFlow, sFlow и IPFIX. Мы также применим такие инструменты как Graphviz для визуализации нашей сетевой топологии и определения любых изменений топологии. Наконец, мы применим такие инструменты как Elasticsearch, Logstash и Kibana, обычно называемые стеком ELK, для мониторинга данных сетевого журнала, а также прочих сетевых подключений.