ReadyNAS - Supervise your USB connected UPS thru SNMP

Contents[Hide]

dropcap readynas102

ReadyNAS devices are running an almost standard Debian and are providing :

  • Net-SNMP agent as a standard feature
  • USB UPS management with NUT (Network UPS Tool)

But, Out-Of-The-Box, there is no possibility to query the UPS state thru SNMP.

Hopefully, thanks to SSH access and Net-SNMP extension MIB capabilities, it is quite simple to add UPS supervision thru SNMP.

This article explains how to setup your ReadyNAS to supervise its locally connected UPS thru SNMP. It has been tested on a ReadyNAS 102, but it should work on other members of the ReadyNAS family.

1. Pre-requisite

First step is to enable SSH access on your ReadyNAS.

With latest ReadyNasOS, it is done with a simple push button on the Web administration console.

Then, SNMP service should be enabled on your ReadyNAS, as Net-SNMP deamon is not started.

Thanks to latest ReadyNASOS, it is also a simple push button activation on the Web administration console.

Finally, your UPS should be connected to your ReadyNAS and recognised by the Web administration console.

2. Query UPS from shell

Once connected to your ReadyNAS thru SSH, you can query your local UPS using simple upsc command :

Terminal
# upsc UPS@localhost
battery.charge: 100
...
device.model: Back-UPS XS 700U
...

Thanks to NUT and upsc command, you can easily query your UPS about its battery charge level or manufacturer :

Terminal
# upsc UPS@localhost battery.charge
100
# upsc UPS@localhost device.mfr
American Power Conversion

3. Principle of SNMP MIB Extension

A standard feature of Net-SNMP is to allow to extend its parameters.

Net-SNMP provides an extension MIB (NET-SNMP-EXTEND-MIB) that can be used to query values thru simple shell scripts.

Shell script should be declared with the extend directive in /etc/snmp/snmpd.conf configuration file.

Once defined, SNMP agent will provide the exit code and any output over a simple snmp-get query.

Here is a example of a MIB extension declaration for previous parameters :

/etc/snmp/snmpd.conf
...
extend battery.charge upsc UPS@localhost battery.charge
extend device.mfr upsc UPS@localhost device.mfr

4. Extend SNMP MIB with list of UPS parameters

We've seen that upsc provides a complete list of available parameters.

So we should declare one extension parameter for every upsc parameter.

Once done, you'll be able to query any UPS parameter thru SNMP.

To query parameters, a local script will be used to collect data from upsc and to quote them for further treatment.

/usr/local/bin/ups-status.sh
#!/bin/bash
# -------------------------------------------------------
# Read local UPS Status on ReadyNAS 
#
# Used in http://bernaerts.dyndns.org/nas/...
#
# Parameters :
#   $1 : UPSC key to be read
#
# 10/05/2016, V1.0 - Creation by N. Bernaerts
# -------------------------------------------------------

# read value
VALUE=$(/bin/upsc UPS@localhost $1)

# return vaue
echo "'"${VALUE}"'"

This script takes upsc parameter and answers back the expected result with double quotes "result".

This can be done under a SSH console with one simple command which will :

  1. list of all known parameters
  2. generate one extension line per parameter
  3. append these lines to snmpd.conf

Terminal
# upsc UPS@localhost | sed 's/^\(.*\): .*$/extend \1 \/usr\/local\/bin\/ups-status.sh \1/' >> /etc/snmp/snmpd.conf

Your /etc/snmp/snmpd.conf configuration file should now handle one extension declaration per UPS parameter :

/etc/snmp/snmpd.conf
...
extend battery.charge upsc UPS@localhost battery.charge
extend battery.charge.low upsc UPS@localhost battery.charge.low
extend battery.charge.warning upsc UPS@localhost battery.charge.warning
...

You now need to restart snmpd daemon for the MIB extensions to become operational.

Terminal
# service snmpd restart

5. Query parameters on a SNMP client

It's now time to query your ReadyNAS about its USB connected UPS from any SNMP client on your network.

Any Linux workstation or server terminal should be a perfect console :

