Мониторим каналы связи посредством Juniper RPM и Zabbix +10


На написание статьи меня натолкнул этот материал — Автоматическое переключение маршрута в Juniper SRX.


Захотелось немного расширить тему использования RPM. Эта технология является аналогом механизма SLA в мире Cisco, и как и у Cisco предназначена больше не для переключения каналов, а для измерения характеристик каналов в реальном времени. И цель моей статьи в том, чтобы показать как результаты этих измерений можно передать в систему мониторинга Zabbix. Надеюсь, эта информация кому нибудь пригодится. Поехали.


краткое введение в Juniper RPM


Juniper RPM расшифровывается как Realtime Perfomance Monitoring. Работает RPM примерно следующим образом:



Устройство с одной стороны канала (Client) периодически посылает ряд запросов на устройство (Server) на другой стороне канала, получает ответы (или неполучает) и сохраняет результаты


Запросы бывают следующих типов:


  • HTTP GET request at a target URL
  • HTTP GET request for metadata at a target URL
  • ICMP echo request to a target address (the default)
  • ICMP timestamp request to a target address
  • UDP ping packets to a target device
  • UDP timestamp requests to a target address
  • TCP ping packets to a target device

Первые два типа запросов относятся, очевидно, не совсем к качеству канала, а скорее к доступности и расторопности web-cервиса.


Последние 4 запроса являются расширенными и требуют поддержки RPM со стороны устройства с ролью Server. Кроме поддержки RPM в железе, для этих тестов так же требуется и расширенная лицензия. В моем случае и для роли Client и для роли Server я использую коммутаторы ex2200 с базовой лицензией и роль RPM Server-а для расширенных тесов я применить не могу.


Поэтому в этой статье я ограничусь запросами типа ICMP echo request. Тем более что это гораздо более универсальный сценарий. Роль Server может выполнить абсолютно любое сетевое устройство умеющее отвечать на ping.


Моя схема тестирования выглядит следующим образом:



У нас есть два L2 канала между офисами от двух операторов связи. К обоим каналам цепляем сбоку свои устройства. Тут как и на верхней картине, устройство с ролью Client размещено слева. В принципе достаточно было использовать по одному устройству с каждой стороны, но так сложилось, что к моменту организации тестирования устройства ex-isp1 и ex-isp2 уже использовались на этом участке сети. Использовались они разумеется как коммутаторы.


Собственно со схемой все. Переходим к конфигурации RPM. На устройстве ex2200-rpm пописываем следующую конфигурацию:


iddqd@ex2200-rpm> show configuration services rpm          

probe Gee {
    test Jitter {
        probe-type icmp-ping-timestamp;
        target address 2.2.2.2;
        probe-count 15;
        probe-interval 1;
        test-interval 15;
        source-address 2.2.2.1;
        data-size 1400;
        thresholds {
            successive-loss 2;
        }
        hardware-timestamp;
    }
}
probe BARS {
    test Jitter {
        probe-type icmp-ping-timestamp;
        target address 1.1.1.2;
        probe-count 15;
        probe-interval 1;
        test-interval 15;
        source-address 1.1.1.1;
        data-size 1400;
        thresholds {
            successive-loss 2;
        }
        hardware-timestamp;
    }
}

Конфигурация, как говорится, self-explanatory и особых пояснений не требует.


Делаем commit and-quit и через минуту уже можно собирать результаты тестов


