Настройка мониторинга состояния ИБП SNR серии Element в Windows
20 Apr 2017Решаем задачу по мониторингу ИБП SNR серии Element, 1000 VA, 24VDC. В комплекте с ним шла утилита хх-летней давности UPSilon 2000, которая кроме как через email (и пейджер ;)) оповещать о событиях не умеет.
Network UPS Tools
Установка
Скачиваем 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)
```