first commit
This commit is contained in:
commit
ef1eb43202
325
NET-SNMP-EXTEND-MIB.txt
Normal file
325
NET-SNMP-EXTEND-MIB.txt
Normal file
@ -0,0 +1,325 @@
|
||||
NET-SNMP-EXTEND-MIB DEFINITIONS ::= BEGIN
|
||||
|
||||
--
|
||||
-- Defines a framework for scripted extensions
|
||||
--
|
||||
|
||||
IMPORTS
|
||||
nsExtensions FROM NET-SNMP-AGENT-MIB
|
||||
|
||||
OBJECT-TYPE, NOTIFICATION-TYPE, MODULE-IDENTITY, Integer32
|
||||
FROM SNMPv2-SMI
|
||||
|
||||
OBJECT-GROUP, NOTIFICATION-GROUP
|
||||
FROM SNMPv2-CONF
|
||||
|
||||
DisplayString, RowStatus, StorageType FROM SNMPv2-TC;
|
||||
|
||||
|
||||
netSnmpExtendMIB MODULE-IDENTITY
|
||||
LAST-UPDATED "201003170000Z"
|
||||
ORGANIZATION "www.net-snmp.org"
|
||||
CONTACT-INFO
|
||||
"postal: Wes Hardaker
|
||||
P.O. Box 382
|
||||
Davis CA 95617
|
||||
|
||||
email: net-snmp-coders@lists.sourceforge.net"
|
||||
DESCRIPTION
|
||||
"Defines a framework for scripted extensions for the Net-SNMP agent."
|
||||
REVISION "201003170000Z"
|
||||
DESCRIPTION
|
||||
"Fixed inconsistencies in the definition of nsExtendConfigTable."
|
||||
REVISION "200405080000Z"
|
||||
DESCRIPTION
|
||||
"First revision."
|
||||
::= { nsExtensions 1 }
|
||||
|
||||
nsExtendObjects OBJECT IDENTIFIER ::= { nsExtensions 2}
|
||||
nsExtendGroups OBJECT IDENTIFIER ::= { nsExtensions 3}
|
||||
|
||||
nsExtendNumEntries OBJECT-TYPE
|
||||
SYNTAX INTEGER
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The number of rows in the nsExtendConfigTable"
|
||||
::= { nsExtendObjects 1 }
|
||||
|
||||
nsExtendConfigTable OBJECT-TYPE
|
||||
SYNTAX SEQUENCE OF NsExtendConfigEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A table of scripted extensions - configuration and (basic) output."
|
||||
::= { nsExtendObjects 2 }
|
||||
|
||||
nsExtendConfigEntry OBJECT-TYPE
|
||||
SYNTAX NsExtendConfigEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A conceptual row within the extension table."
|
||||
INDEX { nsExtendToken }
|
||||
::= { nsExtendConfigTable 1 }
|
||||
|
||||
NsExtendConfigEntry ::= SEQUENCE {
|
||||
nsExtendToken DisplayString,
|
||||
nsExtendCommand DisplayString,
|
||||
nsExtendArgs DisplayString,
|
||||
nsExtendInput DisplayString,
|
||||
nsExtendCacheTime INTEGER,
|
||||
nsExtendExecType INTEGER,
|
||||
nsExtendRunType INTEGER,
|
||||
|
||||
nsExtendStorage StorageType,
|
||||
nsExtendStatus RowStatus
|
||||
}
|
||||
|
||||
--
|
||||
-- The configuration of an extension command
|
||||
--
|
||||
|
||||
nsExtendToken OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"An arbitrary token to identify this extension entry"
|
||||
::= { nsExtendConfigEntry 1 }
|
||||
|
||||
nsExtendCommand OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The full path of the command binary (or script) to run"
|
||||
::= { nsExtendConfigEntry 2 }
|
||||
|
||||
nsExtendArgs OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Any command-line arguments for the command"
|
||||
DEFVAL { ''H } -- the empty string
|
||||
::= { nsExtendConfigEntry 3 }
|
||||
|
||||
nsExtendInput OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The standard input for the command"
|
||||
DEFVAL { ''H } -- the empty string
|
||||
::= { nsExtendConfigEntry 4 }
|
||||
|
||||
nsExtendCacheTime OBJECT-TYPE
|
||||
SYNTAX INTEGER
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The length of time for which the output of
|
||||
this command will be cached. During this time,
|
||||
retrieving the output-related values will not
|
||||
reinvoke the command.
|
||||
A value of -1 indicates that the output results
|
||||
should not be cached at all, and retrieving each
|
||||
individual output-related value will invoke the
|
||||
command afresh."
|
||||
DEFVAL { 5 }
|
||||
::= { nsExtendConfigEntry 5 }
|
||||
|
||||
nsExtendExecType OBJECT-TYPE
|
||||
SYNTAX INTEGER
|
||||
{ exec (1), -- 'fork-and-exec'
|
||||
shell (2) -- run via a sub-shell
|
||||
}
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The mechanism used to invoke the command."
|
||||
DEFVAL { exec }
|
||||
::= { nsExtendConfigEntry 6 }
|
||||
|
||||
nsExtendRunType OBJECT-TYPE
|
||||
SYNTAX INTEGER
|
||||
{ run-on-read (1),
|
||||
run-on-set (2),
|
||||
run-command (3)
|
||||
}
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Used to implement 'push-button' command invocation.
|
||||
The command for a 'run-on-read' entry will be invoked
|
||||
whenever one of the corresponding output-related
|
||||
instances is requested (and assuming the cached value
|
||||
is not still current).
|
||||
The command for a 'run-on-set' entry will only be invoked
|
||||
on receipt of a SET assignment for this object with the
|
||||
value 'run-command'.
|
||||
Reading an instance of this object will always return either
|
||||
'run-on-read' or 'run-on-set'.
|
||||
"
|
||||
DEFVAL { run-on-read }
|
||||
::= { nsExtendConfigEntry 7 }
|
||||
|
||||
--
|
||||
-- Standard table-manipulation objects
|
||||
--
|
||||
|
||||
nsExtendStorage OBJECT-TYPE
|
||||
SYNTAX StorageType
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The storage type for this conceptual row."
|
||||
DEFVAL { volatile }
|
||||
::= { nsExtendConfigEntry 20 }
|
||||
|
||||
nsExtendStatus OBJECT-TYPE
|
||||
SYNTAX RowStatus
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Used to create new rows in the table, in the standard manner.
|
||||
Note that is valid for an instance to be left with the value
|
||||
notInService(2) indefinitely - i.e. the meaning of 'abnormally
|
||||
long' (see RFC 2579, RowStatus) for this table is infinite."
|
||||
::= { nsExtendConfigEntry 21 }
|
||||
|
||||
|
||||
--
|
||||
-- The results of running the extension command
|
||||
--
|
||||
|
||||
nsExtendOutput1Table OBJECT-TYPE
|
||||
SYNTAX SEQUENCE OF NsExtendOutput1Entry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A table of scripted extensions - configuration and (basic) output."
|
||||
::= { nsExtendObjects 3 }
|
||||
|
||||
nsExtendOutput1Entry OBJECT-TYPE
|
||||
SYNTAX NsExtendOutput1Entry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A conceptual row within the extension table."
|
||||
AUGMENTS { nsExtendConfigEntry }
|
||||
::= { nsExtendOutput1Table 1 }
|
||||
|
||||
NsExtendOutput1Entry ::= SEQUENCE {
|
||||
nsExtendOutput1Line DisplayString,
|
||||
nsExtendOutputFull DisplayString,
|
||||
nsExtendOutNumLines Integer32,
|
||||
nsExtendResult Integer32
|
||||
}
|
||||
|
||||
nsExtendOutput1Line OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The first line of output from the command"
|
||||
::= { nsExtendOutput1Entry 1 }
|
||||
|
||||
nsExtendOutputFull OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The full output from the command, as a single string"
|
||||
::= { nsExtendOutput1Entry 2 }
|
||||
|
||||
nsExtendOutNumLines OBJECT-TYPE
|
||||
SYNTAX Integer32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The number of lines of output (and hence
|
||||
the number of rows in nsExtendOutputTable
|
||||
relating to this particular entry)."
|
||||
::= { nsExtendOutput1Entry 3 }
|
||||
|
||||
nsExtendResult OBJECT-TYPE
|
||||
SYNTAX Integer32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The return value of the command."
|
||||
::= { nsExtendOutput1Entry 4 }
|
||||
|
||||
|
||||
--
|
||||
-- The line-based output table
|
||||
--
|
||||
|
||||
nsExtendOutput2Table OBJECT-TYPE
|
||||
SYNTAX SEQUENCE OF NsExtendOutput2Entry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A table of (line-based) output from scripted extensions."
|
||||
::= { nsExtendObjects 4 }
|
||||
|
||||
nsExtendOutput2Entry OBJECT-TYPE
|
||||
SYNTAX NsExtendOutput2Entry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A conceptual row within the line-based output table."
|
||||
INDEX { nsExtendToken, nsExtendLineIndex }
|
||||
::= { nsExtendOutput2Table 1 }
|
||||
|
||||
NsExtendOutput2Entry ::= SEQUENCE {
|
||||
nsExtendLineIndex INTEGER,
|
||||
nsExtendOutLine DisplayString
|
||||
}
|
||||
|
||||
nsExtendLineIndex OBJECT-TYPE
|
||||
SYNTAX INTEGER(1..1024)
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The index of this line of output.
|
||||
For a given nsExtendToken, this will run from
|
||||
1 to the corresponding value of nsExtendNumLines."
|
||||
::= { nsExtendOutput2Entry 1 }
|
||||
|
||||
nsExtendOutLine OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A single line of output from the extension command."
|
||||
::= { nsExtendOutput2Entry 2 }
|
||||
|
||||
--
|
||||
-- Conformance-related definitions
|
||||
--
|
||||
|
||||
nsExtendConfigGroup OBJECT-GROUP
|
||||
OBJECTS {
|
||||
nsExtendCommand, nsExtendArgs, nsExtendInput,
|
||||
nsExtendCacheTime, nsExtendExecType, nsExtendRunType,
|
||||
nsExtendStorage, nsExtendStatus, nsExtendNumEntries
|
||||
}
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Objects relating to the configuration of extension commands."
|
||||
::= { nsExtendGroups 1 }
|
||||
|
||||
nsExtendOutputGroup OBJECT-GROUP
|
||||
OBJECTS {
|
||||
nsExtendOutNumLines, nsExtendResult,
|
||||
nsExtendOutLine, nsExtendOutput1Line, nsExtendOutputFull
|
||||
}
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Objects relating to the output of extension commands."
|
||||
::= { nsExtendGroups 2 }
|
||||
|
||||
END
|
197
README.md
Normal file
197
README.md
Normal file
@ -0,0 +1,197 @@
|
||||
# Install + Configure NUT & NET-SNMP
|
||||
|
||||
## Install and Configure NUT
|
||||
|
||||
If you're not using the same UPS, check the NUT hardware compatibility list to see if your equipment is supported by the drivers included with NUT. First, run the command below to install NUT
|
||||
|
||||
```
|
||||
sudo apt install nut
|
||||
```
|
||||
|
||||
Next, let's configure NUT:
|
||||
|
||||
```
|
||||
$ sudo vi /etc/ups/ups.conf
|
||||
```
|
||||
|
||||
Append these lines:
|
||||
|
||||
```
|
||||
[name_of_your_ups]
|
||||
driver = usbhid-ups
|
||||
port = auto
|
||||
desc = "Description of your UPS"
|
||||
```
|
||||
|
||||
Change [name_of_your_ups] to any name you'd like. This value becomes the query name for polling the device.
|
||||
|
||||
Let's restart the UPS driver:
|
||||
|
||||
```
|
||||
sudo systemctl reload nut-driver.service
|
||||
```
|
||||
|
||||
If you receive any error ensure you have sudo privileges—and try restarting the machine if the problem persists. We will also set NUT's mode to standalone.
|
||||
|
||||
sudo vi /etc/ups/nut.conf
|
||||
|
||||
```
|
||||
MODE=standalone
|
||||
```
|
||||
|
||||
From their documentation:
|
||||
|
||||
- standalone: This mode address a local only configuration, with 1 UPS protecting the local system. This implies to start the 3 NUT layer (driver, upsd and upsmon) and the matching configuration files. This mode can also address UPS redundancy.
|
||||
|
||||
## Configure NUT server and monitor
|
||||
|
||||
Once the driver is up and running, we need to set up the user for accessing the NUT daemon. Append the following under upsd.users.
|
||||
|
||||
sudo vi /etc/ups/upsd.users
|
||||
|
||||
```
|
||||
[upsmon]
|
||||
password = <secretpass>
|
||||
upsmon master
|
||||
```
|
||||
|
||||
Change <secretpass> to a secure password of your choosing.
|
||||
|
||||
Lastly, we'll edit the NUT monitor configuration with the name of our device, and the access information for the newly created user. Append the following under upsmon.conf
|
||||
|
||||
sudo vi /etc/ups/upsmon.conf
|
||||
|
||||
```
|
||||
MONITOR cyberpower@localhost 1 local_mon <secretpass> master
|
||||
```
|
||||
|
||||
Of course, change cyberpower to the name you gave your device, and <secretpass> to the password you specified in /etc/ups/upsd.users
|
||||
Enable services
|
||||
|
||||
To ensure monitoring ability after planned and unplanned reboots, we need to enable and start the NUT system services.
|
||||
|
||||
```
|
||||
sudo systemctl enable nut-monitor.service
|
||||
sudo systemctl enable nut-server.service
|
||||
sudo systemctl start nut-server.service
|
||||
sudo systemctl start nut-monitor.service
|
||||
```
|
||||
|
||||
If you encounter any errors starting the services, restarting may resolve these. Often, running upsdrvctl start as we did earlier hijacks USB communication with the UPS and causes an error when trying to start NUT services.
|
||||
Test UPS querying!
|
||||
|
||||
Run (replacing cyberpower with your device name):
|
||||
|
||||
```
|
||||
upsc name_of_your_ups
|
||||
```
|
||||
|
||||
And, if all configurations are happy you will see some data returned:
|
||||
|
||||
```
|
||||
battery.charge: 100
|
||||
battery.charge.low: 10
|
||||
battery.charge.warning: 20
|
||||
battery.mfr.date: CPS
|
||||
battery.runtime: 2790
|
||||
battery.runtime.low: 300
|
||||
battery.type: PbAcid
|
||||
battery.voltage: 16.0
|
||||
battery.voltage.nominal: 24
|
||||
device.mfr: CPS
|
||||
device.model: CP850PFCLCD
|
||||
device.serial: 000000000000
|
||||
device.type: ups
|
||||
driver.name: usbhid-ups
|
||||
driver.parameter.pollfreq: 30
|
||||
driver.parameter.pollinterval: 2
|
||||
driver.parameter.port: auto
|
||||
driver.version: 2.7.2
|
||||
driver.version.data: CyberPower HID 0.3
|
||||
driver.version.internal: 0.38
|
||||
input.transfer.high: 139
|
||||
input.transfer.low: 88
|
||||
...
|
||||
```
|
||||
|
||||
## Install Net-SNMP
|
||||
|
||||
```
|
||||
sudo yum install net-snmp
|
||||
```
|
||||
|
||||
Create the script for MIB formatting of the query data: Note: this script formats MIBs specifically for LibreNMS.
|
||||
|
||||
```
|
||||
sudo vi /etc/snmp/ups-nut.sh
|
||||
```
|
||||
|
||||
Past the following, making sure to change UPS_NAME to your device name:
|
||||
|
||||
```
|
||||
#!/usr/bin/env bash
|
||||
|
||||
UPS_NAME='cyberpower'
|
||||
|
||||
PATH=$PATH:/usr/bin:/bin
|
||||
TMP=$(upsc $UPS_NAME 2>/dev/null)
|
||||
|
||||
for value in "battery\.charge: [0-9.]+" "battery\.(runtime\.)?low: [0-9]+" "battery\.runtime: [0-9]+" "battery\.voltage: [0-9.]+" "battery\.voltage\.nominal: [0-9]+" "input\.voltage\.nominal: [0-9.]+" "input\.voltage: [0-9.]+" "ups\.load: [0-9.]+"
|
||||
do
|
||||
OUT=$(echo $TMP | grep -Eo "$value" | awk '{print $2}' | LANG=C sort | head -n 1)
|
||||
if [ -n "$OUT" ]; then
|
||||
echo $OUT
|
||||
else
|
||||
echo "Unknown"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
Make the script executable:
|
||||
|
||||
```
|
||||
sudo chmod +x /etc/snmp/ups-nut.sh
|
||||
```
|
||||
|
||||
Now let's extend this script to the SNMP daemon:
|
||||
|
||||
```
|
||||
sudo vi /etc/snmp/snmpd.conf
|
||||
```
|
||||
|
||||
Append the following and change <community> to your community name:
|
||||
|
||||
```
|
||||
rocommunity <community>
|
||||
extend ups-nut /etc/snmp/ups-nut.sh
|
||||
```
|
||||
|
||||
Let's enable and start the SNMP daemon:
|
||||
|
||||
```
|
||||
sudo systemctl enable snmpd
|
||||
sudo systemctl start snmpd
|
||||
```
|
||||
|
||||
And finally, make a test query from a another host that can reach the server:
|
||||
|
||||
```
|
||||
$ snmpwalk -v2c -c <community> <host> 'NET-SNMP-EXTEND-MIB::nsExtendOutLine'
|
||||
|
||||
You should see results similar to this:
|
||||
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".1 = STRING: 100
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".2 = STRING: 300
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".3 = STRING: 2790
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".4 = STRING: 16.0
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".5 = STRING: 24
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".6 = STRING: 120
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".7 = STRING: 125.0
|
||||
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".8 = STRING: 14
|
||||
```
|
||||
|
||||
Your host can now receive an SNMP query, poll your device with NUT, and respond with MIBs formatted for display/graphing on LibreNMS, Observium, or other SNMP-based monitoring platforms.
|
||||
|
||||
You could also skip SNMP entirely and use a bash or python script to automate the retrieval of the UPS values via the upsc command.
|
||||
|
||||
I hope this helps anyone looking to quantify and monitor the health of their UPS from afar.
|
16
ups-nut.sh
Normal file
16
ups-nut.sh
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
UPS_NAME='tripplite'
|
||||
|
||||
PATH=$PATH:/usr/bin:/bin
|
||||
TMP=$(upsc $UPS_NAME 2>/dev/null)
|
||||
|
||||
for value in "battery\.charge: [0-9.]+" "battery\.(runtime\.)?low: [0-9]+" "battery\.runtime: [0-9]+" "battery\.voltage: [0-9.]+" "battery\.voltage\.nominal: [0-9]+" "input\.voltage\.nominal: [0-9.]+" "input\.voltage: [0-9.]+" "ups\.load: [0-9.]+"
|
||||
do
|
||||
OUT=$(echo $TMP | grep -Eo "$value" | awk '{print $2}' | LANG=C sort | head -n 1)
|
||||
if [ -n "$OUT" ]; then
|
||||
echo $OUT
|
||||
else
|
||||
echo "Unknown"
|
||||
fi
|
||||
done
|
Loading…
x
Reference in New Issue
Block a user