SNMP


Примечание

Для корректного отображения устройств на дашбоарде в Grafana следует использовать значение тега component как IP-адрес или имя устройства, которое мониторится с помощью snmp-exporter

SNMP поллинг

Для SNMP мониторинга удаленных устройств применяется snmp-exporter.

Для генерации конфигурационного файла используется специальная утилита generator. В архив с snmp-exporter добавлен каталог стандартных MIB-файлов для генерации конфигураций.

Эта утилита обрабатывает необходимые MIB-файлы и преобразует их в список OID-цепочек и названий метрик.

SNMP exporter опрашивает удаленные устройства на основе этих данных и выводит метрики в формате Prometheus для дальнейшего анализа другими системами.


Запуск snmp-exporter с помощью агента мониторинга

Для установки экспортера как сервиса см. руководство.

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

Настройка раздела exporters

В конфигурационном файле агента в разделе exporters укажите имя запускаемого экспортера и параметр is_custom:

exporters:
  - name: snmp_exporter
    is_custom: true
    args: "--config.file=/opt/astramon-agent/exporters/config/snmp.yml"
    health_address: 127.0.0.1:9116/metrics
  • Поле name должно совпадать с названием бинарного файла с учетом дополнительных условий именования сторонних экспортеров (например: astramon-snmp_exporter-custom ).

  • Параметр is_custom указывает агенту, что это сторонний экспортер, но агент может управлять им (запускать, выполнять health check, останавливать и сообщать статус работы экспортера в Config API). Также это предотвращает использование функциональности, доступной только для экспортеров, специально разработанных для агента мониторинга.

  • Параметр args содержит параметры запуска экспортера, включая путь к файлу конфигурации.

Настройка раздела metrics

Выполните настройку в разделе metrics:

custom_targets:
  - name: snmp_exporter1
    component: 10.177.248.228
    target: 127.0.0.1:9116
    metrics_path: /snmp?module=apcups&target=10.177.248.228
  - name: snmp_exporter2
    component: 10.177.248.234
    target: 127.0.0.1:9116
    metrics_path: /snmp?module=linux&target=10.177.248.234
  • Поле name должно быть уникальным (это особенность работы vmagent). В примере показан сбор данных с двух целевых устройств.

  • Параметр component добавляет лейбл component для различения метрик разных устройств.

  • Параметр target указывает адрес и порт, с которого будут считываться метрики.

  • Параметр metrics_path позволяет обратиться к конкретному эндпоинту для получения метрик. По умолчанию используется /metrics, но в данном случае эндпоинт выводит метрики для разных устройств. При необходимости можно добавить запись для сбора метрик напрямую из /metrics.

В текущей реализации поддерживаются версии SNMP v1 и v2c.

Файл правил состоит из пяти основных частей:

  1. Header - Документация с определением переменных

  2. Lookup - Таблицы приведения числовых обозначений в человекочитаемый формат

  3. Preparation - Подготовка служебной информации и предварительная обработка трапов

  4. Body - Ветвление правил по SNMP трапам

  5. Footer - Подготовка результата для дальнейшей обработки

if (typeof $OID1 == "undefined") $OID1 = "";
if (typeof $OID2 == "undefined") $OID2 = "";
if (typeof $OID3 == "undefined") $OID3 = "";
if (typeof $OID4 == "undefined") $OID4 = "";
if (typeof $OID5 == "undefined") $OID5 = "";
if (typeof $OID6 == "undefined") $OID6 = "";
if (typeof $OID7 == "undefined") $OID7 = "";
if (typeof $OID8 == "undefined") $OID8 = "";
if (typeof $OID9 == "undefined") $OID9 = "";
if (typeof $OID10 == "undefined") $OID10 = "";
if (typeof $OID11 == "undefined") $OID11 = "";
if (typeof $OID12 == "undefined") $OID12 = "";
 
if (typeof $1 == "undefined") $1 = "";
if (typeof $2 == "undefined") $2 = "";
if (typeof $3 == "undefined") $3 = "";
if (typeof $4 == "undefined") $4 = "";
if (typeof $5 == "undefined") $5 = "";
if (typeof $6 == "undefined") $6 = "";
if (typeof $7 == "undefined") $7 = "";
if (typeof $8 == "undefined") $8 = "";
if (typeof $9 == "undefined") $9 = "";
if (typeof $10 == "undefined") $10 = "";
if (typeof $11 == "undefined") $11 = "";
if (typeof $12 == "undefined") $12 = "";
 