iddqd@ex2200-rpm# show services rpm probe-results
Owner: Gee, Test: Jitter
    Target address: 2.2.2.2, Source address: 2.2.2.1, Probe type: icmp-ping-timestamp, Test size: 15 probes
    Probe results:
      Response received, Fri Apr 28 10:38:11 2017, Client and server hardware timestamps
      Rtt: 4908 usec, Round trip jitter: -232 usec, Round trip interarrival jitter: 1257 usec
    Results over current test:
      Probes sent: 7, Probes received: 7, Loss percentage: 0.000000
      Measurement: Round trip time
        Samples: 7, Minimum: 1921 usec, Maximum: 5243 usec, Average: 3355 usec, Peak to peak: 3322 usec, Stddev: 1514 usec, Sum: 23486 usec
      Measurement: Positive round trip jitter
        Samples: 3, Minimum: 262 usec, Maximum: 3322 usec, Average: 2179 usec, Peak to peak: 3060 usec, Stddev: 1364 usec, Sum: 6536 usec
      Measurement: Negative round trip jitter
        Samples: 4, Minimum: 232 usec, Maximum: 3179 usec, Average: 1682 usec, Peak to peak: 2947 usec, Stddev: 1448 usec, Sum: 6728 usec
    Results over last test:
      Probes sent: 15, Probes received: 15, Loss percentage: 0.000000
      Test completed on Fri Apr 28 10:37:50 2017
      Measurement: Round trip time
        Samples: 15, Minimum: 1882 usec, Maximum: 5099 usec, Average: 2502 usec, Peak to peak: 3217 usec, Stddev: 864 usec, Sum: 37535 usec
      Measurement: Positive round trip jitter
        Samples: 7, Minimum: 39 usec, Maximum: 3175 usec, Average: 1000 usec, Peak to peak: 3136 usec, Stddev: 979 usec, Sum: 7000 usec
      Measurement: Negative round trip jitter
        Samples: 8, Minimum: 26 usec, Maximum: 1444 usec, Average: 476 usec, Peak to peak: 1418 usec, Stddev: 494 usec, Sum: 3809 usec
    Results over all tests:
      Probes sent: 124282, Probes received: 124282, Loss percentage: 0.000000
      Measurement: Round trip time
        Samples: 124282, Minimum: 1548 usec, Maximum: 208183 usec, Average: 2964 usec, Peak to peak: 206635 usec, Stddev: 2148 usec,
        Sum: 368337928 usec
      Measurement: Ingress delay
        Samples: 101, Minimum: 1000 usec, Maximum: 6000 usec, Average: 2030 usec, Peak to peak: 5000 usec, Stddev: 1438 usec, Sum: 205000 usec
      Measurement: Egress delay
        Samples: 77, Minimum: 1000 usec, Maximum: 6000 usec, Average: 1883 usec, Peak to peak: 5000 usec, Stddev: 980 usec, Sum: 145000 usec
      Measurement: Positive round trip jitter
        Samples: 62713, Minimum: 0 usec, Maximum: 205349 usec, Average: 1152 usec, Peak to peak: 205349 usec, Stddev: 1866 usec, Sum: 72214061 usec
      Measurement: Negative round trip jitter
        Samples: 61568, Minimum: 1 usec, Maximum: 174369 usec, Average: 1173 usec, Peak to peak: 174368 usec, Stddev: 1645 usec, Sum: 72211519 usec

    Owner: BARS, Test: Jitter
    Target address: 1.1.1.2, Source address: 1.1.1.1, Probe type: icmp-ping-timestamp, Test size: 15 probes
    Probe results:
      Response received, Fri Apr 28 10:38:08 2017, Client and server hardware timestamps
      Rtt: 2695 usec, Round trip jitter: -109 usec, Round trip interarrival jitter: 1178 usec
    Results over current test:
      Probes sent: 15, Probes received: 15, Loss percentage: 0.000000
      Measurement: Round trip time
        Samples: 15, Minimum: 1654 usec, Maximum: 5020 usec, Average: 2630 usec, Peak to peak: 3366 usec, Stddev: 1105 usec, Sum: 39452 usec
      Measurement: Positive round trip jitter
        Samples: 6, Minimum: 20 usec, Maximum: 3079 usec, Average: 1504 usec, Peak to peak: 3059 usec, Stddev: 918 usec, Sum: 9021 usec
      Measurement: Negative round trip jitter
        Samples: 9, Minimum: 23 usec, Maximum: 3143 usec, Average: 1186 usec, Peak to peak: 3120 usec, Stddev: 1235 usec, Sum: 10671 usec
    Results over last test:
      Probes sent: 15, Probes received: 15, Loss percentage: 0.000000
      Test completed on Fri Apr 28 10:38:08 2017
      Measurement: Round trip time
        Samples: 15, Minimum: 1654 usec, Maximum: 5020 usec, Average: 2630 usec, Peak to peak: 3366 usec, Stddev: 1105 usec, Sum: 39452 usec
      Measurement: Positive round trip jitter
        Samples: 6, Minimum: 20 usec, Maximum: 3079 usec, Average: 1504 usec, Peak to peak: 3059 usec, Stddev: 918 usec, Sum: 9021 usec
      Measurement: Negative round trip jitter
        Samples: 9, Minimum: 23 usec, Maximum: 3143 usec, Average: 1186 usec, Peak to peak: 3120 usec, Stddev: 1235 usec, Sum: 10671 usec
    Results over all tests:
      Probes sent: 82380, Probes received: 7769, Loss percentage: 90.569313
      Measurement: Round trip time
        Samples: 7769, Minimum: 1483 usec, Maximum: 10135 usec, Average: 2589 usec, Peak to peak: 8652 usec, Stddev: 1147 usec, Sum: 20110188 usec
      Measurement: Ingress delay
        Samples: 3, Minimum: 3000 usec, Maximum: 3000 usec, Average: 3000 usec, Peak to peak: 0 usec, Stddev: 0 usec, Sum: 9000 usec
      Measurement: Egress delay
        Samples: 8, Minimum: 1000 usec, Maximum: 4000 usec, Average: 1750 usec, Peak to peak: 3000 usec, Stddev: 1090 usec, Sum: 14000 usec
      Measurement: Positive round trip jitter
        Samples: 3936, Minimum: 0 usec, Maximum: 8426 usec, Average: 1048 usec, Peak to peak: 8426 usec, Stddev: 1091 usec, Sum: 4125122 usec
      Measurement: Negative round trip jitter
        Samples: 3832, Minimum: 1 usec, Maximum: 8409 usec, Average: 1076 usec, Peak to peak: 8408 usec, Stddev: 1123 usec, Sum: 4124713 usec

