Решаем задачу по мониторингу ИБП SNR серии Element, 1000 VA, 24VDC. В комплекте с ним шла утилита хх-летней давности UPSilon 2000, которая кроме как через email (и пейджер ;)) оповещать о событиях не умеет.

SNR серии Element, 1000 VA, 24VDC

Network UPS Tools

http://networkupstools.org



Установка

Скачиваем msi пакет для Windows Windows (complete port, Beta) и устанвливаем. Входе установки у меня возникла ошибка установки NUT UPS драйвера . Пришлось скачивать этот: http://sourceforge.net/projects/libusb-win32/. В составе этого драйвера есть утилита inf-wizard.exe с помощью которой можно легко определить какое из usb устройств наш ИБП и установить драйвер в систему, особенно актуально для установки в режиме Windows Server Core.

Дальше нужно найти недастующие библиотеки (которые отсутствуют в инсталяторе), а именно:

  • libeay32.dll
  • ssleay32.dll
  • msvcr71.dll
  • libgcc_s_dw2-1.dll

Их можно скачать у меня в составе архива или найти самостоятельно.

Настройка

Минимальная настройка конфигурации в моем случае.

Файл nut.conf:

MODE=netserver

Файл ups.conf:

[snr1000]
driver=blazer_usb
port=auto
langid_fix=0x409
#Эти параметры критичны для данной модели ИБП

desc="SNR-UPS-ONRM-1000-S24"

default.battery.voltage.high=26
default.battery.voltage.low=23
#Без этих параметров будет неверно вычислятся заряд батареи

#runtimecal = 900,86,1960,42

runtimecal - Для подсчета этого параметра нужно тестировать сам ИБП. Нужно разредить полностью с определенным процентом нагрузки и замерить время. Например в приведенном верху примере при 86% нагрузке ИБП разряжается за 900 секунд, а при 42% нагрузке за 1960 секунд.

Файл upsd.conf:

LISTEN 127.0.0.1 3493
LISTEN 192.168.133.5 3493

Файл upsd.users:

[admin]
password=password1
actions=SET
instcmds=ALL
upsmon master

[upsmon_local]
password=password2
upsmon master

[upsmon_remote]
password=password3
upsmon slave

Файл upsmon.conf:

MONITOR snr1000@localhost 1 upsmon_local password2 master

Проверить правильность настроек (после запуска службы) можно так:

upsc.exe snr1000

Вывод:

battery.charge: 100
battery.voltage: 27.36
battery.voltage.high: 28
battery.voltage.low: 23
battery.voltage.nominal: 27.0
device.mfr:
device.model:
device.type: ups
driver.name: blazer_usb
driver.parameter.langid_fix: 0x409
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.version: Windows-v2.6.5-5-7-g72f380c
driver.version.internal: 0.10
input.current.nominal: 5.0
input.frequency: 50.1
input.frequency.nominal: 50
input.voltage: 212.5
input.voltage.fault: 206.0
input.voltage.nominal: 220
output.voltage: 220.5
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware:        V04
ups.load: 25
ups.mfr:
ups.model:
ups.productid: 0000
ups.status: OL
ups.temperature: 25.0
ups.type: online
ups.vendorid: 0001

Запустить NUT для отладки как консольную программу можно так:

nut.exe -N

Обязательно нужно проверить настройки брандмаэура, открыть TCP порт 3493.

На Windows Server Core, NUT на отрез отказывался корректно запускаться как служба. Пришлось в планировщике задач прописать следующий powershell скрипт выполняющийся при старте системы:

#Start-NUT.ps1

Write-Host "Starting drivers"
Start-Process cmd.exe "/C C:\NUT\bin\blazer_usb.exe -a snr1000"

Write-Host "Starting upsd"
Start-Process C:\NUT\bin\upsd.exe

Write-Host "Starting upsmon"
Start-Process C:\NUT\bin\upsmon.exe

Write-Host "NUT started"
Мониторинг

Мониторить будем с помощью icinga2 ...

Вариант опроса ИБП из Linux