_Manager = "";
_Agent = "";
_Class = "";
_Node = "";
_NodeAlias = "";
_AlertKey = "";
_AlertGroup = "";
_Summary = "";
_Severity = "";
_Type = "";
_Identifier = "";
_ExpireTime = 0;
_FirstOccurrence = new Date($ReceivedTime * 1000);
_LastOccurrence = _FirstOccurrence;
_Alert = false;

Lookup - таблицы приведения

IIANAifType = {
    "1": "Other", // other - none of the following
    "2": "Regular 1822", // regular1822
    "3": "HDH 1822", // hdh1822
    "4": "DDN X.25", // ddnX25
    "5": "RFC-877 X.25", // rfc877x25
    "6": "Ethernet CSMA-CD", // ethernetCsmacd
    "7": "ISO 8802.3 CSMA-CD", // iso88023Csmacd
    "8": "ISO 8802.4 Token Bus", // iso88024TokenBus
    ...
    "212": "Voice FGD Exchange Access North American", // voiceFGDEANA - voice FGD Exchange Access North American
    "213": "Voice Direct Inward Dialing" // voiceDID - voice Direct Inward Dialing
}
 
ifAdminStatus = {
    "1": "Up", // up - ready to pass packets
    "2": "Down", // down
    "3": "Testing" // testing - in some test mode
}
 
ifOperStatus = {
    "1": "Up", // up - ready to pass packets
    "2": "Down", // down
    "3": "Testing", // testing - in some test mode
    "4": "Unknown", // unknown - status can not be determined for some reason.
    "5": "Dormant", // dormant
    "6": "Not Present", // notPresent - some component is missing
    "7": "Lower Layer Down" // lowerLayerDown - down due to state of lower-layer interface(s)
}

Preparation - подготовка данных

// Устанавливаем стандартный Agent, Manager и Class
_Manager = "SNMP Trap adapter on " + hostname()
_Agent = "SNMPagent"
_Class = "300"
 
// Проверяем если получили SNMPv2 трап и ковертируем его в SNMPv1 стиль
if (typeof $notify !== "undefined") // Если $notify существует то это SNMPv2 трап
{
    _Node = $PeerAddress
    _NodeAlias = $PeerIPaddress
 
    if (regmatch($notify, "\.iso\.")) {
        $notify = ".1." + extract($notify, "\.iso\.(.*)")
    }
 
    if (nmatch($notify, ".1.3.6.1.6.3.1.1.5")) // SNMPv2 Generic трап
    {
        $Enterprise = extract($notify, "(.*)\.[0-9]+$")
        $specific_trap = "0"
        $generic_trap = (int(extract($notify, ".*\.([0-9]+)$")) - 1).toString()
    } else // Enterprise Specific трап
    {
        if (match(extract($notify, "\.([0-9]+)\.[0-9]+$"), "0")) {
            $Enterprise = extract($notify, "(.*)\.[0-9]+\.[0-9]+$")
        } else {
            $Enterprise = extract($notify, "(.*)\.[0-9]+$")
        }
        $specific_trap = extract($notify, ".*\.([0-9]+)$")
        $generic_trap = "6"
    }
} else // Это SNMPv1 трап
{
    _Node = $Node
    if (typeof $IPAddress !== "undefined")
    {
        _NodeAlias = $IPAddress
    } else {
        _NodeAlias = $IPaddress
    }
}

Body - определение трапов

Пример конфигурации для Cisco Generic трапов:

