FIrst Commit

main
Petr Vanin 2 years ago
commit 974f052a77
  1. 77
      README.md
  2. BIN
      Screenshot_20231112_014602.png
  3. 18
      apc_read_sql_strings.sh
  4. 109
      apc_snmp_metrics.sh
  5. 16
      apcups_telegram.service
  6. 32
      apcups_telegram.sh
  7. 44
      check_snmp_apc_ups_state/README.md
  8. 199
      check_snmp_apc_ups_state/check_snmp_apc_ups_state.sh

@ -0,0 +1,77 @@
## About
**Bash APC scripts** - other method for APC AP96xx than apcupsd or nut.
*I express my gratitude to [Alexey Maksimov](https://blog.it-kb.ru/about-this-blog/) for examples of working snmp handlers - (fork of [his code](https://github.com/Aleksey-Maksimov/check_snmp_apc_ups_state) is in the attachment)*
### This apc_snmp_metrics.sh script can show current state from networked APC UPS.
Tested on **Centos 7 GNU/Linux** with **AP9618** in **SURTD3000XLI**, with external termistor **AP9512TBLK**
<br/>
## Usage
To start you need:
1. add IP (string number 14 variable IPS)
2. add the user (string number 15 variable SUSER)
3. add the bot token (string number 20 variable TOKEN)
4. add chat ID (string number 21 variable CHAT_ID)
5. add the directory (optional - defalts creates in ```$(pwd)``` dir)
6. create an init file (optional, see the example **apcups_telegram.service** file)
#### For one-shot (non-interactive) - simple run in bash:
```
~# bash apc_snmp_metrics.sh
```
And there is example of success result (database not created, only verbosed hypothetic name with path) :
```
DB 2023.1112.0043_apc-metric.db
WATTS 16
AMPRS 2
CBATT 17
CEEXT 22
INPWA 221
PRBAT 100
REMAT 1:15:05.00
BAREP 1
DATES 1699739034
DATEN 491653013
EXITS 0
```
**WATTS** - percent of UPS load in watts
**AMPRS** - current load in amperes
**CBATT** - internal battery temperature
**CEEXT** - external AP9512TBLK temperature
**INPWA** - input line voltage
**PRBAT** - percent of charge batteries
**REMAT** - remain time for current load if 220/230 line turns off
**BAREP** - battery replasing key - 1 is OK, 2 is REPLACE
**DATES** - unix-seconds (date) of local machine
**DATEN** - nano-seconds, each string need for being unique
**EXITS** - exit-code from snmpget utility, used in Telegram function
<br/>
### For daemonized use ```--run``` argument (mode for systemd unit)
#### This mode creates sqlite database file, than you can get logged data from it.
The database is created anew every time you start it, create a separate directory within /usr/share/ for example.
```
$ bash apc_snmp_metrics.sh --run
DB /root/2023.1112.0043_apc-metric.db
```
### Warning! Monitor the disk usage, this script cat write more than 2 MB of data per hour!
#### For reading sqlite database (daemonized data-log) - run
```~# bash apc_read_sql_strings.sh```
This script searching for last writed .db file in specified folder and SELECTing from
<br/>
### Also have fun! Bash rules!
![picture](https://sources.krechet.tech/vaninpetr/apc_bash/raw/branch/main/Screenshot_20231112_014602.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

@ -0,0 +1,18 @@
#!/bin/bash
cd # write directory for sqlitedb file
DATABASE=$( ls -t *_apc-metric.db | head -1 )
du -sh $DATABASE
sqlreadtable(){
cat << FEO | sqlite3 $DATABASE
.timeout 2000
SELECT * FROM ( \
SELECT * FROM mainmetric0 \
ORDER BY id DESC LIMIT 10 )\
ORDER BY id ;
FEO
}
sqlreadtable

@ -0,0 +1,109 @@
#!/bin/bash
OIDS=$( cat << EOF
1.3.6.1.4.1.318.1.1.1.4.2.3.0
1.3.6.1.4.1.318.1.1.1.4.2.4.0
1.3.6.1.4.1.318.1.1.1.2.2.2.0
1.3.6.1.4.1.318.1.1.10.2.3.2.1.4.1
1.3.6.1.4.1.318.1.1.1.3.2.1.0
1.3.6.1.4.1.318.1.1.1.2.2.1.0
1.3.6.1.4.1.318.1.1.1.2.2.3.0
1.3.6.1.4.1.318.1.1.1.7.2.3.0
EOF
)
IPS='' # add ip of APC AP module
SUSER='' # add snmp user (version 3)
cd # write directory for sqlitedb file
funcsend(){
if [[ "$EXITS" != "0" ]]; then
TOKEN="" # write Telegrambot token
CHAT_ID="" # write Telegram chat id
curl -s -X POST \
https://api.telegram.org/bot"$TOKEN"/sendMessage \
-d chat_id="$CHAT_ID" \
-d text="ERROR IN APC SNMPGET"
sleep 10
fi
}
funconexit(){
exit 0
}
trap 'funconexit' SIGINT
DATABASE="$(date "+%Y.%m%d.%H%M")_apc-metric.db"
echo DB "$DATABASE"
sqlcreatetables(){
cat << EFO | sqlite3 "$DATABASE"
.timeout 200
CREATE TABLE IF NOT EXISTS mainmetric0 \
( id INTEGER PRIMARY KEY AUTOINCREMENT, \
watts TEXT, amperes TEXT, battemp TEXT, \
exttemp TEXT, input TEXT, battperc TEXT, \
remainperc TEXT, replace TEXT, unixsec TEXT, \
msec TEXT, exitcodes TEXT );
EFO
}
sqlwritetable(){
sqlcreatetables
cat << EOF | sqlite3 "$DATABASE"
.timeout 200
INSERT INTO mainmetric0 ( watts, amperes, battemp, \
exttemp, input, battperc, remainperc, replace, \
unixsec, msec, exitcodes ) \
VALUES ( "$WATTS", "$AMPRS", \
"$CBATT", "$CEEXT", "$INPWA", \
"$PRBAT", "$REMAT", "$BAREP", \
"$DATES", "$DATEN", "$EXITS" );
EOF
}
funcrun(){
VARS="$( snmpget -u $SUSER -v 3 $IPS $OIDS 2>/dev/null )"
EXITS="$?"
# Percentage load (of watts)
WATTS=$( echo "$VARS" | grep '4.2.3.0' | grep -o '[^ ]*$' )
# Amperes of load
AMPRS=$( echo "$VARS" | grep '4.2.4.0' | grep -o '[^ ]*$' )
# Celsius on battery
CBATT=$( echo "$VARS" | grep '2.2.2.0' | grep -o '[^ ]*$' )
# External celsius
CEEXT=$( echo "$VARS" | grep '2.1.4.1' | grep -o '[^ ]*$' )
# Volts input
INPWA=$( echo "$VARS" | grep '3.2.1.0' | grep -o '[^ ]*$' )
# battery percents
PRBAT=$( echo "$VARS" | grep '2.2.1.0' | grep -o '[^ ]*$' )
# remaining time
REMAT=$( echo "$VARS" | grep '2.2.3.0' | grep -o '[^ ]*$' )
# battery replace (replace if =2)
BAREP=$( echo "$VARS" | grep '7.2.3.0' | grep -o '[^ ]*$' )
# datetimer
DATES=$( date "+%s" )
DATEN=$( date "+%N" )
}
RUNANSW01=$( echo "$@" | grep -oP '\--run' | grep -oP 'run' )
if [[ "$RUNANSW01" = "run" ]]; then
while : ; do
funcrun &>/dev/null
sqlwritetable
funcsend &>/dev/null
done
else
funcrun &>/dev/null
funcsend &>/dev/null
echo WATTS $WATTS
echo AMPRS $AMPRS
echo CBATT $CBATT
echo CEEXT $CEEXT
echo INPWA $INPWA
echo PRBAT $PRBAT
echo REMAT $REMAT
echo BAREP $BAREP
echo DATES $DATES
echo DATEN $DATEN
echo EXITS $EXITS
fi

@ -0,0 +1,16 @@
[Unit]
Description=APC SNMP TRIGGER
Requires=network-online.target
[Service]
Type=simple
User=root
Group=root
ExecStart=/bin/bash /root/apcups_telegram.sh
Restart=always
RestartSec=10
TimeoutSec=10
[Install]
WantedBy=multi-user.target

@ -0,0 +1,32 @@
#!/bin/bash
IPS='' # add ip of APC AP module
SUSER1='' # add snmp user
funcsnmp(){
cd check_snmp_apc_ups_state
bash check_snmp_apc_ups_state.sh -H $IPS -P 1 -C $SUSER1
}
funcsend(){
TOKEN="" # write Telegrambot token
CHAT_ID="" # write Telegram chat id
curl -s -X POST \
https://api.telegram.org/bot"$TOKEN"/sendMessage \
-d chat_id="$CHAT_ID" \
-d text="$varfuncsnmp"
}
varf=$( funcsnmp | md5sum )
while :; do
sleep 1
varfuncsnmp="$( funcsnmp )"
vars=$( echo "$varfuncsnmp" | md5sum )
if [[ $vars != $varf ]]; then
# echo EDITED $(date "+%F_%s")
funcsend > /dev/null
fi
varf=$vars
# sleep 5
done

@ -0,0 +1,44 @@
## About
### this is [fork of original](https://github.com/Aleksey-Maksimov/check_snmp_apc_ups_state) by Alexey Maximov
###
**check_snmp_apc_ups_state** - Icinga Plugin Script (Check Command).
It calculate APC UPS current state from SNMP data in upsBasicStateOutputState
Tested on **Debian GNU/Linux 9.11 (Stretch)** with **Icinga r2.10.5-1**
Put here: /usr/lib/nagios/plugins/check_snmp_apc_ups_state.sh
PreReq: **snpmget** tool
## Usage
Options:
```
$ /usr/lib/nagios/plugins/check_snmp_apc_ups_state.sh [OPTIONS]
Option GNU long option Meaning
------ -------------- -------
-H --hostname Host name, IP Address
-P --protocol SNMP protocol version. Possible values: 1|2c|3
-C --community SNMPv1/2c community string for SNMP communication (for example,public)
-L --seclevel SNMPv3 securityLevel. Possible values: noAuthNoPriv|authNoPriv|authPriv
-a --authproto SNMPv3 auth proto. Possible values: MD5|SHA
-x --privproto SNMPv3 priv proto. Possible values: DES|AES
-U --secname SNMPv3 username
-A --authpassword SNMPv3 authentication password
-X --privpasswd SNMPv3 privacy password
-q --help Show this message
-v --version Print version information and exit
```
Example for all UPS types:
```
$ ./check_snmp_apc_ups_state.sh -H ups001.holding.com -P 2c -C public
```
Icinga Director integration manual (in Russian):
[Icinga плагин check_snmp_apc_ups_state для расширенного отслеживания аварийных состояний ИБП APC по данным, полученным по протоколу SNMP из параметра upsBasicStateOutputState](https://blog.it-kb.ru/2019/09/20/icinga-plugin-check_snmp_apc_ups_state-for-abnormal-conditions-monitoring-of-apc-ups-from-snmp-in-flags-from-upsbasicstateoutputstate/)

@ -0,0 +1,199 @@
#!/bin/bash
#
# Icinga Plugin Script (Check Command). It calculate APC UPS current state from SNMP data in upsBasicStateOutputState
# Aleksey Maksimov <aleksey.maksimov@it-kb.ru>
# Tested on Debian GNU/Linux 9.11 (Stretch) with Icinga r2.10.5-1
# Put here: /usr/lib/nagios/plugins/check_snmp_apc_ups_state.sh
# Usage example:
# ./check_snmp_apc_ups_state.sh -H ups-nmc-01.holding.com -P 2c -C public
#
PLUGIN_NAME="Icinga Plugin Check Command to calculate APC UPS current state (from SNMP data)"
PLUGIN_VERSION="2019.09.16"
PRINTINFO=`printf "\n%s, version %s\n \n" "$PLUGIN_NAME" "$PLUGIN_VERSION"`
#
# Exit codes
#
codeOK=0
codeWARNING=1
codeCRITICAL=2
codeUNKNOWN=3
#
# OID
#
checkOID="1.3.6.1.4.1.318.1.1.1.11.1.1.0"
#
Usage() {
echo "$PRINTINFO"
echo "Usage: $0 [OPTIONS]
Option GNU long option Meaning
------ --------------- -------
-H --hostname Host name, IP Address
-P --protocol SNMP protocol version. Possible values: 1|2c|3
-C --community SNMPv1/2c community string for SNMP communication (for example,"public")
-L --seclevel SNMPv3 securityLevel. Possible values: noAuthNoPriv|authNoPriv|authPriv
-a --authproto SNMPv3 auth proto. Possible values: MD5|SHA
-x --privproto SNMPv3 priv proto. Possible values: DES|AES
-U --secname SNMPv3 username
-A --authpassword SNMPv3 authentication password
-X --privpasswd SNMPv3 privacy password
-q --help Show this message
-v --version Print version information and exit
"
}
#
# Parse arguments
#
if [ -z $1 ]; then
Usage; exit $codeUNKNOWN;
fi
#
OPTS=`getopt -o H:P:C:L:a:x:U:A:X:qv -l hostname:,protocol:,community:,seclevel:,authproto:,privproto:,secname:,authpassword:,privpasswd:,help,version -- "$@"`
eval set -- "$OPTS"
while true; do
case $1 in
-H|--hostname) HOSTNAME=$2 ; shift 2 ;;
-P|--protocol)
case "$2" in
"1"|"2c"|"3") PROTOCOL=$2 ; shift 2 ;;
*) printf "Unknown value for option %s. Use '1' or '2c' or '3'\n" "$1" ; exit $codeUNKNOWN ;;
esac ;;
-C|--community) COMMUNITY=$2 ; shift 2 ;;
-L|--seclevel)
case "$2" in
"noAuthNoPriv"|"authNoPriv"|"authPriv") v3SECLEVEL=$2 ; shift 2 ;;
*) printf "Unknown value for option %s. Use 'noAuthNoPriv' or 'authNoPriv' or 'authPriv'\n" "$1" ; exit $codeUNKNOWN ;;
esac ;;
-a|--authproto)
case "$2" in
"MD5"|"SHA") v3AUTHPROTO=$2 ; shift 2 ;;
*) printf "Unknown value for option %s. Use 'MD5' or 'SHA'\n" "$1" ; exit $codeUNKNOWN ;;
esac ;;
-x|--privproto)
case "$2" in
"DES"|"AES") v3PRIVPROTO=$2 ; shift 2 ;;
*) printf "Unknown value for option %s. Use 'DES' or 'AES'\n" "$1" ; exit $codeUNKNOWN ;;
esac ;;
-U|--secname) v3SECNAME=$2 ; shift 2 ;;
-A|--authpassword) v3AUTHPWD=$2 ; shift 2 ;;
-X|--privpasswd) v3PRIVPWD=$2 ; shift 2 ;;
-q|--help) Usage ; exit $codeOK ;;
-v|--version) echo "$PRINTINFO" ; exit $codeOK ;;
--) shift ; break ;;
*) Usage ; exit $codeUNKNOWN ;;
esac
done
#
# Set SNMP connection paramaters
#
vCS=$( echo " -O qvn -v $PROTOCOL" )
if [ "$PROTOCOL" = "1" ] || [ "$PROTOCOL" = "2c" ]
then
vCS=$vCS$( echo " -c $COMMUNITY" );
elif [ "$PROTOCOL" = "3" ]
then
vCS=$vCS$( echo " -l $v3SECLEVEL" );
vCS=$vCS$( echo " -a $v3AUTHPROTO" );
vCS=$vCS$( echo " -x $v3PRIVPROTO" );
vCS=$vCS$( echo " -A $v3AUTHPWD" );
vCS=$vCS$( echo " -X $v3PRIVPWD" );
vCS=$vCS$( echo " -u $v3SECNAME" );
fi
#
# Calculate APC UPS State
#
vOIDOut=$( snmpget $vCS $HOSTNAME $checkOID )
vOIDOut=$( echo $vOIDOut | tr -d '"' )
if [ ${#vOIDOut} -ne 64 ]; then
echo "The string length obtained from the SNMP parameter 'upsBasicStateOutputState' is not equal to 64 characters. So we cannot parse the data."
exit $codeUNKNOWN
fi
declare -a vFlags=(
"Flag 01: Abnormal Condition Present"
"Flag 02: On Battery"
"Flag 03: Low Battery"
"Flag 04: On Line"
"Flag 05: Replace Battery"
"Flag 06: Serial Communication Established"
"Flag 07: AVR Boost Active"
"Flag 08: AVR Trim Active"
"Flag 09: Overload"
"Flag 10: Runtime Calibration"
"Flag 11: Batteries Discharged"
"Flag 12: Manual Bypass"
"Flag 13: Software Bypass"
"Flag 14: In Bypass due to Internal Fault"
"Flag 15: In Bypass due to Supply Failure"
"Flag 16: In Bypass due to Fan Failure"
"Flag 17: Sleeping on a Timer"
"Flag 18: Sleeping until Utility Power Returns"
"Flag 19: On"
"Flag 20: Rebooting"
"Flag 21: Battery Communication Lost"
"Flag 22: Graceful Shutdown Initiated"
"Flag 23: Smart Boost or Smart Trim Fault"
"Flag 24: Bad Output Voltage"
"Flag 25: Battery Charger Failure"
"Flag 26: High Battery Temperature"
"Flag 27: Warning Battery Temperature"
"Flag 28: Critical Battery Temperature"
"Flag 29: Self Test In Progress"
"Flag 30: Low Battery / On Battery"
"Flag 31: Graceful Shutdown Issued by Upstream Device"
"Flag 32: Graceful Shutdown Issued by Downstream Device"
"Flag 33: No Batteries Attached"
"Flag 34: Synchronized Command is in Progress"
"Flag 35: Synchronized Sleeping Command is in Progress"
"Flag 36: Synchronized Rebooting Command is in Progress"
"Flag 37: Inverter DC Imbalance"
"Flag 38: Transfer Relay Failure"
"Flag 39: Shutdown or Unable to Transfer"
"Flag 40: Low Battery Shutdown"
"Flag 41: Electronic Unit Fan Failure"
"Flag 42: Main Relay Failure"
"Flag 43: Bypass Relay Failure"
"Flag 44: Temporary Bypass"
"Flag 45: High Internal Temperature"
"Flag 46: Battery Temperature Sensor Fault"
"Flag 47: Input Out of Range for Bypass"
"Flag 48: DC Bus Overvoltage"
"Flag 49: PFC Failure"
"Flag 50: Critical Hardware Fault"
"Flag 51: Green Mode/ECO Mode"
"Flag 52: Hot Standby"
"Flag 53: Emergency Power Off (EPO) Activated"
"Flag 54: Load Alarm Violation"
"Flag 55: Bypass Phase Fault"
"Flag 56: UPS Internal Communication Failure"
"Flag 57: Efficiency Booster Mode"
"Flag 58: Off"
"Flag 59: Standby"
"Flag 60: Minor or Environment Alarm")
vFlag1=$( echo $vOIDOut | awk '{print substr($0,0,1)}' )
vFlagsStr=""
vIndex=0
for vFlag in "${vFlags[@]}"; do
vFlagN=$( echo ${vOIDOut:vIndex:1} )
if [ "$vFlagN" -eq "1" ]; then
vFlagsStr=$vFlagsStr$( echo "\n${vFlag}" );
fi
let vIndex=${vIndex}+1
done
#
# Icinga Check Plugin output
#
if [ "$vFlag1" -eq "1" ]; then
echo -e "APC UPS State CRITICAL \nCurrent active flags:$vFlagsStr"
exit $codeCRITICAL
elif [ "$vFlag1" -eq "0" ]; then
echo -e "APC UPS State OK \nCurrent active flags:$vFlagsStr"
exit $codeOK
fi
exit $codeUNKNOWN
Loading…
Cancel
Save