Подключаем плагин check_nut_plus как CheckCommand:

object CheckCommand "check_nut_plus" {
    import "plugin-check-command"

    #command = [ "sudo", PluginDir + "/check_nut_plus", "-d $name_ups$", "-v $ups_value$" ]

    command = [ "sudo" ]
    arguments = {
        "-command" = {
            skip_key = true
            value = PluginDir + "/check_nut_plus"
            order = 0
        }
        "-d" = {
            value = "$name_ups$"
            order = 1
        }
        "-v" = {
            value = "$ups_value$"
            order = 2
        }
    }

}

Применяем сервисы к хосту с переменной vars.nut_endpoint.

Сервисы для Linux:
```python

apply Service "ups-load" {
  command_endpoint = host.vars.nut_endpoint
  check_command = "check_nut_plus"

  vars.name_ups = host.vars.name_ups
  vars.ups_value = "ups.load=w>60:c>=70"

  assign where host.vars.nut_endpoint
}

apply Service "battery-charge" {
  command_endpoint = host.vars.nut_endpoint
  check_command = "check_nut_plus"

  vars.name_ups = host.vars.name_ups
  vars.ups_value = "battery.charge=w<30:c<=5"

  assign where host.vars.nut_endpoint
}

apply Service "battery-voltage" {
  command_endpoint = host.vars.nut_endpoint
  check_command = "check_nut_plus"

  vars.name_ups = host.vars.name_ups
  vars.ups_value = "battery.voltage=w<26:c<=23"

  assign where host.vars.nut_endpoint
}

apply Service "input-voltage" {
  command_endpoint = host.vars.nut_endpoint
  check_command = "check_nut_plus"

  vars.name_ups = host.vars.name_ups
  vars.ups_value = "input.voltage=w<201:c<=190"

  assign where host.vars.nut_endpoint
}

apply Service "ups-temperature" {
  command_endpoint = host.vars.nut_endpoint
  check_command = "check_nut_plus"

  vars.name_ups = host.vars.name_ups
  vars.ups_value = "ups.temperature=w>45:c>=55"

  assign where host.vars.nut_endpoint
}

apply Service "ups-status" {
  command_endpoint = host.vars.nut_endpoint
  check_command = "check_nut_plus"

  vars.name_ups = host.vars.name_ups
  vars.ups_value = "ups.status=c!=OL"
  enable_perfdata = false

  assign where host.vars.nut_endpoint
}

```

Описываем безагентный хост (здесь vars.nut_endpoint и command_endpoint хост на котором будет выполнятся check_nut_plus, на этом хосте должен быть установлен nut-client):

object Host "ups-snr1000.hv1.mkucou.local" {
    import "img-ups"

    max_check_attempts = 2
    check_interval = 1m
    retry_interval = 10s

    check_command = "dummy"
    vars.dummy_state = 0

    vars.domain_name = "MKUCOU"

    vars.non_pc = true
    vars.nut_endpoint = "hv1.mkucou.local"
    vars.nut_ups_name = "ups-snr1000.hv1.mkucou.local@localhost"
    vars.nut_win = true
    vars.nut_bvoltage = 12