Terminal
$ snmpget -v 1 -c public your.nas.ip.address NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"battery.charge.low\"
NET-SNMP-EXTEND-MIB::nsExtendOutputFull."battery.charge.low" = STRING: 10
$ snmpget -v 1 -One -c public your.nas.ip.address NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"battery.charge\"
.1.3.6.1.4.1.8072.1.3.2.3.1.2.14.98.97.116.116.101.114.121.46.99.104.97.114.103.101 = STRING: 100

You are now able to get your NAS USB connected UPS status from any computer connected on your network.

6. Munin - UPS supervision Plugin

Now that your ReadyNAS is publishing its UPS data, you can supervise it from any Munin server.

Here is an example of a Munin plugin in charge of this supervision.

As this is not the goal of this article, I won't explain how to setup a Munin server or to declare a SNMP plugin.
Very detailed explaination are available from http://munin-monitoring.org/wiki/Using_SNMP_plugins.

This plugin provides UPS main data :

  • Battery level (%)
  • Input power (%)
  • Runtime (mn)

As generic data, it also provides :

  • Manufacturer
  • Model
  • Battery type
  • Real power

/usr/share/munin/plugins/snmp__ups
#!/bin/bash
# -*- sh -*-
# -------------------------------------------------------
# Munin node script
#
# Monitor UPS state when connected to a ReadyNAS
#
# Used in http://bernaerts.dyndns.org/nas/...
#
# Script name format should be :
#   snmp_HostName_ups
#   snmp_HostName_PortNumber_ups
#
# Parameters :
#   $1 : none, "snmpconf" or "config"
#
# 14/05/2016, V1.0 - Creation by N. Bernaerts
# -------------------------------------------------------

: << =cut

=head1 NAME

snmp__ups - Munin plugin to monitor UPS state when USB connected to any SNMP extended device.

=head1 APPLICABLE SYSTEMS

Any ReadyNAS with SNMP enabled and extended to handle UPS data.
Informations are available from http://bernaerts.dyndns.org/nas/...
Tested on ReadyNAS 102.

=head1 CONFIGURATION

ReadyNAS must have SNMP enabled and extended to handle UPS data.
This plugin uses public community.

=head1 INTERPRETATION

Battery level is in % (0-100).
Input power is in % of maximum power (0-100).
Runtime is in mn.

=head1 MIB INFORMATION

This plugin uses extension MIB (NET-SNMP-EXTEND-MIB).

=head1 MAGIC MARKERS

  #%# family=snmpauto
  #%# capabilities=snmpconf

=head1 VERSION

  $Id$

=head1 BUGS

None known.

=head1 AUTHOR

Copyright (C) 2016 Nicolas Bernaerts

=head1 LICENSE

GPLv2.

=cut

# -------------------------------------------------------
# Configure all MIBs adresses
# -------------------------------------------------------

MIB_MANUFACTURER="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"ups.mfr\""
MIB_MODEL="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"ups.model\""
MIB_STATUS="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"ups.status\""
MIB_POWER_NOMINAL="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"ups.realpower.nominal\""
MIB_POWER_LOAD="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"ups.load\""
MIB_BATTERY_TYPE="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"battery.type\""
MIB_BATTERY_CHARGE="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"battery.charge\""
MIB_BATTERY_RUNTIME="NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\"battery.runtime\""

# -------------------------------------------------------
# Get NAS address and port
# -------------------------------------------------------

# get NAS hostname and port from script name
NAS_HOST=$(basename $0 | cut -d'_' -f2)
NAS_PORT=$(( $(basename $0 | cut -d'_' -f3) ))

# set IP according to hostname and port
[ "${NAS_PORT}" = "0" ] && NAS_IP="${NAS_HOST}" || NAS_IP="${NAS_HOST}:${NAS_PORT}"

# -------------------------------------------------------
#   Handle SNMP snmpconf call
#   Announce required MIBs
# -------------------------------------------------------
if [ "$1" = "snmpconf" ];
then

  echo "require ${MIB_MANUFACTURER}"
  echo "require ${MIB_MODEL}"
  echo "require ${MIB_STATUS}"
  echo "require ${MIB_POWER_NOMINAL}"
  echo "require ${MIB_POWER_LOAD}"
  echo "require ${MIB_BATTERY_TYPE}"
  echo "require ${MIB_BATTERY_CHARGE}"
  echo "require ${MIB_BATTERY_RUNTIME}"