На этом про RPM все. Двигаемся дальше. А для раскрытия темы отправлю к подробнейшее руководству от Juniper


Настраиваем Zabbix для мониторинга RPM тестов


К сожалению MIB-ы для RPM объектов в JunOS построены не самым удобным образом.
Встроенной функциональности SNMP LLD Discovery в Zabbix недостаточно для автообнаружения RPM тестов


Для автообнаружения Zabbix использует метод snmpwalk. Где в качестве возвращаемых параметров используются SNMP индексы и их значения


Например при поиске по объекту ifDescr


$ snmpwalk -v 2c -c public 192.168.1.1 IF-MIB::ifDescr
IF-MIB::ifDescr.4 = STRING: WAN
IF-MIB::ifDescr.7 = STRING: LAN1
IF-MIB::ifDescr.11 = STRING: LAN2

метод discovery в Zabbix обнаружит индексы 4,7,11 и их значения WAN, LAN1 и LAN2


А вот для обнаружения тестов RPM, Juniper не предоставил такого удобного объекта.
Наиболее подходящий объект, что мне удалось обнаружить — это объект jnxRpmResSampleValue


И вот как выгядит таблица возвращаемая этим объектом:


iddqd@ex2200-rpm> show snmp mib walk jnxRpmResSampleValue  
  jnxRpmResSampleValue.3.71.101.101.6.74.105.116.116.101.114.1 = 1989
  jnxRpmResSampleValue.3.71.101.101.6.74.105.116.116.101.114.2 = -424
  jnxRpmResSampleValue.3.71.101.101.6.74.105.116.116.101.114.3 = 810
  jnxRpmResSampleValue.4.66.65.82.83.6.74.105.116.116.101.114.1 = 3352
  jnxRpmResSampleValue.4.66.65.82.83.6.74.105.116.116.101.114.2 = 1612
  jnxRpmResSampleValue.4.66.65.82.83.6.74.105.116.116.101.114.3 = 971

Разберем, что значат эта мешанина из цифр и точек.
jnxRpmResSampleValue — это MIB объект, по которому мы гуляем
Куча цифр .3.66.101.101.6.74.105.116.116.101.114 — это название нашего теста


доказательство

В этом легко убедиться запустив предыдущую команду с параметром ascii


iddqd@ex2200-rpm> show snmp mib walk jnxRpmResSampleValue ascii
  jnxRpmResSampleValue."Gee"."Jitter".1 = 1989
  jnxRpmResSampleValue."Gee"."Jitter".2 = -424
  jnxRpmResSampleValue."Gee"."Jitter".3 = 810
  jnxRpmResSampleValue."BARS"."Jitter".1 = 3352
  jnxRpmResSampleValue."BARS"."Jitter".2 = 1612
  jnxRpmResSampleValue."BARS"."Jitter".3 = 971

Ну а в качестве SNMP index (последнее после точки число) выступает порядковый номер параметров теста:
.1 — RTT
.2 — Round trip jitter
.3 — Round trip interarrival jitter


В чем так же легко убедиться посмотрев на результаты RPM теста и сопоставив с числами, которые вернул snmpwalk
iddqd@ex2200-rpm> show services rpm probe-results | match RTT
      Rtt: 1989 usec, Round trip jitter: -424 usec, Round trip interarrival jitter: 810 usec
      Rtt: 3352 usec, Round trip jitter: 1612 usec, Round trip interarrival jitter: 971 usec