    vars.ups_address = "192.168.223.220"
    vars.ups_name = "ups-snr1000.hv1.mkucou.local"
    enable_perfdata = false
    vars.grafana_graph_disable = true

}
Вариант опроса ИБП из Windows
Сервисы для Windows:
```python
apply Dependency "ups-state-from-battery-charge" to Host {
  parent_service_name = "battery-charge"

  host.vars.dummy_state = {
      {
        if (get_service(host.name, "ups-details").state > 0) {
        return 3
        } else {
        return 0
        }
    }
  }

    assign where host.vars.nut_endpoint && host.vars.nut_win
}



apply Service "ups-load" {
  max_check_attempts = 2
  check_interval = 1m
  enable_perfdata = true

  assign where host.vars.nut_endpoint && host.vars.nut_win

  check_command = "powershell"
  vars.ps_command = "c:\\ProgramData\\icinga2\\Scripts\\icinga2\\check_nut.ps1"
  vars.ps_args = [ host.vars.nut_ups_name, "ups.load:60:70" ]

  command_endpoint = host.vars.nut_endpoint

}

apply Service "battery-charge" {
  max_check_attempts = 2
  check_interval = 1m
  enable_perfdata = true

  assign where host.vars.nut_endpoint && host.vars.nut_win

  check_command = "powershell"
  vars.ps_command = "c:\\ProgramData\\icinga2\\Scripts\\icinga2\\check_nut.ps1"
  vars.ps_args = [ host.vars.nut_ups_name, "battery.charge:30:10" ]

  command_endpoint = host.vars.nut_endpoint

}

apply Service "battery-voltage" {
  max_check_attempts = 2
  check_interval = 1m
  enable_perfdata = true

  assign where host.vars.nut_endpoint && host.vars.nut_win
  ignore where host.vars.nut_bvoltage == 12

  check_command = "powershell"
  vars.ps_command = "c:\\ProgramData\\icinga2\\Scripts\\icinga2\\check_nut.ps1"
  vars.ps_args = [ host.vars.nut_ups_name, "battery.voltage:26:23" ]

  command_endpoint = host.vars.nut_endpoint

}

apply Service "battery-voltage" {
  max_check_attempts = 2
  check_interval = 1m
  enable_perfdata = true

  assign where host.vars.nut_endpoint && host.vars.nut_win && host.vars.nut_bvoltage == 12

  check_command = "powershell"
  vars.ps_command = "c:\\ProgramData\\icinga2\\Scripts\\icinga2\\check_nut.ps1"
  vars.ps_args = [ host.vars.nut_ups_name, "battery.voltage:12:11" ]

  command_endpoint = host.vars.nut_endpoint

}

apply Service "input-voltage" {
  max_check_attempts = 2
  check_interval = 1m
  enable_perfdata = true

  assign where host.vars.nut_endpoint && host.vars.nut_win

  check_command = "powershell"
  vars.ps_command = "c:\\ProgramData\\icinga2\\Scripts\\icinga2\\check_nut.ps1"
  vars.ps_args = [ host.vars.nut_ups_name, "input.voltage:201:190" ]

  command_endpoint = host.vars.nut_endpoint

}

apply Service "ups-temperature" {
  max_check_attempts = 2
  check_interval = 1m
  enable_perfdata = true

  assign where host.vars.nut_endpoint && host.vars.nut_win

  check_command = "powershell"
  vars.ps_command = "c:\\ProgramData\\icinga2\\Scripts\\icinga2\\check_nut.ps1"
  vars.ps_args = [ host.vars.nut_ups_name, "ups.temperature:45:55" ]

  command_endpoint = host.vars.nut_endpoint

}

apply Service "ups-details" {
  max_check_attempts = 2
  check_interval = 5m
  enable_perfdata = true

  assign where host.vars.nut_endpoint && host.vars.nut_win

  check_command = "powershell"
  vars.ps_command = "c:\\ProgramData\\icinga2\\Scripts\\icinga2\\check_nut.ps1"
  vars.ps_args = host.vars.nut_ups_name

  command_endpoint = host.vars.nut_endpoint

}


```
Скрипт проверки состояния:
```powershell
<#
 .SYNOPSIS
  Скрипт для Icinga 2 - Информация о ИБП через ПО Network UPS Tools

 .DESCRIPTION


 .PARAMETER ComputerName
  Имя компьютера

 .OUTPUTS


 .EXAMPLE


 .LINK
  https://webnote.satin-pl.com

 .NOTES
  Version:        0.1
  Author:         Pavel Satin
  Email:          plsatin@yandex.ru
  Creation Date:  17.02.2018
  Purpose/Change: Initial script development

#>
Param(
    [Parameter(Mandatory = $false)]
        [string]$NUTArgs =  "snr1000@localhost",
    [Parameter(Mandatory = $false)]
        [string]$NUTArgsService = "details"
    )


#$ErrorActionPreference = "SilentlyContinue"

$returnStateOK = 0
$returnStateWarning = 1
$returnStateCritical = 2
$returnStateUnknown = 3

$returnState = $returnStateUnknown

$strRNDFile = Get-Random
$upscExe = "c:\NUT\bin\upsc.exe"
$NUTOuputFile = "c:\\ProgramData\\icinga2\\scripts\\icinga2\\tmp\\nut-out-$strRNDFile.txt"



$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = $upscExe
$psi.Arguments = $NUTArgs
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
$process.Start() | Out-Null
$process.WaitForExit()
$NUTOutputExe = $process.StandardOutput.ReadToEnd()

$NUTOutputExe | Out-File $NUTOuputFile


if ($NUTArgsService -eq "details") {
    Write-Host "OK - UPS Status:"
    $output = ""
    $output += "<div class='plsatin-ps-style'><table>"

    foreach ($str in Get-Content $NUTOuputFile) {
        if ($str) {
            $nutstrarr = $str -split ": "

            $output += "<tr><td>" + $nutstrarr[0] + "</td><td>" + $nutstrarr[1] + "</td></tr>"
            $intNum = $nutstrarr[1]

            #Отдаем perfdata
            if ($nutstrarr[0] -eq "input.voltage") {
                $perfdataLINEV = "'input.voltage'=$intNum;200;180;140;300"
            } elseif ($nutstrarr[0] -eq "battery.voltage") {
                $perfdataBATTV = "'battery.voltage'=$intNum;;;;"
            } elseif ($nutstrarr[0] -eq "battery.charge") {
                $perfdataBCHARGE = "'battery.charge'=$intNum;30;15;0;100"
            } elseif ($nutstrarr[0] -eq "ups.load") {
                $perfdataLOADPCT = "'ups.load'=$intNum;60;90;0;100"
            } elseif ($nutstrarr[0] -eq "ups.temperature") {
                $perfdataTemperature = "'ups.temperature'=$intNum;55;65;15;70"
            }

        }

    } #Конец цикла

    $returnState = $returnStateOK

    $output += "</table></div>"
    Write-Host "$output | $perfdataLINEV $perfdataBATTV $perfdataBCHARGE $perfdataLOADPCT $perfdataTemperature"

} else {
    $nutsrvarr = $NUTArgsService -split ":"
    [string]$labelValue = $nutsrvarr[0]
    [int]$warnValue = $nutsrvarr[1]
    [int]$critValue = $nutsrvarr[2]

    foreach ($str in Get-Content $NUTOuputFile) {
        $nutstrarr = $str -split ": "

        #Write-Host $nutstrarr[0]

        if ($nutstrarr[0] -eq $nutsrvarr[0]) {
            [int]$NUTServiceResult = $nutstrarr[1]
        }
    }


    if ($warnValue -gt $critValue) { #100 30 5
        if ($NUTServiceResult -ge $warnValue) {
            $returnState = $returnStateOK
            Write-Host "OK: $labelValue=$NUTServiceResult"
        } elseif ($NUTServiceResult -le $critValue) {
            $returnState = $returnStateCritical
            Write-Host "Critical: $labelValue=$NUTServiceResult"
        } else {
            $returnState = $returnStateWarning
            Write-Host "Warning: $labelValue=$NUTServiceResult"
        }

    } else { #0 80 90
        if ($NUTServiceResult -le $warnValue) {
            $returnState = $returnStateOK
            Write-Host "OK: $labelValue=$NUTServiceResult"
        } elseif ($NUTServiceResult -ge $critValue) {
            $returnState = $returnStateCritical
            Write-Host "Critical: $labelValue=$NUTServiceResult"
        } else {
            $returnState = $returnStateWarning
            Write-Host "Warning: $labelValue=$NUTServiceResult"
        }

    }


    Write-Host " |'$labelValue'=$NUTServiceResult;$warnValue;$critValue;;"

}

Remove-Item $NUTOuputFile -Force

[System.Environment]::Exit($returnState)


```
Скриншоты