commit 974f052a77328c907fea65fb2c4d30898ab2e3ef Author: VaninPetr Date: Sun Nov 12 14:12:50 2023 +0300 FIrst Commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..d82fa85 --- /dev/null +++ b/README.md @@ -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** + +
+ +## 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 + +
+ +### 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 + +
+ +### Also have fun! Bash rules! + +![picture](https://sources.krechet.tech/vaninpetr/apc_bash/raw/branch/main/Screenshot_20231112_014602.png) \ No newline at end of file diff --git a/Screenshot_20231112_014602.png b/Screenshot_20231112_014602.png new file mode 100644 index 0000000..49dfc23 Binary files /dev/null and b/Screenshot_20231112_014602.png differ diff --git a/apc_read_sql_strings.sh b/apc_read_sql_strings.sh new file mode 100644 index 0000000..f190d6b --- /dev/null +++ b/apc_read_sql_strings.sh @@ -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 + diff --git a/apc_snmp_metrics.sh b/apc_snmp_metrics.sh new file mode 100644 index 0000000..da123f8 --- /dev/null +++ b/apc_snmp_metrics.sh @@ -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 diff --git a/apcups_telegram.service b/apcups_telegram.service new file mode 100644 index 0000000..2773751 --- /dev/null +++ b/apcups_telegram.service @@ -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 diff --git a/apcups_telegram.sh b/apcups_telegram.sh new file mode 100644 index 0000000..770cfa3 --- /dev/null +++ b/apcups_telegram.sh @@ -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 diff --git a/check_snmp_apc_ups_state/README.md b/check_snmp_apc_ups_state/README.md new file mode 100644 index 0000000..4f4c5d5 --- /dev/null +++ b/check_snmp_apc_ups_state/README.md @@ -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/) diff --git a/check_snmp_apc_ups_state/check_snmp_apc_ups_state.sh b/check_snmp_apc_ups_state/check_snmp_apc_ups_state.sh new file mode 100644 index 0000000..ce318f0 --- /dev/null +++ b/check_snmp_apc_ups_state/check_snmp_apc_ups_state.sh @@ -0,0 +1,199 @@ +#!/bin/bash +# +# Icinga Plugin Script (Check Command). It calculate APC UPS current state from SNMP data in upsBasicStateOutputState +# Aleksey Maksimov +# 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