Кстати, чтобы узнать OID (т.е. цифровое значение) MIB объектов в JunOS таких как jnxRpmResSampleValue, jnxRpmResultsSampleTable, jnxRpmHistorySummaryTable да
и любых других, можно запустить команду:


show snmp mib walk jnxRpmResSampleValue | display json

Скрипт автообнаружения


Итак, без внешней помощи Zabbix с обнаружением RPM тестов не справится.
Значит предоставим такую помощь в виде внешнего скрипта.
Скрипт написан на Python 2.7 и весьма компактен.


скрипт *zbx_junper_rpm_discovery.py*
#!/usr/bin/python
import sys
from pysnmp.hlapi import *
import json

def findsubstrings(s):
    la = s.split('.')
    lb = la[1:]

    if '6' in lb: # looking for a delimiter. 6 for EX or 10 for SRX
        i = lb.index('6')
    elif '10' in lb:
        i = lb.index('10')
    else:
        sys.stderr.write("delimiter nor 6 ot 10")
        exit(0)

    l1 = lb[:i]
    l2 = lb[i+1:]
    param2 = ''.join([chr(int(i)) for i in l1])
    param3 = ''.join([chr(int(i)) for i in l2])
    return param2, param3

eRR = '{ data: ["Error parsing arguments"]}\n'

if len(sys.argv)!=3:
    sys.stderr.write(eRR)
    exit()

hostname = sys.argv[1]
community=sys.argv[2]
jnxRpmResSumSent = "1.3.6.1.4.1.2636.3.50.1.2.1.2"
l = []

# init snmpwalk over jnxRpmResSumSent MIB Object
varBind = nextCmd(SnmpEngine(), CommunityData(community), UdpTransportTarget((hostname, 161)),
    ContextData(), ObjectType(ObjectIdentity(jnxRpmResSumSent)),
    lexicographicMode=False)

# do snmmpwalk and collect an rpm specific substring
for res in varBind:
    s = str(res[3][0][0])[len(jnxRpmResSumSent)+1:-2]
    l.append(s)

# lets make values inside the list l uniq
u = set(l)

jsonData=[]
for param1 in u:
    d={}
    param2, param3 = findsubstrings(param1)
    d["{#RPMUUID}"] = param1
    d["{#RPMOWNER}"] = param2
    d["{#RPMTEST}"] = param3
    jsonData.append(d)

print (json.dumps({"data": jsonData}, indent=4))

использует всего одну внешнюю библиотеку — pysnmp
Библиотека популярная и в большинстве дистрибутивов присутствует


в Ubuntu ее можно поставить командой: apt install python-pysnmp4
или в любом дистрибутиве через PIP менеджер командой: pip install pysnmp


На вход скрипта подаются 2 параметра hostname и community
И возвращается JSON в таком виде


{
    "data": [
        {
            "{#RPMTEST}": "Jitter", 
            "{#RPMUUID}": "4.66.65.82.83.6.74.105.116.116.101.114", 
            "{#RPMOWNER}": "BARS"
        }, 
        {
            "{#RPMTEST}": "Jitter", 
            "{#RPMUUID}": "3.71.101.101.6.74.105.116.116.101.114", 
            "{#RPMOWNER}": "Gee"
        }
    ]
}

Пользовательские макросы {#RPMUUID}, {#RPMOWNER} и {#RPMTEST} далее используются в названиях элементов, их ключах, триггерах и даже графиках


Скрипту нужно сделать chmod +x и разместить в директорию для внешних скриптов Zabbix
В моем случае это директория: /etc/zabbix/etc/externalscripts


Шаблон


Далее я не буду рассказывать как настраивать Zabbix. А просто поделюсь работающим шабоном (ссылка внизу). Шаблон включает в себя 3 элемента: RTT, Jitter и PacketLoss, для каждого RPM теста, которые он обнаруживает с помощью скрипта
Если тип RPM теста не предполагает измерения Jitter, то этот параметр просто автоматически исключается из мониторинга


Для более продвинутых тестов шаблон можно будет доработать по желанию. При этом скрипт не потребует изменений


Все 3 элемента отмассштабированы и выведены на один график, который так же создается автоматически.


Итог


После натягивания шаблона на устройство Juniper с запущенными RPM тестами через некоторое время увидим такую картину в элементах данных (items)


А примерно так будет выглядеть график:


На этом все. скрипт и шаблон выложен на gitHub. Можно при желании дорабатывать, форкать итд без ограничений




К сожалению, не доступен сервер mySQL