if (match($generic_trap, "6")) // Проверяем если Enterprise Specific трап
{
    switch ($Enterprise) {
        case "dummy case statement": // Это позволит ибежать синтаксических ошибок при отсутствующих кейсай
            break
        // В этом сегменте определяем Enterprise Specific трапы не относящиеся к Generic, как в следующем примере
        case ".1.3.6.1.4.1.9.9.43.2":    // Если $Enterpries соответствует Cisco и трапу ciscoConfigManMIBNotificationPrefix
            switch ($specific_trap) {
                case "1": // - ciscoConfigManEvent
                    // ...
                    break
                case "2": // - ccmCLIRunningConfigChanged
                    // ...
                    break
                case "3": // Если $specific_trap соответсвует ccmCTIDRolledOver
                    _AlertGroup = "cisco"
                    _Agent = "cisco"
                    _Summary = "ccmCTIDRolledOver: This notification indicates that the Config Change Tracking ID has rolled over and will be reset."
                    _Severity = 3
                    _Type = 1
                    _ExpireTime = 10
                    _Identifier = _Node + _Summary
                    break
                default:
                    _Summary = "Unknown specific trap number (" + $specific_trap + ") received for enterprise " + $Enterprise
                    _Identifier = _Node + $Enterprise + $generic_trap + $specific_trap + _Agent + _Manager
                    _Severity = 3
                    _Type = 1
            }
            break
        default:
            $EventID = $Enterprise + "|" + $generic_trap + "|" + $specific_trap
            switch ($EventID) {
                case "dummy case statement": // Это позволит ибежать синтаксических ошибок при отсутствующих кейсай
                    break
                default:
                    _Summary = "Enterprise ID Not Found (see details): " + $Enterprise + " " + $generic_trap + " " + $specific_trap
                    _Severity = 2
                    _Type = 1
            }
            _Identifier = _Node + " " + $Enterprise + " " + $generic_trap + " " + $specific_trap + " " + _AlertGroup + " " + _AlertKey + " " + _Agent + " " + _Manager
    }
} else // Проверяем если Generic трап
{
    // Стантартно для Generic
    _Agent = "Generic"
    switch ($generic_trap) {
        // В этом сегменте определяем только SNMP Generic трапы
        case "0": // coldStart
            _AlertGroup = "Generic"
            _AlertKey = ""
            _Summary = "Cold Start"
            _Severity = 2
            _Type = 1
            _Identifier = _Node + " " + _AlertGroup + " " + _Agent + " " + _Manager + " " + $generic_trap
            break
        case "1": // warmStart
            // ...
            break
        case "2": // linkDown
            // ...
            break
        // ...
        default:
            _Summary = "Invalid Generic Trap Number: " + $Enterprise + " " + $generic_trap + " " + $specific_trap
            _Severity = 2
            _Type = 0
            _Identifier = _Node + " " + $Enterprise + " " + $generic_trap + " " + $specific_trap + " " + _Agent + " " + _Manager
    }
    switch ($Enterprise) {
      // В этом сегменте определяем SNMP Generic трапы которые относятся к другим MIB или к Enterprise (Generic трапы имеющие дополнительную Enterprise информацию)
        case ".1.3.6.1.6.3.1.1.5": // RFC1907 - SNMPv2-MIB
            if (nmatch($OID1, ".1.3.6.1.4.1.9") || nmatch($OID2, ".1.3.6.1.4.1.9") || nmatch($OID4, ".1.3.6.1.4.1.9")) { // Если трап содержит один из данных OID, значит это Enterprise Generic трап принадлежащий Cisco
                _Agent = "Generic-Cisco SNMPv2"
                _Class = "40057"
                switch ($generic_trap) {
                    case "0": // При попадании в этот кейс, выполняем следующий что бы не дублировать код
                    case "1": // Для трапов coldStart и warmStart одинаковая ветка, так что можно их обрабатывать одинаково
                        $sysUptime = $1
                        $whyReload = $2
                        details($sysUptime, $whyReload)
 
                        _Summary = _Summary + ": " + $2
                        _Identifier = _Identifier + " " + $2
                        break
                    case "2":
                    case "3": // Так же как и для предыдущих, linkDown и linkUp обрабатываем одинаково
                        // ...
                        break
                    // ...
                    default:
                }
            } if (nmatch($OID6, ".1.3.6.1.4.1.9")) { // Если Generic трап содержит данный OID, значит это Generic-Cisco трап
                _Agent = "Generic-Cisco SNMPv2"
                _Class = "40057"
                switch ($generic_trap) {
                    case "2":
                    case "3": // linkDown, linkUp
                        $ifIndex = $1
                        $ifAdminStatus = ifAdminStatus[$2] + " ( " + $2 + " )"
                        $ifOperStatus = ifOperStatus[$3] + " ( " + $3 + " )"
                        $ifDescr = $4
                        $ifType = IANAifType[$5] + " ( " + $5 + " )" // Берем описание из Lookup таблицы
                        $locIfReason = $6
                        details($ifIndex, $ifAdminStatus, $ifOperStatus, $ifDescr, $ifType, $locIfReason)
 
                        switch ($2) {
                            case "2": // Down
                                _Summary = _Summary + ", Administratively: " + $6 + "  ( " + $4 + " )"
                                _Severity = 2
                                break
                            case "3": // Testing - in some test mode
                                _Summary = _Summary + ", Testing: " + $6 + "  ( " + $4 + " )"
                                _Severity = 2
                                break
                            default:
                                _Summary = _Summary + ": " + $6 + "  ( " + $4 + " )"
                        }
                        _Identifier = _Identifier + " "
                        break
                    default:
                    // ...
                }
            } else { // Если не подходит не под онид из перечисленнх вариантов, значит это Generic IETF SNMPv2 Трап
                _Agent = "Generic-IETF-SNMPv2-MIB"
 
                switch ($generic_trap) {
                    case "2":
                    case "3": // linkDown, linkUp
                        // ...
                        break
                    // ...
                    default:
                    // ...
                }
            }
            break
        // ...
        default:
            if (match($Enterprise, "")) {
                _Summary = "Dummy Enterprise! If you matched here you have problems! (see details)"
            }
            else // Обрабатываем неизвестный Enterprise как SNMPv1 Generic трап
            {
                _Agent = "Generic-Unknown"
                switch ($generic_trap) {
                    case "2":
                    case "3": // linkDown, linkUp
                        //...
                        break
                    default:
                        _Summary = _Summary + "  ( Enterprise = " + $Enterprise + " )"
                }
            }
    }
}