# -------------------------------------------------------
#   Handle SNMP config call
#   Publish plugin configuration
# -------------------------------------------------------
elif [ "$1" = "config" ];
then

  # read SNMP MIB
  MIB_RESULT=$(snmpget -v1 -c public ${NAS_IP} ${MIB_MANUFACTURER} ${MIB_MODEL} ${MIB_STATUS} ${MIB_POWER_NOMINAL} ${MIB_BATTERY_TYPE})

  # get values from result
  UPS_MANUFACTURER=$(echo ${MIB_RESULT} | sed "s/^.*ups.mfr[^']*'\([^']*\).*$/\1/g")
  UPS_MODEL=$(echo ${MIB_RESULT} | sed "s/^.*ups.model[^']*'\([^']*\).*$/\1/g")
  UPS_STATUS=$(echo ${MIB_RESULT} | sed "s/^.*ups.status[^']*'\([^']*\).*$/\1/g")
  UPS_POWER=$(echo ${MIB_RESULT} | sed "s/^.*ups.realpower.nominal[^']*'\([^']*\).*$/\1/g")
  UPS_BATTERY=$(echo ${MIB_RESULT} | sed "s/^.*battery.type[^']*'\([^']*\).*$/\1/g")

  # get UPS connection hostname
  echo "host_name $NAS_HOST"

  # graph  description
  echo "graph_title UPS ${UPS_MANUFACTURER} model ${UPS_MODEL}"
  echo "graph_category power"
  echo "graph_info This graph shows UPS battery charge and load"
  echo "graph_args -l 0"

  # battery capacity
  echo "capacity.info Battery ${UPS_BATTERY} of ${UPS_POWER} VA"
  echo "capacity.label Battery level (%)"
  echo "capacity.draw LINE2"
  [ "${UPS_STATUS}" = "OL" ] && echo "capacity.colour 008000" || echo "capacity.colour FFA500"
  echo "capacity.min 0"
  echo "capacity.max 100"

  # input power
  echo "power.info Input power"
  echo "power.label Input power (%)"
  echo "power.draw LINE1"
  echo "power.colour 0000FF"
  echo "power.min 0"

  # battery runtime
  echo "runtime.info UPS runtime if power failure"
  echo "runtime.label Runtime (mn)"
  echo "runtime.draw LINE1"
  echo "runtime.colour FF0000"
  echo "runtime.min 0"

# -------------------------------------------------------
#   Handle SNMP normal call
#   Provide UPS data
# -------------------------------------------------------
else

  # read SNMP MIB
  MIB_RESULT=$(snmpget -v1 -c public ${NAS_IP} ${MIB_BATTERY_CHARGE} ${MIB_BATTERY_RUNTIME} ${MIB_POWER_LOAD})

  # get values from result
  UPS_LOAD=$(echo ${MIB_RESULT} | sed "s/^.*ups.load[^']*'\([^']*\).*$/\1/g")
  UPS_CHARGE=$(echo ${MIB_RESULT} | sed "s/^.*battery.charge[^']*'\([^']*\).*$/\1/g")
  UPS_RUNTIME=$(echo ${MIB_RESULT} | sed "s/^.*battery.runtime[^']*'\([^']*\).*$/\1/g")

  # publish battery level and runtime
  echo "capacity.value ${UPS_CHARGE}"
  echo "power.value ${UPS_LOAD}"
  echo "runtime.value ${UPS_RUNTIME}"

fi

# exit
exit 0

As with any SNMP munin plugin, you need to create one symbolic lynk by device address and to restart Munin Node :

Terminal
$ ln -s /usr/share/munin/plugins/snmp__ups /etc/munin/plugins/snmp_DeviceNetworkName_DevicePort_ups
$ service munin-node restart

 

Hope it helps.

Signature Technoblog

This article is published "as is", without any warranty that it will work for your specific need.
If you think this article needs some complement, or simply if you think it saved you lots of time & trouble,
just let me know at This email address is being protected from spambots. You need JavaScript enabled to view it.. Cheers !

icon linux icon debian icon apache icon mysql icon php icon piwik icon googleplus