Полный файл правил для Cisco Generic можно найти в репозитории .

set("Manager", _Manager);
set("Agent", _Agent);
set("Class", _Class);
set("Node", _Node);
set("NodeAlias", _NodeAlias);
set("AlertKey", _AlertKey);
set("AlertGroup", _AlertGroup);
set("Summary", _Summary);
set("Severity", _Severity);
set("Type", _Type);
set("Identifier", _Identifier);
set("ExpireTime", _ExpireTime);
set("FirstOccurrence", _FirstOccurrence.getTime() / 1000);
set("LastOccurrence", _LastOccurrence.getTime() / 1000);
set("Alert", _Alert);

Алерты

Для отправки алертов необходимо установить параметр _Alert = true в соответствующих ветках файла правил:

// ...
        case "2": // linkDown
            _AlertGroup = "Generic Link Status"
            _AlertKey = "ifEntry." + $1
            _Summary = "Link Down"
            _Severity = 5
            _Type = 1
            _Identifier = _Node + " " + _AlertKey + " " + _AlertGroup + " " + _Agent + " " + _Manager
            _Alert = true // При установке данного параметра в true будет создан алерт на текущий трап
            break
// ...

Доступные параметры в файле правил

Параметр

Поддерживаемые версии

Описание

$Community

V1, V2c

Строка community SNMP

$contextEngineID

V3

Context Engine ID

$Enterprise

V1

Строка enterprise SNMP

$generic_trap

V1

Целочисленное значение Generic SNMP-трапа

$IPAddress

V1, V2c, V3

IP-адрес источника трапа

$Node

V1, V2c, V3

Имя узла источника (или IP-адрес, если имя не разрешено)

$notify

V2c, V3

Специфическое поле notify для V2c

$PeerAddress

V1, V2c, V3

Имя хоста/IP-адрес отправителя трапа

$PeerIPaddress

V1, V2c, V3

IP-адрес отправителя трапа

$Protocol

V1, V2c, V3

Протокол получения (UDP/TCP)

$ReceivedPort

V1, V2c, V3

Номер порта источника

$ReceivedTime

V1, V2c, V3

Время получения пакета

$ReqId

V1

Идентификатор SNMP-запроса

$securityEngineID

V3

Security Engine ID авторитетного SNMP-субъекта (для трапов - ID источника)

$securityLevel

V3

Уровень безопасности:
• noAuth - без аутентификации
• authNoPriv - с аутентификацией
• authPriv - с аутентификацией и шифрованием

$securityName

V3

Security Name для аутентификации

$SNMP_Version

V1, V2c, V3

Версия SNMP (1 для V1, 2 для V2c)

$specific_trap

V1

Целочисленное значение Specific SNMP-трапа

$UpTime

V1, V2c

Аптайм системы в тиках

$n_hex

-

Шестнадцатеричное представление переменных varbind

Примечание

  1. Инструкция по установке и настройке snmp_exporter.

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

  3. В файле правил используется синтаксис JavaScript.