From e849b61d077a9759cef0e5a58b68e90b8ab9cc7b Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Mon, 23 Jan 2017 19:52:44 +0100 Subject: [PATCH 01/31] Create quota2percent_ Quota usage in percent --- plugins/disk/quota2percent_ | 126 ++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 plugins/disk/quota2percent_ diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ new file mode 100644 index 00000000..6ccbc8c5 --- /dev/null +++ b/plugins/disk/quota2percent_ @@ -0,0 +1,126 @@ +#!/bin/bash + +# Spachauswahl +# Language selection + Language="de" + + +# Wildcard-Text erkennen +# get tehe wild card text + Id=$0 + Id=${Id##*_} + +# Einlesen der Quoten für das entsprechende Laufwerk mit repquota +# Reading the quotes for the selected device, using repquota + readarray Quotas < <( repquota /dev/$Id | grep " -- " ) + readarray Totals < <( df /dev/$Id ) + +# Anzahl der Nutzer ermitteln +# Get the count of Users + Users=${#Quotas[@]} + + +################################################### +# Beginn der Standard-Konfigurationsbereiches # +# Standard Config Section Begin # +################################################### + + if [ "$1" = "autoconf" ]; then + echo yes + exit 0 + fi + +. $MUNIN_LIBDIR/plugins/plugin.sh + + if [ "$1" = "config" ]; then + + # Anpassung der Texte in der Grafik + # Localisation of the graphic texts + case $Language in + de) + echo graph_title Quota-Hard-Limit von $Id + echo graph_vlabel Nutzung in % Hardlimit + echo graph_info "Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >=1000) in Prozent des Hardlimits." + Total_txt="Su. aller Nutzer" + Total_info="Inklusive Systemnutzer (UID < 1000)" + ;; + es) + echo graph_title Cuota de límite absoluto de $ Id + echo graph_vlabel el % de uso del límite duro + echo graph_info "El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID> = 1000) como porcentaje de límites duros." + Total_txt="Suma de todos los usuarios " + Total_info="La inclusión de usuario del sistema (UID <1000) " + ;; + *) + echo graph_title quota hard limit of %Id + echo graph_vlabel Usage in % + Total_txt="all users" + echo graph_info "The graphic shows the allocation of the quota-regulated storage space for all regular users (UID> = 1000) as a percentage of the hard limit ." + Total_info="system users (UID < 1000) included" + ;; + esac + + # Standard Konfiguration + # Defaults configuration + echo graph_category disk + echo graph_args --lower-limit 0 --upper-limit 100 + echo graph_printf %5.2lf %% + echo graph_scale no + + # Ggf. Werte aus der Datei munin-node uebernehmen + # if any fetch from munin-node file + Warning=${warning:-90} + Critical=${critical:-95} + + # Die Quota-Nutzer und deren Real-Namen ermitteln, das Root-Problem beheben, die Kondfigurationsdaten ausgeben + # For each quota user fetch his real name, solve the root problem, Output the configuration data + for((i=0; i<$Users; i++));do + Quota=( ${Quotas[$i]} ) + User=${Quota[0]} + Passwd=$(cat /etc/passwd | grep $User) + OLDIFS=$IFS + IFS=':' Infos=($Passwd) + IFS=$OLDIFS + Name=${Infos[4]} + Name=${Name%%,*} + + [ $User == "root" ] && { User="__root"; Name="__root";} + [ ! -n "$Name" ] && Name=$User + [ $(id -u ${Quota[0]}) -lt 1000 ] && echo $User.graph no + echo $User.label $Name + echo $User.warning $warning + echo $User.critical $critical + done + + # Die Summenzeile konfigurieren + # configure the total line + echo total.label $Total_txt + echo total.warning $Warning + echo total.critical $Critical + echo total.info $Total_info + exit 0 + fi + +################################################### +# Ende der Standard-Konfigurationsbereiches # +# Standard Config Section End # +################################################### + +# Die Werte (Belegung und Hardlimit) je Nutzer ermitteln, das Root-Problem umgehen, die Prozente berechnen +# fetch the needed values (used and hard limit) for each user, work around the root problem, calculate the percent value + for((i=0; i<$Users; i++));do + Quota=( ${Quotas[$i]} ) + User=${Quota[0]} + [ $User == "root" ] && User="__root" + Prozent=`echo "scale=2 ; ${Quota[2]}*100/${Quota[4]}" | bc` + + echo $User.value $Prozent + done + +# Die Summenwerte +# the value for the total line + Total=( ${Totals[1]} ) + Summe=`echo "scale=2;${Total[2]}*100/${Total[1]}" | bc` + echo total.value $Summe + + exit 0 From 1605f56bc1a5fec1e5bade91f62f9dfb7f1d0c46 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Tue, 24 Jan 2017 22:28:30 +0100 Subject: [PATCH 02/31] Update quota2percent_ --- plugins/disk/quota2percent_ | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index 6ccbc8c5..37879970 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -1,5 +1,22 @@ #!/bin/bash +# Das Plugin zeigt die Festplattenbelegung in Prozent des Quota-Hard-Limits. +# Munin plugin to show the disk usage in percent of the quota hard limit. +# The base frame is copied from the proftp plugin + +########################################################################################## +# Folgende Eintraege in der Datei /etc/munin/plugin-conf.d/munin-node nicht vergessen ! # +# Don't forget to add following lines to the file /etc/munin/plugin-conf.d/munin-node # +# [quota2percent_*] # +# user root # +# # +# Weiterhin sind folgende Environment-Variablen erlaubt: # +# Following environment variables are allowed: # +# env.warning [value] # +# env.critical [value] # +# V17.0124 Jo Hartmann # +########################################################################################## + # Spachauswahl # Language selection Language="de" From 3a9f69b137cd687bf8490327b5fe8baf9a0f3be7 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 15:08:50 +0100 Subject: [PATCH 03/31] Create fritzbox7490_ --- pugins/fritz-box7490/de/fritzbox7490_ | 191 ++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 pugins/fritz-box7490/de/fritzbox7490_ diff --git a/pugins/fritz-box7490/de/fritzbox7490_ b/pugins/fritz-box7490/de/fritzbox7490_ new file mode 100644 index 00000000..d2051536 --- /dev/null +++ b/pugins/fritz-box7490/de/fritzbox7490_ @@ -0,0 +1,191 @@ +#!/bin/bash + +# Munin plugin um die aktuellen Werte der Datei fritzbox7490.log auszuwerten. +# internet connection by reading the top_status.htm from the +# Don't forget zu fill in the following lines into the munin-node +# +# - normally at /etc/muni/plugin-conf.d/ - an than restart munin +# +# [fritzbox_] +# user root +# +# LLOSS: Leitungsdämpfung = line loss +# DRATE: Datenrate = data rate +# SNR: Störabstand = signal-to-noise ratio +# DATAV: Datenvolumen = data transfer +# ES: Sek. m. Fehlern = sec. w. errors +# SES: Sek. m. v. Fehlern = sec w. m. errors +# VERB: Anzahl tägl. Verb. = count of daily connections +# UPT: Zt. seit Reboot = router uptime +# Jo Hartmann (Version 16.0126) +# + +################################### +## Personal config Section Begin ## +################################### + +logfile=/var/log/fritzbox7490.log + +################################### +## Personal config section End ## +################################### + +function Echo() { +# Munin hat probleme mit Sonderzeichen ÄÖÜ äöüß +# Munin has problems with special characters ÄÖÜ ääüß + konvert=`echo $* | sed s/Ä/Ae/g | sed s/Ö/Oe/g | sed s/Ü/Oe/g | sed s/ä/ae/g | sed s/ö/ue/g | sed s/ü/ue/g | sed s/ß/ss/g` + echo $konvert +} + +# Wildcard-Text erkennen +# Detect wildcard text + id=$0 + id=${id##*_} + +# Prüfen ob die Werte-Datei existiert, wenn ja einlesen sonst Abbruch +# Check if the values ??file exists, if yes read in otherwise abort + if [ -f $logfile ]; then + werte=$(cat $logfile) + else + echo Die Datei $logfile wurde nicht gefunden! Abbruch! >&2 + exit 1 + fi + + +# Standard Config Section Begin ## + if [ "$1" = "autoconf" ]; then + echo yes + exit 0 + fi + + if [ "$1" = "config" ]; then + +# Standard Konfiguration +# Default configuration + echo graph_category DSL + echo graph_args --base 1000 -l 100 + #echo graph_printf %7.3lf%S M + echo graph_info Datenstatistik aus der FRITZ!Box 7490 + +# Wildcard-abhängige Konfiguration überschreibt den obigen Standard +# Wildcard dependent configuration overwrites the above standards + case $id in + LLOSS) + Echo graph_title Leitungsdämpfung + Echo graph_vlabel Dämpfung in db + echo u.label upload + echo d.label download + ;; + DRATE) + Echo graph_title Übertragungsgeschwindigkeit + echo graph_vlabel Datenrate in kbit/s + echo u.label upload + echo d.label download + ;; + SNR) + Echo graph_title Störabstand + echo graph_vlabel Abstand in db + echo u.label upload + echo d.label download + ;; + DATAV) + Echo graph_title tägliches Daten-Volumen + echo graph_vlabel Transfer in MB + echo u.label upload + echo d.label download + echo g.label gesamt + ;; + ES) + echo graph_title Sekunden mit Fehlern \(ES\) + echo graph_vlabel Sekunden + echo u.label upload + echo d.label download + ;; + SES) + echo graph_title Sekunden mit vielen Fehlern \(SES\) + echo graph_vlabel Sekunden + echo u.label upload + echo d.label download + ;; + CRC01) + Echo graph_title Nicht korrigierbare Fehler \(CRC\) + echo graph_vlabel Anzahl + echo u.label upload + echo d.label download + ;; + CRC15) + Echo graph_title Nicht korrigierbare Fehler in 15 Min. \(CRC\) + echo graph_vlabel Anzahl + echo u.label upload + echo d.label download + ;; + VERB) + Echo graph_title Anzahl der täglichen Wiederverbindung + echo graph_vlabel Anzahl + echo u.label upload + echo d.label download + ;; + UPT) + ;; + *) + echo " ##############################################" >&2 + echo " # Felerhafter Programmaufruf, zulässig sind: #" >&2 + echo " # - fritzbox7490_DRATE #" >&2 + echo " # - fritzbox7490_LLOSS #" >&2 + echo " # - fritzbox7490_SNR #" >&2 + echo " # - fritzbox7490_DATAV #" >&2 + echo " # - fritzbox7490_CRC01 #" >&2 + echo " # - fritzbox7490_CRC15 #" >&2 + echo " # - fritzbox7490_ES #" >&2 + echo " # - fritzbox7490_SES #" >&2 + echo " # - fritzbox7490_VERB #" >&2 +# echo " # - fritzbox7490_UPT #" >&2 + echo " ##############################################" >&2 + exit 2 + ;; + esac + exit 0 + fi +# Standard Config Section End #### + +# Wildcard-abhängige Datenauswertung +# Wildcard-dependent data evaluation + case $id in + LLOSS) + u_value=$(echo "${werte}" | awk 'match($0,/pfung OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/mpfung IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value + ;; + DRATE) + u_value=$(echo "${werte}" | awk 'match($0,/atenrate OUT:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo u.value `echo "$u_value * 1024" | bc` + d_value=$(echo "${werte}" | awk 'match($0,/Datenrate IN:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo d.value `echo "$d_value * 1024" | bc` + ;; + SNR) + u_value=$(echo "${werte}" | awk 'match($0,/bstandsmarge OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/abstandsmarge IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value + ;; + DATAV) + u_value=$(echo "${werte}" | awk 'match($0,/volumen \(upload\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/volumen \(download\):.* ([0-9]+) MB/,arr){print arr[1]};'); echo d.value $d_value + g_value=$(echo "${werte}" | awk 'match($0,/volumen \(gesamt\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo g.value $g_value + ;; + CRC01) + u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) IN: .* ([0-9,\.]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) OUT:.* ([0-9,\.]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + CRC15) + u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + ES) + u_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + SES) + u_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + *) + u_value=0 + d_value=0 + ;; + esac From aa881ff45d24ebe32208845c50275d30139a956c Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 15:18:22 +0100 Subject: [PATCH 04/31] Das Plugin selbst - The plugin itself - Das Plugin wertet die vom Batch fritzbox7490.sh erstellte Datei aus. - The plugin evaluates the file created by batch fritzbox7490.sh --- plugins/fritz-box7490/de/fritzbox7490_ | 1 + 1 file changed, 1 insertion(+) create mode 100644 plugins/fritz-box7490/de/fritzbox7490_ diff --git a/plugins/fritz-box7490/de/fritzbox7490_ b/plugins/fritz-box7490/de/fritzbox7490_ new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/plugins/fritz-box7490/de/fritzbox7490_ @@ -0,0 +1 @@ + From a7775a1547805f743d61e50585b51b05250c946b Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 15:20:07 +0100 Subject: [PATCH 05/31] Delete fritzbox7490_ --- plugins/fritz-box7490/de/fritzbox7490_ | 1 - 1 file changed, 1 deletion(-) delete mode 100644 plugins/fritz-box7490/de/fritzbox7490_ diff --git a/plugins/fritz-box7490/de/fritzbox7490_ b/plugins/fritz-box7490/de/fritzbox7490_ deleted file mode 100644 index 8b137891..00000000 --- a/plugins/fritz-box7490/de/fritzbox7490_ +++ /dev/null @@ -1 +0,0 @@ - From a532aade2ce06ade30b2601bdb5f52266007a4fd Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 15:21:07 +0100 Subject: [PATCH 06/31] Delete fritzbox7490_ --- pugins/fritz-box7490/de/fritzbox7490_ | 191 -------------------------- 1 file changed, 191 deletions(-) delete mode 100644 pugins/fritz-box7490/de/fritzbox7490_ diff --git a/pugins/fritz-box7490/de/fritzbox7490_ b/pugins/fritz-box7490/de/fritzbox7490_ deleted file mode 100644 index d2051536..00000000 --- a/pugins/fritz-box7490/de/fritzbox7490_ +++ /dev/null @@ -1,191 +0,0 @@ -#!/bin/bash - -# Munin plugin um die aktuellen Werte der Datei fritzbox7490.log auszuwerten. -# internet connection by reading the top_status.htm from the -# Don't forget zu fill in the following lines into the munin-node -# -# - normally at /etc/muni/plugin-conf.d/ - an than restart munin -# -# [fritzbox_] -# user root -# -# LLOSS: Leitungsdämpfung = line loss -# DRATE: Datenrate = data rate -# SNR: Störabstand = signal-to-noise ratio -# DATAV: Datenvolumen = data transfer -# ES: Sek. m. Fehlern = sec. w. errors -# SES: Sek. m. v. Fehlern = sec w. m. errors -# VERB: Anzahl tägl. Verb. = count of daily connections -# UPT: Zt. seit Reboot = router uptime -# Jo Hartmann (Version 16.0126) -# - -################################### -## Personal config Section Begin ## -################################### - -logfile=/var/log/fritzbox7490.log - -################################### -## Personal config section End ## -################################### - -function Echo() { -# Munin hat probleme mit Sonderzeichen ÄÖÜ äöüß -# Munin has problems with special characters ÄÖÜ ääüß - konvert=`echo $* | sed s/Ä/Ae/g | sed s/Ö/Oe/g | sed s/Ü/Oe/g | sed s/ä/ae/g | sed s/ö/ue/g | sed s/ü/ue/g | sed s/ß/ss/g` - echo $konvert -} - -# Wildcard-Text erkennen -# Detect wildcard text - id=$0 - id=${id##*_} - -# Prüfen ob die Werte-Datei existiert, wenn ja einlesen sonst Abbruch -# Check if the values ??file exists, if yes read in otherwise abort - if [ -f $logfile ]; then - werte=$(cat $logfile) - else - echo Die Datei $logfile wurde nicht gefunden! Abbruch! >&2 - exit 1 - fi - - -# Standard Config Section Begin ## - if [ "$1" = "autoconf" ]; then - echo yes - exit 0 - fi - - if [ "$1" = "config" ]; then - -# Standard Konfiguration -# Default configuration - echo graph_category DSL - echo graph_args --base 1000 -l 100 - #echo graph_printf %7.3lf%S M - echo graph_info Datenstatistik aus der FRITZ!Box 7490 - -# Wildcard-abhängige Konfiguration überschreibt den obigen Standard -# Wildcard dependent configuration overwrites the above standards - case $id in - LLOSS) - Echo graph_title Leitungsdämpfung - Echo graph_vlabel Dämpfung in db - echo u.label upload - echo d.label download - ;; - DRATE) - Echo graph_title Übertragungsgeschwindigkeit - echo graph_vlabel Datenrate in kbit/s - echo u.label upload - echo d.label download - ;; - SNR) - Echo graph_title Störabstand - echo graph_vlabel Abstand in db - echo u.label upload - echo d.label download - ;; - DATAV) - Echo graph_title tägliches Daten-Volumen - echo graph_vlabel Transfer in MB - echo u.label upload - echo d.label download - echo g.label gesamt - ;; - ES) - echo graph_title Sekunden mit Fehlern \(ES\) - echo graph_vlabel Sekunden - echo u.label upload - echo d.label download - ;; - SES) - echo graph_title Sekunden mit vielen Fehlern \(SES\) - echo graph_vlabel Sekunden - echo u.label upload - echo d.label download - ;; - CRC01) - Echo graph_title Nicht korrigierbare Fehler \(CRC\) - echo graph_vlabel Anzahl - echo u.label upload - echo d.label download - ;; - CRC15) - Echo graph_title Nicht korrigierbare Fehler in 15 Min. \(CRC\) - echo graph_vlabel Anzahl - echo u.label upload - echo d.label download - ;; - VERB) - Echo graph_title Anzahl der täglichen Wiederverbindung - echo graph_vlabel Anzahl - echo u.label upload - echo d.label download - ;; - UPT) - ;; - *) - echo " ##############################################" >&2 - echo " # Felerhafter Programmaufruf, zulässig sind: #" >&2 - echo " # - fritzbox7490_DRATE #" >&2 - echo " # - fritzbox7490_LLOSS #" >&2 - echo " # - fritzbox7490_SNR #" >&2 - echo " # - fritzbox7490_DATAV #" >&2 - echo " # - fritzbox7490_CRC01 #" >&2 - echo " # - fritzbox7490_CRC15 #" >&2 - echo " # - fritzbox7490_ES #" >&2 - echo " # - fritzbox7490_SES #" >&2 - echo " # - fritzbox7490_VERB #" >&2 -# echo " # - fritzbox7490_UPT #" >&2 - echo " ##############################################" >&2 - exit 2 - ;; - esac - exit 0 - fi -# Standard Config Section End #### - -# Wildcard-abhängige Datenauswertung -# Wildcard-dependent data evaluation - case $id in - LLOSS) - u_value=$(echo "${werte}" | awk 'match($0,/pfung OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/mpfung IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value - ;; - DRATE) - u_value=$(echo "${werte}" | awk 'match($0,/atenrate OUT:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo u.value `echo "$u_value * 1024" | bc` - d_value=$(echo "${werte}" | awk 'match($0,/Datenrate IN:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo d.value `echo "$d_value * 1024" | bc` - ;; - SNR) - u_value=$(echo "${werte}" | awk 'match($0,/bstandsmarge OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/abstandsmarge IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value - ;; - DATAV) - u_value=$(echo "${werte}" | awk 'match($0,/volumen \(upload\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/volumen \(download\):.* ([0-9]+) MB/,arr){print arr[1]};'); echo d.value $d_value - g_value=$(echo "${werte}" | awk 'match($0,/volumen \(gesamt\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo g.value $g_value - ;; - CRC01) - u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) IN: .* ([0-9,\.]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) OUT:.* ([0-9,\.]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - CRC15) - u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - ES) - u_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - SES) - u_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - *) - u_value=0 - d_value=0 - ;; - esac From 5d09905baa78e8f3490005ab4d062e4a4c3517be Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 15:25:14 +0100 Subject: [PATCH 07/31] FRITZ!Box 7490 PlugIn --- plugins/fritz-box7490/read.me | 1 + 1 file changed, 1 insertion(+) create mode 100644 plugins/fritz-box7490/read.me diff --git a/plugins/fritz-box7490/read.me b/plugins/fritz-box7490/read.me new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/plugins/fritz-box7490/read.me @@ -0,0 +1 @@ + From 70c13a2177d7c79823f6b5d395dedca910385507 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 15:35:21 +0100 Subject: [PATCH 08/31] Das PlugIn selbst - The plugin itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Der Batch-Job fritzbox7490.sh wird durch cron gestartet und liest alle relevanten Daten aus dem AVM-Router aus. - Die Daten werden aufbereitet und in der Datei /var/log/fritzbox7490.log gespeichert. - Das Plugin bereitet die Daten für Munin auf. -------------------------------------------------------------------------------------------------------------------------- - The batch job fritzbox7490.sh is started by cron and reads all relevant data from the AVM router. - The data are processed and stored in the /var/log/fritzbox7490.log file. - The plugin prepares the data for Munin. --- plugins/fritz-box7490/de/fritzbox7490_ | 191 +++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 plugins/fritz-box7490/de/fritzbox7490_ diff --git a/plugins/fritz-box7490/de/fritzbox7490_ b/plugins/fritz-box7490/de/fritzbox7490_ new file mode 100644 index 00000000..d2051536 --- /dev/null +++ b/plugins/fritz-box7490/de/fritzbox7490_ @@ -0,0 +1,191 @@ +#!/bin/bash + +# Munin plugin um die aktuellen Werte der Datei fritzbox7490.log auszuwerten. +# internet connection by reading the top_status.htm from the +# Don't forget zu fill in the following lines into the munin-node +# +# - normally at /etc/muni/plugin-conf.d/ - an than restart munin +# +# [fritzbox_] +# user root +# +# LLOSS: Leitungsdämpfung = line loss +# DRATE: Datenrate = data rate +# SNR: Störabstand = signal-to-noise ratio +# DATAV: Datenvolumen = data transfer +# ES: Sek. m. Fehlern = sec. w. errors +# SES: Sek. m. v. Fehlern = sec w. m. errors +# VERB: Anzahl tägl. Verb. = count of daily connections +# UPT: Zt. seit Reboot = router uptime +# Jo Hartmann (Version 16.0126) +# + +################################### +## Personal config Section Begin ## +################################### + +logfile=/var/log/fritzbox7490.log + +################################### +## Personal config section End ## +################################### + +function Echo() { +# Munin hat probleme mit Sonderzeichen ÄÖÜ äöüß +# Munin has problems with special characters ÄÖÜ ääüß + konvert=`echo $* | sed s/Ä/Ae/g | sed s/Ö/Oe/g | sed s/Ü/Oe/g | sed s/ä/ae/g | sed s/ö/ue/g | sed s/ü/ue/g | sed s/ß/ss/g` + echo $konvert +} + +# Wildcard-Text erkennen +# Detect wildcard text + id=$0 + id=${id##*_} + +# Prüfen ob die Werte-Datei existiert, wenn ja einlesen sonst Abbruch +# Check if the values ??file exists, if yes read in otherwise abort + if [ -f $logfile ]; then + werte=$(cat $logfile) + else + echo Die Datei $logfile wurde nicht gefunden! Abbruch! >&2 + exit 1 + fi + + +# Standard Config Section Begin ## + if [ "$1" = "autoconf" ]; then + echo yes + exit 0 + fi + + if [ "$1" = "config" ]; then + +# Standard Konfiguration +# Default configuration + echo graph_category DSL + echo graph_args --base 1000 -l 100 + #echo graph_printf %7.3lf%S M + echo graph_info Datenstatistik aus der FRITZ!Box 7490 + +# Wildcard-abhängige Konfiguration überschreibt den obigen Standard +# Wildcard dependent configuration overwrites the above standards + case $id in + LLOSS) + Echo graph_title Leitungsdämpfung + Echo graph_vlabel Dämpfung in db + echo u.label upload + echo d.label download + ;; + DRATE) + Echo graph_title Übertragungsgeschwindigkeit + echo graph_vlabel Datenrate in kbit/s + echo u.label upload + echo d.label download + ;; + SNR) + Echo graph_title Störabstand + echo graph_vlabel Abstand in db + echo u.label upload + echo d.label download + ;; + DATAV) + Echo graph_title tägliches Daten-Volumen + echo graph_vlabel Transfer in MB + echo u.label upload + echo d.label download + echo g.label gesamt + ;; + ES) + echo graph_title Sekunden mit Fehlern \(ES\) + echo graph_vlabel Sekunden + echo u.label upload + echo d.label download + ;; + SES) + echo graph_title Sekunden mit vielen Fehlern \(SES\) + echo graph_vlabel Sekunden + echo u.label upload + echo d.label download + ;; + CRC01) + Echo graph_title Nicht korrigierbare Fehler \(CRC\) + echo graph_vlabel Anzahl + echo u.label upload + echo d.label download + ;; + CRC15) + Echo graph_title Nicht korrigierbare Fehler in 15 Min. \(CRC\) + echo graph_vlabel Anzahl + echo u.label upload + echo d.label download + ;; + VERB) + Echo graph_title Anzahl der täglichen Wiederverbindung + echo graph_vlabel Anzahl + echo u.label upload + echo d.label download + ;; + UPT) + ;; + *) + echo " ##############################################" >&2 + echo " # Felerhafter Programmaufruf, zulässig sind: #" >&2 + echo " # - fritzbox7490_DRATE #" >&2 + echo " # - fritzbox7490_LLOSS #" >&2 + echo " # - fritzbox7490_SNR #" >&2 + echo " # - fritzbox7490_DATAV #" >&2 + echo " # - fritzbox7490_CRC01 #" >&2 + echo " # - fritzbox7490_CRC15 #" >&2 + echo " # - fritzbox7490_ES #" >&2 + echo " # - fritzbox7490_SES #" >&2 + echo " # - fritzbox7490_VERB #" >&2 +# echo " # - fritzbox7490_UPT #" >&2 + echo " ##############################################" >&2 + exit 2 + ;; + esac + exit 0 + fi +# Standard Config Section End #### + +# Wildcard-abhängige Datenauswertung +# Wildcard-dependent data evaluation + case $id in + LLOSS) + u_value=$(echo "${werte}" | awk 'match($0,/pfung OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/mpfung IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value + ;; + DRATE) + u_value=$(echo "${werte}" | awk 'match($0,/atenrate OUT:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo u.value `echo "$u_value * 1024" | bc` + d_value=$(echo "${werte}" | awk 'match($0,/Datenrate IN:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo d.value `echo "$d_value * 1024" | bc` + ;; + SNR) + u_value=$(echo "${werte}" | awk 'match($0,/bstandsmarge OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/abstandsmarge IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value + ;; + DATAV) + u_value=$(echo "${werte}" | awk 'match($0,/volumen \(upload\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/volumen \(download\):.* ([0-9]+) MB/,arr){print arr[1]};'); echo d.value $d_value + g_value=$(echo "${werte}" | awk 'match($0,/volumen \(gesamt\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo g.value $g_value + ;; + CRC01) + u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) IN: .* ([0-9,\.]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) OUT:.* ([0-9,\.]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + CRC15) + u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + ES) + u_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + SES) + u_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value + d_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value + ;; + *) + u_value=0 + d_value=0 + ;; + esac From 3f3d7290ba2e7121d9c66f4e846ad76285a5ff51 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 15:52:51 +0100 Subject: [PATCH 09/31] Der Vorbereitungsjob - The prerunning battch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Der Batch-Job fritzbox7490.sh wird durch cron gestartet und liest alle relevanten Daten aus dem AVM-Router aus. - Die Daten werden aufbereitet und in der Datei /var/log/fritzbox7490.log gespeichert. - Das Plugin bereitet die Daten für Munin auf. -------------------------------------------------------------------------------------------------------------------------- - The batch job fritzbox7490.sh is started by cron and reads all relevant data from the AVM router. - The data are processed and stored in the /var/log/fritzbox7490.log file. - The plugin prepares the data for Munin. --- plugins/fritz-box7490/de/fritzbox7490.sh | 204 +++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 plugins/fritz-box7490/de/fritzbox7490.sh diff --git a/plugins/fritz-box7490/de/fritzbox7490.sh b/plugins/fritz-box7490/de/fritzbox7490.sh new file mode 100644 index 00000000..f8f86a89 --- /dev/null +++ b/plugins/fritz-box7490/de/fritzbox7490.sh @@ -0,0 +1,204 @@ +#!/bin/bash +# FritzBox.sh + +### Quelle des Codekerns - Target of die skript core ############################ +# https://github.com/Tscherno/Fritzbox.sh # +# compatible with Fritz.box Firmware 6.50 and higher, Horst Schmid, 2016-01-05 # +# /usr/local/addons/cuxd/user/FritzBox.sh # +################################################################################# + +##################################################################################################################################################### +# Der Vorbereitungs-Job muss per cron gestartet werden - Thie prerunning job must be started by cron # +# /etc/cron.d/fritzbox # +# 3,8,13,18,23,28,33,38,43,48,53,58 * * * * root //fritzbox7490.sh -p (-u >login user if required>] #okay # +# # +# Jo Hartmann V17.0126 # +##################################################################################################################################################### + +# Deklaration der Dateipfade +# Declaration of file pathes + CPWMD5="/etc/munin/plugins/pre2run/cpwmd5" + FRITZLOGIN="/login_sid.lua" + FRITZWEBCM="/cgi-bin/webcm" + FRITZHOME="/home/home.lua" + CURLFILE="/var/tmp/FritzBoxCurl.txt" + LOGFILE="/var/log/fritzbox7490.log" + PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# Wie werden die Webseiten aufgerufen +# How to call web pages + WEBCLIENT="curl -s" + +# Deklaration sonstiger Variablen +# Declaration of other variables + FritzBoxURL="192.168.0.111" + Username="" + Passwd="" + Debug=false + +# Verarbeitung der Aufruf-Parameter +# Processing the script parameters + while getopts u:p:d OPT; do + case $OPT in + u) + Username=$OPTARG + ;; + p) + Passwd=$OPTARG + ;; + d) + Debug=true + LOGFILE="/dev/stdout" + ;; + + esac + done + +# Anmelde-Routine, Quelle: https://github.com/Tscherno/Fritzbox.sh, Horst Schmid, 2016-01-05 +# Login routine, source: https://github.com/Tscherno/Fritzbox.sh, Horst Schmid, 2016-01-05 + LOGIN(){ + # We need an SessionInfoChallenge SID from the FB. Combined with the PW an + # MD5-Checksum needs to be calculated and send back. + # 1. Are we already logged in? + htmlLoginPage=$($WEBCLIENT "$FritzBoxURL$FRITZLOGIN") + SessionInfoChallenge=$(echo "$htmlLoginPage" | sed -n '/.*\([^<]*\)<.*/s//\1/p') + SessionInfoSID=$(echo "$htmlLoginPage" | sed -n '/.*\([^<]*\)<.*/s//\1/p') + if $Debug; then echo "****************** LOGIN: Challenge $SessionInfoChallenge" >> $LOGFILE; fi + if [ "$SessionInfoSID" = "0000000000000000" ]; then + if $Debug; then echo "****************** LOGIN: Keine gueltige SID - login aufbauen" >> $LOGFILE; fi + CPSTR="$SessionInfoChallenge-$Passwd" # Combine Challenge and Passwd + if $Debug; then echo "****************** LOGIN: CPSTR: $CPSTR -> MD5" >> $LOGFILE; fi + MD5=`$CPWMD5 $CPSTR` # here the MD5 checksum is calculated + RESPONSE="$SessionInfoChallenge-$MD5" + if $Debug; then echo "****************** LOGIN: login senden und SID herausfischen, MD5: $MD5" >> $LOGFILE; fi + GETDATA="?username=$Username&response=$RESPONSE" + if $Debug; then echo "****************** LOGIN: $GETDATA" >> $LOGFILE; fi + SID=$($WEBCLIENT "$FritzBoxURL$FRITZLOGIN$GETDATA" | sed -n '/.*\([^<]*\)<.*/s//\1/p') + if $Debug; then echo "****************** Logged in with SID=$SID" >> $LOGFILE; fi + else + SID=$SessionInfoSID + if $Debug; then echo "****************** LOGIN: Bereits erfolgreiche SID: $SID" >> $LOGFILE; fi + fi + if [ "$SID" = "0000000000000000" ]; then + if $Debug; then echo "****************** LOGIN: ERROR - Konnte keine gueltige SID ermitteln" >> $LOGFILE; fi + fi + } + +# Definition der Linienlänge für die Ausgabe (MEZ oder MESZ?) +# Definition of line length for output (CET or CEST?) + MESZ=$(echo $(date +"%Z") | awk '{print length($0)-3}') + line="#####################################################" + if [ "$MESZ" = "1" ]; then line="${line}#";fi + +# Die alte Log-Datei für Differenzbetrachtungen sichern +# Save the old log file for differential views + if ! $Debug; then mv ${LOGFILE} ${LOGFILE}.1; fi + +# Startmeldung zur Ausgabe +# Start message for output + echo $line > $LOGFILE + echo "Startzeit der Auswertung: $(date +"%d.%m.%Y %X %Z") #" >> $LOGFILE + echo $line >> $LOGFILE + echo >> $LOGFILE + +# Abrage der Hard-/Software-Eigenschaften, funktioniert ohne Anmeldung! +# Query the hardware / software properties, works without login! + jBoxInfo=$($WEBCLIENT "$FritzBoxURL/jason_boxinfo.xml") + fbName=$(echo "$jBoxInfo" | grep 'j:Name' | sed -n 's,.*>\(.*\)\(.*\)\(.*\)\(.*\)\(.*\) /var/log/fritzbox7490.txt + +# Verarbeitung der Daten der Seite Online-Monitor +# Processing the data of the Online Monitor page + _AKT_IP=$(echo "$_PAGE_INET_STAT" | sed -n 's/.*
IP-Adresse: \(.*\)<\/span>.*/\1/p') + _VERBAB=$(echo "$_PAGE_INET_STAT" | sed -n 's/.*verbunden seit \(.*\)<\/span>,.*/\1/p') + +# Verarbeitung der Daten der Seite Online-Zähler +# Processing the data of the page Online counter + _ONLINE_Zeit=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"time">([0-9,:]+)<\/td>.*Gestern/,arr){print arr[1]};') + _VOLUMEN_T=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"vol">([0-9]+)<\/td>.*"vol">.*"vol">.*Gestern/,arr){print arr[1]};') + _VOLUMEN_U=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"vol">.*"vol">([0-9]+)<\/td>.*"vol">.*Gestern/,arr){print arr[1]};') + _VOLUMEN_D=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"vol">.*"vol">.*"vol">([0-9]+)<\/td>.*Gestern/,arr){print arr[1]};') + _ANZ_VERB=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"conn">([0-9,:]+)<\/td>.*Gestern/,arr){print arr[1]};') + +# Verarbeitung der Daten der Seite DSL-Informationen --> DSL +# Processing the data of the page DSL information -> DSL + _DATARATE_IN=$(echo "${_PAGE_DSL_STATS}" | awk 'match($0,/Aktuelle Datenrate.*"c3">([0-9]+)<\/td>.*Nahtlose Ratenadaption/,arr){print arr[1]};') + _DATARATE_OUT=$(echo "${_PAGE_DSL_STATS}" | awk 'match($0,/Aktuelle Datenrate.*"c4">([0-9]+)<\/td>.*Nahtlose Ratenadaption/,arr){print arr[1]};') + + _LATENZ_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Latenz.*"c3">([0-9]+) ms<\/td>/,arr){print arr[1]};') + _LATENZ_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Latenz.*"c4">([0-9]+) ms<\/td>/,arr){print arr[1]};') + + _NOISEMARGIN_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/rabstandsmarge.*"c3">([0-9]+)<\/td>.*gertausch/,arr){print arr[1]};') + _NOISEMARGIN_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/rabstandsmarge.*"c4">([0-9]+)<\/td>.*gertausch/,arr){print arr[1]};') + + _DSLLINELOSS_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Leitungsd.*"c3">([0-9]+)<\/td>.*Leistungsreduzierung/,arr){print arr[1]};') + _DSLLINELOSS_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Leitungsd.*"c4">([0-9]+)<\/td>.*Leistungsreduzierung/,arr){print arr[1]};') + + _DSLESERROR_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c2">([0-9]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') + _DSLESERROR_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c2">([0-9]+)<\/td>.*table>/,arr){print arr[1]};') + + _DSLSESERROR_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c3">([0-9]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') + _DSLSESERROR_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c3">([0-9]+)<\/td>.*table>/,arr){print arr[1]};') + + _DSLCRCERROR01_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c4">([0-9,.]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') + _DSLCRCERROR01_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c4">([0-9,.]+)<\/td>.*table>/,arr){print arr[1]};') + + _DSLCRCERROR15_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c5">([0-9]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') + _DSLCRCERROR15_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c5">([0-9]+)<\/td>.*table>/,arr){print arr[1]};') + +#Resyncs der letzten 24h auslesen + +#_RESYNCS=$(echo "$_PAGE_STATS_GRAPH" | awk 'BEGIN {summe = 0}; match($0, /\[\"sar:status\/StatResync\"\] = \"(.*)\"/, arr){for(i = 1; i <= split(arr[1],splitted,",");i++){summe += int(splitted[i])}};END {print summe};') + +# Schreiben der Ausgabe Datei +# Write the output file + echo "AVM Typenbezeichnung: $fbName" >> $LOGFILE + echo "Firmeware-Version: $fbVersion1" >> $LOGFILE + echo "FritzOS: $fbVersion2" >> $LOGFILE + echo "Hardware-Version: $fbHardw" >> $LOGFILE + echo "Reversion: $fbRev" >> $LOGFILE + echo "Seriennummer: $fbSN" >> $LOGFILE + + + echo "Aktuelle IP-Adresse: $_AKT_IP" >> $LOGFILE + echo "Verbunden seit: $_VERBAB" >> $LOGFILE + + echo "Datenrate IN: $_DATARATE_IN kbit/s" >> $LOGFILE + echo "Datenrate OUT: $_DATARATE_OUT kbit/s" >> $LOGFILE + echo "Latenz Empfangsrichtung: $_LATENZ_IN ms" >> $LOGFILE + echo "Latenz Senderichtung: $_LATENZ_OUT ms" >> $LOGFILE + echo "Störabstandsmarge IN: $_NOISEMARGIN_IN db" >> $LOGFILE + echo "Störabstandsmarge OUT: $_NOISEMARGIN_OUT db" >> $LOGFILE + echo "Leitungsdämpfung IN: $_DSLLINELOSS_IN db" >> $LOGFILE + echo "Leitungsdämpfung OUT: $_DSLLINELOSS_OUT db" >> $LOGFILE + echo "Sek. m. Fehlern (ES) IN: $_DSLESERROR_IN" >> $LOGFILE + echo "Sek. m. Fehlern (ES) OUT: $_DSLESERROR_OUT" >> $LOGFILE + echo "Sek. m. v. Fehl. (SES) IN: $_DSLSESERROR_IN" >> $LOGFILE + echo "Sek. m. v. Fehl. (SES) OUT: $_DSLSESERROR_OUT" >> $LOGFILE + echo "CRC Fehler (je Min) IN: $_DSLCRCERROR01_IN" >> $LOGFILE + echo "CRC Fehler (je Min) OUT: $_DSLCRCERROR01_OUT" >> $LOGFILE + echo "CRC Fehler (15 Min) IN: $_DSLCRCERROR15_IN" >> $LOGFILE + echo "CRC Fehler (15 Min) OUT: $_DSLCRCERROR15_OUT" >> $LOGFILE + + echo "Stunden Online: $_ONLINE_Zeit" >> $LOGFILE + echo "Datenvolumen (gesamt): $_VOLUMEN_T MB" >> $LOGFILE + echo "Datenvolumen (upload): $_VOLUMEN_U MB" >> $LOGFILE + echo "Datenvolumen (download): $_VOLUMEN_D MB" >> $LOGFILE + echo "Anz. der Verbindungen: $_ANZ_VERB" >> $LOGFILE + echo >> $LOGFILE + echo $line >> $LOGFILE + echo "Stoppzeit der Auswertung: $(date +"%d.%m.%Y %X %Z") #" >> $LOGFILE + echo $line >> $LOGFILE + #echo ${_PAGE_INET_COUN} From a0d6851cfa0c5ebaf6be042dbc5920f0b2d3582c Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 16:07:53 +0100 Subject: [PATCH 10/31] Lies mich Datei! --- plugins/fritz-box7490/de/read.me | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 plugins/fritz-box7490/de/read.me diff --git a/plugins/fritz-box7490/de/read.me b/plugins/fritz-box7490/de/read.me new file mode 100644 index 00000000..7ccad11c --- /dev/null +++ b/plugins/fritz-box7490/de/read.me @@ -0,0 +1,2 @@ +Die Versionen für die deutschsprachige Benutzeroberfläche. +The versions for the German-language user interface. From a19306b829e113b56ca91622329d018fb4502cdf Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 16:10:44 +0100 Subject: [PATCH 11/31] Read me file --- plugins/fritz-box7490/en/read.me | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 plugins/fritz-box7490/en/read.me diff --git a/plugins/fritz-box7490/en/read.me b/plugins/fritz-box7490/en/read.me new file mode 100644 index 00000000..cb7f4191 --- /dev/null +++ b/plugins/fritz-box7490/en/read.me @@ -0,0 +1,2 @@ +Die Versionen für die englischsprachige Benutzeroberfläche. +The versions for the English-language user interface. From 88f93e8111a1e0ed18de571ba520b26c2e605548 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 16:15:55 +0100 Subject: [PATCH 12/31] Beschreibung - Description Allgemeine Informationen zu dem Plugin. General information about the plugin . --- plugins/fritz-box7490/read.me | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/fritz-box7490/read.me b/plugins/fritz-box7490/read.me index 8b137891..8ee9aa4d 100644 --- a/plugins/fritz-box7490/read.me +++ b/plugins/fritz-box7490/read.me @@ -1 +1,2 @@ - +Deutsche Version (English version below) +English version (deutsche Version oberhalb) From 58b4b4fe9b46562cce5c9e187d866172f6fc57ef Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Thu, 26 Jan 2017 16:17:44 +0100 Subject: [PATCH 13/31] Update read.me From 542150815ba9590b469aac069be43fc2443fc092 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sun, 5 Feb 2017 19:50:04 +0100 Subject: [PATCH 14/31] Create dummy --- plugins/disk/example-graphs/dummy | 1 + 1 file changed, 1 insertion(+) create mode 100644 plugins/disk/example-graphs/dummy diff --git a/plugins/disk/example-graphs/dummy b/plugins/disk/example-graphs/dummy new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/plugins/disk/example-graphs/dummy @@ -0,0 +1 @@ + From 952a3eaee896622782805588fe84f6a7446e2f02 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sun, 5 Feb 2017 19:54:39 +0100 Subject: [PATCH 15/31] Graph example An example for a daily graph of device sdb1 --- .../example-graphs/quota2percent_sdb1-day.png | Bin 0 -> 79808 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/disk/example-graphs/quota2percent_sdb1-day.png diff --git a/plugins/disk/example-graphs/quota2percent_sdb1-day.png b/plugins/disk/example-graphs/quota2percent_sdb1-day.png new file mode 100644 index 0000000000000000000000000000000000000000..d1ff2c8d08bbe7659f6e8edb933e98fd15ac1df5 GIT binary patch literal 79808 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 K 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 literal 0 HcmV?d00001 From dab96a619fcfce86f955898fb781fcb12f0c0cdf Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sun, 5 Feb 2017 19:55:41 +0100 Subject: [PATCH 16/31] Delete dummy --- plugins/disk/example-graphs/dummy | 1 - 1 file changed, 1 deletion(-) delete mode 100644 plugins/disk/example-graphs/dummy diff --git a/plugins/disk/example-graphs/dummy b/plugins/disk/example-graphs/dummy deleted file mode 100644 index 8b137891..00000000 --- a/plugins/disk/example-graphs/dummy +++ /dev/null @@ -1 +0,0 @@ - From f21a2fe4325161a9214a478961cb27be7314d910 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Wed, 8 Feb 2017 15:23:44 +0100 Subject: [PATCH 17/31] Update quota2percent_ add POD documentation add env.language add example graph for Munin Plugin Gallery remove German comments --- plugins/disk/quota2percent_ | 208 +++++++++++++++++++++++------------- 1 file changed, 135 insertions(+), 73 deletions(-) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index 37879970..d372fc41 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -1,45 +1,116 @@ #!/bin/bash +# -*- sh -*- +: <<=cut -# Das Plugin zeigt die Festplattenbelegung in Prozent des Quota-Hard-Limits. -# Munin plugin to show the disk usage in percent of the quota hard limit. -# The base frame is copied from the proftp plugin +=head1 NAME -########################################################################################## -# Folgende Eintraege in der Datei /etc/munin/plugin-conf.d/munin-node nicht vergessen ! # -# Don't forget to add following lines to the file /etc/munin/plugin-conf.d/munin-node # -# [quota2percent_*] # -# user root # -# # -# Weiterhin sind folgende Environment-Variablen erlaubt: # -# Following environment variables are allowed: # -# env.warning [value] # -# env.critical [value] # -# V17.0124 Jo Hartmann # -########################################################################################## +quota2percent - Plugin to show disk usage in percent of quota hard limit. -# Spachauswahl -# Language selection - Language="de" +=head1 APPLICABLE SYSTEMS +All systems with "bash", "quota", "repquota" and "munin" + +=head1 CONFIGURATION + +The following is the default configuration + + [quota2percent_*] + user root + +You could define two alert levels and the graph language + + [quota2percent_*] + env.warning [value] (default: 90) + env.critical [value] (default: 95) + env.language [en|de|es] (default: en) + +=head1 DESCRIPTION + +Wild card Plugin for monitoring the utilization of devices with quota rules. +A graph is drawn for each user, which shows the usage as a percentage of his hard limit. System accounts (UID <1000) are suppressed. +In addition, a graph is displayed which indicates the ratio device size to device coverage. +The script repqutoa, usually part of the package quota, is needed. +The plugin itself can be stored in any directory. For example, the device sdb1 shell be monitored, a symbolic link must be created +in the /etc/munin/plugins/ directory as follows: + +=over + +I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> + +=back + +=head1 MAGIC MARKERS + + #%# family=auto + #%# capabilities=autoconf + +=head1 VERSION + +17.0131 + +=head1 HISTORY + +V17.0131 + + add POD documentation + add env.language + add example graph for Munin Plugin Gallery + remove German comments + +V17.0124 + + first version, not munin rules conform + +=head1 AUTHOR + +Jo Hartmann + +=head1 LICENSE + +GPLv2 (L) + +=cut + +################################################### +# Preparation section # +################################################### + +# Load munin's shell libary + . "$MUNIN_LIBDIR/plugins/plugin.sh" + +# if any fetch from munin-node file + Warning=${warning:-90} + Critical=${critical:-95} + Language=${language:-en} + +# Ensure that the 'root' path is valid + PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# Checking if repquota installed and on the path + repquota -V &> /dev/null + if ! repquota -V &> /dev/null ; then + echo "The script 'repquota' is not installed or on the path" + # Send the exit code FATAL ERROR happens + exit 127 + fi -# Wildcard-Text erkennen # get tehe wild card text - Id=$0 - Id=${Id##*_} + Id=${0##*_} + +################################################### +# Data reading sections # +################################################### -# Einlesen der Quoten für das entsprechende Laufwerk mit repquota # Reading the quotes for the selected device, using repquota - readarray Quotas < <( repquota /dev/$Id | grep " -- " ) - readarray Totals < <( df /dev/$Id ) + readarray Quotas < <( repquota "/dev/$Id" | grep " -- " ) + readarray Totals < <( df "/dev/$Id" ) -# Anzahl der Nutzer ermitteln # Get the count of Users Users=${#Quotas[@]} ################################################### -# Beginn der Standard-Konfigurationsbereiches # -# Standard Config Section Begin # +# Munin Configuration Section # ################################################### if [ "$1" = "autoconf" ]; then @@ -47,97 +118,88 @@ exit 0 fi -. $MUNIN_LIBDIR/plugins/plugin.sh if [ "$1" = "config" ]; then - # Anpassung der Texte in der Grafik # Localisation of the graphic texts case $Language in de) - echo graph_title Quota-Hard-Limit von $Id - echo graph_vlabel Nutzung in % Hardlimit + echo graph_title "Quota-Hard-Limit von $Id" + echo graph_vlabel "Nutzung in % Hardlimit" echo graph_info "Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >=1000) in Prozent des Hardlimits." Total_txt="Su. aller Nutzer" Total_info="Inklusive Systemnutzer (UID < 1000)" ;; es) - echo graph_title Cuota de límite absoluto de $ Id - echo graph_vlabel el % de uso del límite duro + echo graph_title "Cuota de límite absoluto de $Id" + echo graph_vlabel "el % de uso del límite duro" echo graph_info "El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID> = 1000) como porcentaje de límites duros." Total_txt="Suma de todos los usuarios " Total_info="La inclusión de usuario del sistema (UID <1000) " ;; *) - echo graph_title quota hard limit of %Id - echo graph_vlabel Usage in % - Total_txt="all users" + echo graph_title "quota hard limit of $Id" + echo graph_vlabel "Usage in %" echo graph_info "The graphic shows the allocation of the quota-regulated storage space for all regular users (UID> = 1000) as a percentage of the hard limit ." + Total_txt="all users" Total_info="system users (UID < 1000) included" ;; esac - # Standard Konfiguration # Defaults configuration echo graph_category disk echo graph_args --lower-limit 0 --upper-limit 100 echo graph_printf %5.2lf %% echo graph_scale no - # Ggf. Werte aus der Datei munin-node uebernehmen - # if any fetch from munin-node file - Warning=${warning:-90} - Critical=${critical:-95} - - # Die Quota-Nutzer und deren Real-Namen ermitteln, das Root-Problem beheben, die Kondfigurationsdaten ausgeben # For each quota user fetch his real name, solve the root problem, Output the configuration data - for((i=0; i<$Users; i++));do + for((i=0; i<"$Users"; i++));do Quota=( ${Quotas[$i]} ) - User=${Quota[0]} - Passwd=$(cat /etc/passwd | grep $User) + UserName=${Quota[0]} + #Passwd=$(cat /etc/passwd | grep $UserName) + Passwd=$(grep "$UserName" /etc/passwd) OLDIFS=$IFS IFS=':' Infos=($Passwd) IFS=$OLDIFS - Name=${Infos[4]} - Name=${Name%%,*} + UserInfo=${Infos[4]} + UserInfo=${UserInfo%%,*} - [ $User == "root" ] && { User="__root"; Name="__root";} - [ ! -n "$Name" ] && Name=$User - [ $(id -u ${Quota[0]}) -lt 1000 ] && echo $User.graph no - echo $User.label $Name - echo $User.warning $warning - echo $User.critical $critical + UserName="$(clean_fieldname "$UserName")" + UserInfo="$(clean_fieldname "$UserInfo")" + + [ ! -n "$UserInfo" ] && UserInfo="$UserName" + [ "$(id -u "${Quota[0]}")" -lt 1000 ] && echo "$UserName.graph no" + echo "$UserName.label $UserInfo" + echo "$UserName.warning $Warning" + echo "$UserName.critical $Critical" done - # Die Summenzeile konfigurieren - # configure the total line - echo total.label $Total_txt - echo total.warning $Warning - echo total.critical $Critical - echo total.info $Total_info - exit 0 + # configure the total line and send exit code NO ERROR happens + echo total.label "$Total_txt" + echo total.warning "$Warning" + echo total.critical "$Critical" + echo total.info "$Total_info" + exit 0 fi ################################################### -# Ende der Standard-Konfigurationsbereiches # -# Standard Config Section End # +# Munin value section # ################################################### -# Die Werte (Belegung und Hardlimit) je Nutzer ermitteln, das Root-Problem umgehen, die Prozente berechnen # fetch the needed values (used and hard limit) for each user, work around the root problem, calculate the percent value - for((i=0; i<$Users; i++));do + for((i=0; i<"$Users"; i++));do Quota=( ${Quotas[$i]} ) - User=${Quota[0]} - [ $User == "root" ] && User="__root" - Prozent=`echo "scale=2 ; ${Quota[2]}*100/${Quota[4]}" | bc` - - echo $User.value $Prozent + UserName="$(clean_fieldname "${Quota[0]}")" + echo "${Quota[2]} ${Quota[4]} $UserName.value" | awk '{printf "%s %.2f\n", $3 ,$1*100/$2}' done -# Die Summenwerte # the value for the total line Total=( ${Totals[1]} ) - Summe=`echo "scale=2;${Total[2]}*100/${Total[1]}" | bc` - echo total.value $Summe + echo "${Total[2]} ${Total[1]} total.value" | awk '{printf "%s %.2f\n", $3, $1*100/$2}' +# send the exit code NO ERROR happens exit 0 + +################################################### +# Script end # +################################################### From 5efef7ca2e7c8c6c4178ab00bd6ffd946a3bb9d2 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Fri, 10 Feb 2017 18:32:48 +0100 Subject: [PATCH 18/31] Update quota2percent_ to V17.0210 add env.humanid fix same nitpicking details --- plugins/disk/quota2percent_ | 48 ++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index d372fc41..1c27e6d2 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -9,6 +9,7 @@ quota2percent - Plugin to show disk usage in percent of quota hard limit. =head1 APPLICABLE SYSTEMS All systems with "bash", "quota", "repquota" and "munin" +Systems with multiple users and individual storage space limitations administered via 'quota' =head1 CONFIGURATION @@ -22,7 +23,8 @@ You could define two alert levels and the graph language [quota2percent_*] env.warning [value] (default: 90) env.critical [value] (default: 95) - env.language [en|de|es] (default: en) + env.language [en|de|es] (default: en) + env.humanuid [value] (default: 1000, only need if there is an other value define for UID_MIN in /etc/login.defs) =head1 DESCRIPTION @@ -46,10 +48,15 @@ I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> =head1 VERSION -17.0131 +17.0210 =head1 HISTORY +17.0210 + + add env.humanid + fix same nitpicking details + V17.0131 add POD documentation @@ -71,6 +78,20 @@ GPLv2 (L) =cut +################################################### +# Autoconf section # +################################################### + + if [ "$1" = "autoconf" ]; then + if repquota -V &> /dev/null ; then + echo yes + exit 0 + else + echo "no ('requota' executable is missing)" + exit 127 + fi + fi + ################################################### # Preparation section # ################################################### @@ -82,14 +103,14 @@ GPLv2 (L) Warning=${warning:-90} Critical=${critical:-95} Language=${language:-en} + Min_UID=${humanuid:-1000} # Ensure that the 'root' path is valid PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # Checking if repquota installed and on the path - repquota -V &> /dev/null if ! repquota -V &> /dev/null ; then - echo "The script 'repquota' is not installed or on the path" + echo "The script 'repquota' is not installed or on the path" >&2 # Send the exit code FATAL ERROR happens exit 127 fi @@ -113,12 +134,6 @@ GPLv2 (L) # Munin Configuration Section # ################################################### - if [ "$1" = "autoconf" ]; then - echo yes - exit 0 - fi - - if [ "$1" = "config" ]; then # Localisation of the graphic texts @@ -128,21 +143,21 @@ GPLv2 (L) echo graph_vlabel "Nutzung in % Hardlimit" echo graph_info "Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >=1000) in Prozent des Hardlimits." Total_txt="Su. aller Nutzer" - Total_info="Inklusive Systemnutzer (UID < 1000)" + Total_info="Inklusive Systemnutzer (UID < $Min_UID)" ;; es) echo graph_title "Cuota de límite absoluto de $Id" echo graph_vlabel "el % de uso del límite duro" echo graph_info "El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID> = 1000) como porcentaje de límites duros." Total_txt="Suma de todos los usuarios " - Total_info="La inclusión de usuario del sistema (UID <1000) " + Total_info="La inclusión de usuario del sistema (UID < $Min_UID) " ;; *) echo graph_title "quota hard limit of $Id" echo graph_vlabel "Usage in %" echo graph_info "The graphic shows the allocation of the quota-regulated storage space for all regular users (UID> = 1000) as a percentage of the hard limit ." Total_txt="all users" - Total_info="system users (UID < 1000) included" + Total_info="system users (UID < $Min_UID) included" ;; esac @@ -156,7 +171,6 @@ GPLv2 (L) for((i=0; i<"$Users"; i++));do Quota=( ${Quotas[$i]} ) UserName=${Quota[0]} - #Passwd=$(cat /etc/passwd | grep $UserName) Passwd=$(grep "$UserName" /etc/passwd) OLDIFS=$IFS IFS=':' Infos=($Passwd) @@ -168,7 +182,7 @@ GPLv2 (L) UserInfo="$(clean_fieldname "$UserInfo")" [ ! -n "$UserInfo" ] && UserInfo="$UserName" - [ "$(id -u "${Quota[0]}")" -lt 1000 ] && echo "$UserName.graph no" + [ "$(id -u "${Quota[0]}")" -lt $Min_UID ] && echo "$UserName.graph no" echo "$UserName.label $UserInfo" echo "$UserName.warning $Warning" echo "$UserName.critical $Critical" @@ -190,12 +204,12 @@ GPLv2 (L) for((i=0; i<"$Users"; i++));do Quota=( ${Quotas[$i]} ) UserName="$(clean_fieldname "${Quota[0]}")" - echo "${Quota[2]} ${Quota[4]} $UserName.value" | awk '{printf "%s %.2f\n", $3 ,$1*100/$2}' + echo "${Quota[2]} ${Quota[4]} $UserName.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' done # the value for the total line Total=( ${Totals[1]} ) - echo "${Total[2]} ${Total[1]} total.value" | awk '{printf "%s %.2f\n", $3, $1*100/$2}' + echo "${Total[2]} ${Total[1]} total.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' # send the exit code NO ERROR happens exit 0 From 2caf1a978dc84f2f6e8a6f380e74ad9b2806bcfd Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sat, 11 Feb 2017 11:16:00 +0100 Subject: [PATCH 19/31] Delete quota2percent_ --- plugins/disk/quota2percent_ | 219 ------------------------------------ 1 file changed, 219 deletions(-) delete mode 100644 plugins/disk/quota2percent_ diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ deleted file mode 100644 index 1c27e6d2..00000000 --- a/plugins/disk/quota2percent_ +++ /dev/null @@ -1,219 +0,0 @@ -#!/bin/bash -# -*- sh -*- -: <<=cut - -=head1 NAME - -quota2percent - Plugin to show disk usage in percent of quota hard limit. - -=head1 APPLICABLE SYSTEMS - -All systems with "bash", "quota", "repquota" and "munin" -Systems with multiple users and individual storage space limitations administered via 'quota' - -=head1 CONFIGURATION - -The following is the default configuration - - [quota2percent_*] - user root - -You could define two alert levels and the graph language - - [quota2percent_*] - env.warning [value] (default: 90) - env.critical [value] (default: 95) - env.language [en|de|es] (default: en) - env.humanuid [value] (default: 1000, only need if there is an other value define for UID_MIN in /etc/login.defs) - -=head1 DESCRIPTION - -Wild card Plugin for monitoring the utilization of devices with quota rules. -A graph is drawn for each user, which shows the usage as a percentage of his hard limit. System accounts (UID <1000) are suppressed. -In addition, a graph is displayed which indicates the ratio device size to device coverage. -The script repqutoa, usually part of the package quota, is needed. -The plugin itself can be stored in any directory. For example, the device sdb1 shell be monitored, a symbolic link must be created -in the /etc/munin/plugins/ directory as follows: - -=over - -I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> - -=back - -=head1 MAGIC MARKERS - - #%# family=auto - #%# capabilities=autoconf - -=head1 VERSION - -17.0210 - -=head1 HISTORY - -17.0210 - - add env.humanid - fix same nitpicking details - -V17.0131 - - add POD documentation - add env.language - add example graph for Munin Plugin Gallery - remove German comments - -V17.0124 - - first version, not munin rules conform - -=head1 AUTHOR - -Jo Hartmann - -=head1 LICENSE - -GPLv2 (L) - -=cut - -################################################### -# Autoconf section # -################################################### - - if [ "$1" = "autoconf" ]; then - if repquota -V &> /dev/null ; then - echo yes - exit 0 - else - echo "no ('requota' executable is missing)" - exit 127 - fi - fi - -################################################### -# Preparation section # -################################################### - -# Load munin's shell libary - . "$MUNIN_LIBDIR/plugins/plugin.sh" - -# if any fetch from munin-node file - Warning=${warning:-90} - Critical=${critical:-95} - Language=${language:-en} - Min_UID=${humanuid:-1000} - -# Ensure that the 'root' path is valid - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -# Checking if repquota installed and on the path - if ! repquota -V &> /dev/null ; then - echo "The script 'repquota' is not installed or on the path" >&2 - # Send the exit code FATAL ERROR happens - exit 127 - fi - -# get tehe wild card text - Id=${0##*_} - -################################################### -# Data reading sections # -################################################### - -# Reading the quotes for the selected device, using repquota - readarray Quotas < <( repquota "/dev/$Id" | grep " -- " ) - readarray Totals < <( df "/dev/$Id" ) - -# Get the count of Users - Users=${#Quotas[@]} - - -################################################### -# Munin Configuration Section # -################################################### - - if [ "$1" = "config" ]; then - - # Localisation of the graphic texts - case $Language in - de) - echo graph_title "Quota-Hard-Limit von $Id" - echo graph_vlabel "Nutzung in % Hardlimit" - echo graph_info "Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >=1000) in Prozent des Hardlimits." - Total_txt="Su. aller Nutzer" - Total_info="Inklusive Systemnutzer (UID < $Min_UID)" - ;; - es) - echo graph_title "Cuota de límite absoluto de $Id" - echo graph_vlabel "el % de uso del límite duro" - echo graph_info "El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID> = 1000) como porcentaje de límites duros." - Total_txt="Suma de todos los usuarios " - Total_info="La inclusión de usuario del sistema (UID < $Min_UID) " - ;; - *) - echo graph_title "quota hard limit of $Id" - echo graph_vlabel "Usage in %" - echo graph_info "The graphic shows the allocation of the quota-regulated storage space for all regular users (UID> = 1000) as a percentage of the hard limit ." - Total_txt="all users" - Total_info="system users (UID < $Min_UID) included" - ;; - esac - - # Defaults configuration - echo graph_category disk - echo graph_args --lower-limit 0 --upper-limit 100 - echo graph_printf %5.2lf %% - echo graph_scale no - - # For each quota user fetch his real name, solve the root problem, Output the configuration data - for((i=0; i<"$Users"; i++));do - Quota=( ${Quotas[$i]} ) - UserName=${Quota[0]} - Passwd=$(grep "$UserName" /etc/passwd) - OLDIFS=$IFS - IFS=':' Infos=($Passwd) - IFS=$OLDIFS - UserInfo=${Infos[4]} - UserInfo=${UserInfo%%,*} - - UserName="$(clean_fieldname "$UserName")" - UserInfo="$(clean_fieldname "$UserInfo")" - - [ ! -n "$UserInfo" ] && UserInfo="$UserName" - [ "$(id -u "${Quota[0]}")" -lt $Min_UID ] && echo "$UserName.graph no" - echo "$UserName.label $UserInfo" - echo "$UserName.warning $Warning" - echo "$UserName.critical $Critical" - done - - # configure the total line and send exit code NO ERROR happens - echo total.label "$Total_txt" - echo total.warning "$Warning" - echo total.critical "$Critical" - echo total.info "$Total_info" - exit 0 - fi - -################################################### -# Munin value section # -################################################### - -# fetch the needed values (used and hard limit) for each user, work around the root problem, calculate the percent value - for((i=0; i<"$Users"; i++));do - Quota=( ${Quotas[$i]} ) - UserName="$(clean_fieldname "${Quota[0]}")" - echo "${Quota[2]} ${Quota[4]} $UserName.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' - done - -# the value for the total line - Total=( ${Totals[1]} ) - echo "${Total[2]} ${Total[1]} total.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' - -# send the exit code NO ERROR happens - exit 0 - -################################################### -# Script end # -################################################### From c9dbd8d1bfe4b012fef7f9706e03f816fc78f6b0 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sat, 11 Feb 2017 11:49:13 +0100 Subject: [PATCH 20/31] Update quota2percent_ to V17.0210 add env.humanid add check if device exist add if no limitations administered via 'quota' for the device the total line is shown only fix some nitpicking details add some comments --- plugins/disk/quota2percent_ | 247 ++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 plugins/disk/quota2percent_ diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ new file mode 100644 index 00000000..683a9368 --- /dev/null +++ b/plugins/disk/quota2percent_ @@ -0,0 +1,247 @@ +#!/bin/bash +# -*- sh -*- +: <<=cut + +=head1 NAME + +quota2percent - Plugin to show disk usage in percent of quota hard limit. + +=head1 APPLICABLE SYSTEMS + +All systems with "bash", "quota", "repquota" and "munin" +Systems with multiple users and individual storage space limitations administered via 'quota' + +=head1 CONFIGURATION + +The following is the default configuration + + [quota2percent_*] + user root + +You could define two alert levels and the graph language + + [quota2percent_*] + env.warning [value] (default: 90) + env.critical [value] (default: 95) + env.language [en|de|es] (default: en) + env.humanuid [value] (default: 1000, only need if there is an other value define for UID_MIN in /etc/login.defs) + +=head1 DESCRIPTION + +Wild card Plugin for monitoring the utilization of devices with quota rules. +A graph is drawn for each user, which shows the usage as a percentage of his hard limit. System accounts (UID <1000) are suppressed. +In addition, a graph is displayed which indicates the ratio device size to device coverage. +The script repqutoa, usually part of the package quota, is needed. +The plugin itself can be stored in any directory. For example, the device sdb1 shell be monitored, a symbolic link must be created +in the /etc/munin/plugins/ directory as follows: + +=over + +I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> + +=back + +=head1 MAGIC MARKERS + + #%# family=auto + #%# capabilities=autoconf + +=head1 VERSION + +17.0210 + +=head1 HISTORY + +V17.0210 + + add env.humanid + add check if device exist + add if no limitations administered via 'quota' for the device the total line is shown only + fix same nitpicking details + add some comments + +V17.0131 + + add POD documentation + add env.language + add example graph for Munin Plugin Gallery + remove German comments + +V17.0124 + + first version, not munin rules conform + +=head1 AUTHOR + +Jo Hartmann + +=head1 LICENSE + +GPLv2 (L) + +=cut + +################################################### +# Autoconf section # +################################################### + + if [ "$1" = "autoconf" ]; then + if ! repquota -V &> /dev/null ; then + echo "no ('requota' executable is missing)" + exit 127 + fi + + if ! df "/dev/${0##*_}" &> /dev/null; then + echo "The device /dev/${0##*_} does not exist!" >&2 + exit 128 + fi + + echo yes + exit 0 + fi + +################################################### +# Preparation section # +################################################### + +# Load munin's shell libary + . "$MUNIN_LIBDIR/plugins/plugin.sh" + +# if any fetch from munin-node file + Warning=${warning:-90} + Critical=${critical:-95} + Language=${language:-en} + Min_UID=${humanuid:-1000} + +# Ensure that the 'root' path is valid + PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# Checking if repquota installed and on the path + if ! repquota -V &> /dev/null ; then + echo "The script 'repquota' is not installed or on the path" >&2 + # Send the exit code FATAL ERROR happens + exit 127 + fi + +# get tehe wild card text + Id=${0##*_} + +# Check if device exist + if ! df "/dev/$Id" &> /dev/null; then + echo "The device /dev/$Id does not exist!" >&2 + exit 128 + fi + +################################################### +# Data reading sections # +################################################### + +# Reading the quotes for the selected device, using repquota + if repquota "/dev/$Id" &> /dev/null; then + readarray Quotas < <( repquota "/dev/$Id" | grep " -- " ) + else + echo "No limitations administered via 'quota' for $Id" >&2 + # If no limitatitons administered: create a dummy + Quotas[0]="root -- 1 1 1 1 1 1" + fi + + readarray Totals < <( df "/dev/$Id" ) + +# Get the count of Users + Users=${#Quotas[@]} + + +################################################### +# Munin Configuration Section # +################################################### + + if [ "$1" = "config" ]; then + + # Localisation of the graphic texts + case $Language in + de) + echo graph_title "Quota-Hard-Limit von $Id" + echo graph_vlabel "Nutzung in % Hardlimit" + echo graph_info "Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >= $Min_UID) in Prozent des Hardlimits." + Total_txt="Su. aller Nutzer" + Total_info="Inklusive Systemnutzer (UID < $Min_UID)" + ;; + es) + echo graph_title "Cuota de límite absoluto de $Id" + echo graph_vlabel "el % de uso del límite duro" + echo graph_info "El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID >= $Min_UID) como porcentaje de límites duros." + Total_txt="Suma de todos los usuarios " + Total_info="La inclusión de usuario del sistema (UID < $Min_UID) " + ;; + *) + echo graph_title "quota hard limit of $Id" + echo graph_vlabel "Usage in %" + echo graph_info "The graphic shows the allocation of the quota-regulated storage space for all regular users (UID >= $Min_UID) as a percentage of the hard limit ." + Total_txt="all users" + Total_info="system users (UID < $Min_UID) included" + ;; + esac + + # Defaults configuration + echo graph_category disk + echo graph_args --lower-limit 0 --upper-limit 100 + echo graph_printf %5.2lf %% + echo graph_scale no + + # For each quota user fetch his real name, solve the root problem, Output the configuration data + for((i=0; i<"$Users"; i++));do + Quota=( ${Quotas[$i]} ) + UserName=${Quota[0]} + Passwd=$(grep "$UserName" /etc/passwd) + OLDIFS=$IFS + IFS=':' Infos=($Passwd) + IFS=$OLDIFS + UserInfo=${Infos[4]} + UserInfo=${UserInfo%%,*} + + UserName="$(clean_fieldname "$UserName")" + + # I hate the underlines in place of blanks! + [ "$(echo "$UserName"|cut -c 1)" = "_" ] && UserInfo="$(clean_fieldname "$UserInfo")" + + # If no UserInfo found + [ ! -n "$UserInfo" ] && UserInfo="$UserName" + + # No graph for none human uid + [ "$(id -u "${Quota[0]}")" -lt "$Min_UID" ] && echo "$UserName.graph no" + + # configure the user lines + echo "$UserName.label $UserInfo" + echo "$UserName.warning $Warning" + echo "$UserName.critical $Critical" + done + + # configure the total line and send exit code NO ERROR happens + echo total.label "$Total_txt" + echo total.warning "$Warning" + echo total.critical "$Critical" + echo total.info "$Total_info" + exit 0 + fi + +################################################### +# Munin value section # +################################################### + +# fetch the needed values (used and hard limit) for each user, work around the root problem, calculate the percent value + for((i=0; i<"$Users"; i++));do + Quota=( ${Quotas[$i]} ) + UserName="$(clean_fieldname "${Quota[0]}")" + echo "${Quota[2]} ${Quota[4]} $UserName.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' + done + +# the value for the total line + Total=( ${Totals[1]} ) + echo "${Total[2]} ${Total[1]} total.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' + +# send the exit code NO ERROR happens + exit 0 + +################################################### +# Script end # +################################################### From a00b8e6f2ed39233a814c2db46bc322d6bf6d8a9 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sat, 11 Feb 2017 14:18:46 +0100 Subject: [PATCH 21/31] Update quota2percent_ to V17.0210 --- plugins/disk/quota2percent_ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index 683a9368..06222cd8 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -92,7 +92,7 @@ GPLv2 (L) fi if ! df "/dev/${0##*_}" &> /dev/null; then - echo "The device /dev/${0##*_} does not exist!" >&2 + echo "no (device /dev/${0##*_} does not exist!)" >&2 exit 128 fi From d24215d05e8cfd038354e6ef7cf53d0667e845c8 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sat, 11 Feb 2017 14:31:16 +0100 Subject: [PATCH 22/31] Update quota2percent_ to V17.0210 add env.humanid add check if device exist add if no limitations administered via 'quota' for the device the total line is shown only fix some nitpicking details add some comments --- plugins/disk/quota2percent_ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index 06222cd8..a3b66cb1 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -57,7 +57,7 @@ V17.0210 add env.humanid add check if device exist add if no limitations administered via 'quota' for the device the total line is shown only - fix same nitpicking details + fix some nitpicking details add some comments V17.0131 From 19a193ef11f24ff9396d492ed4c67282cb285da4 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sun, 12 Feb 2017 17:56:49 +0100 Subject: [PATCH 23/31] Update quota2percent_ to V17.0213 fixed some slips --- plugins/disk/quota2percent_ | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index a3b66cb1..0038e05c 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -48,10 +48,13 @@ I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> =head1 VERSION -17.0210 +17.0213 =head1 HISTORY +V17.0213 + + fix some slips V17.0210 add env.humanid @@ -88,12 +91,12 @@ GPLv2 (L) if [ "$1" = "autoconf" ]; then if ! repquota -V &> /dev/null ; then echo "no ('requota' executable is missing)" - exit 127 + exit 0 fi if ! df "/dev/${0##*_}" &> /dev/null; then - echo "no (device /dev/${0##*_} does not exist!)" >&2 - exit 128 + echo "no (device /dev/${0##*_} does not exist!)" + exit 0 fi echo yes @@ -193,9 +196,7 @@ GPLv2 (L) Quota=( ${Quotas[$i]} ) UserName=${Quota[0]} Passwd=$(grep "$UserName" /etc/passwd) - OLDIFS=$IFS IFS=':' Infos=($Passwd) - IFS=$OLDIFS UserInfo=${Infos[4]} UserInfo=${UserInfo%%,*} From 1018c515b178956b397c840271cfcf785654974a Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Sun, 12 Feb 2017 18:11:49 +0100 Subject: [PATCH 24/31] same as before only add second line feed before V17.0210 in POD text --- plugins/disk/quota2percent_ | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index 0038e05c..fdd330eb 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -55,6 +55,7 @@ I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> V17.0213 fix some slips + V17.0210 add env.humanid From 0da1222099eb29817df7dbb8947574038e8cdf83 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Mon, 13 Feb 2017 09:49:57 +0100 Subject: [PATCH 25/31] Delete fritzbox7490.sh --- plugins/fritz-box7490/de/fritzbox7490.sh | 204 ----------------------- 1 file changed, 204 deletions(-) delete mode 100644 plugins/fritz-box7490/de/fritzbox7490.sh diff --git a/plugins/fritz-box7490/de/fritzbox7490.sh b/plugins/fritz-box7490/de/fritzbox7490.sh deleted file mode 100644 index f8f86a89..00000000 --- a/plugins/fritz-box7490/de/fritzbox7490.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/bin/bash -# FritzBox.sh - -### Quelle des Codekerns - Target of die skript core ############################ -# https://github.com/Tscherno/Fritzbox.sh # -# compatible with Fritz.box Firmware 6.50 and higher, Horst Schmid, 2016-01-05 # -# /usr/local/addons/cuxd/user/FritzBox.sh # -################################################################################# - -##################################################################################################################################################### -# Der Vorbereitungs-Job muss per cron gestartet werden - Thie prerunning job must be started by cron # -# /etc/cron.d/fritzbox # -# 3,8,13,18,23,28,33,38,43,48,53,58 * * * * root //fritzbox7490.sh -p (-u >login user if required>] #okay # -# # -# Jo Hartmann V17.0126 # -##################################################################################################################################################### - -# Deklaration der Dateipfade -# Declaration of file pathes - CPWMD5="/etc/munin/plugins/pre2run/cpwmd5" - FRITZLOGIN="/login_sid.lua" - FRITZWEBCM="/cgi-bin/webcm" - FRITZHOME="/home/home.lua" - CURLFILE="/var/tmp/FritzBoxCurl.txt" - LOGFILE="/var/log/fritzbox7490.log" - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -# Wie werden die Webseiten aufgerufen -# How to call web pages - WEBCLIENT="curl -s" - -# Deklaration sonstiger Variablen -# Declaration of other variables - FritzBoxURL="192.168.0.111" - Username="" - Passwd="" - Debug=false - -# Verarbeitung der Aufruf-Parameter -# Processing the script parameters - while getopts u:p:d OPT; do - case $OPT in - u) - Username=$OPTARG - ;; - p) - Passwd=$OPTARG - ;; - d) - Debug=true - LOGFILE="/dev/stdout" - ;; - - esac - done - -# Anmelde-Routine, Quelle: https://github.com/Tscherno/Fritzbox.sh, Horst Schmid, 2016-01-05 -# Login routine, source: https://github.com/Tscherno/Fritzbox.sh, Horst Schmid, 2016-01-05 - LOGIN(){ - # We need an SessionInfoChallenge SID from the FB. Combined with the PW an - # MD5-Checksum needs to be calculated and send back. - # 1. Are we already logged in? - htmlLoginPage=$($WEBCLIENT "$FritzBoxURL$FRITZLOGIN") - SessionInfoChallenge=$(echo "$htmlLoginPage" | sed -n '/.*\([^<]*\)<.*/s//\1/p') - SessionInfoSID=$(echo "$htmlLoginPage" | sed -n '/.*\([^<]*\)<.*/s//\1/p') - if $Debug; then echo "****************** LOGIN: Challenge $SessionInfoChallenge" >> $LOGFILE; fi - if [ "$SessionInfoSID" = "0000000000000000" ]; then - if $Debug; then echo "****************** LOGIN: Keine gueltige SID - login aufbauen" >> $LOGFILE; fi - CPSTR="$SessionInfoChallenge-$Passwd" # Combine Challenge and Passwd - if $Debug; then echo "****************** LOGIN: CPSTR: $CPSTR -> MD5" >> $LOGFILE; fi - MD5=`$CPWMD5 $CPSTR` # here the MD5 checksum is calculated - RESPONSE="$SessionInfoChallenge-$MD5" - if $Debug; then echo "****************** LOGIN: login senden und SID herausfischen, MD5: $MD5" >> $LOGFILE; fi - GETDATA="?username=$Username&response=$RESPONSE" - if $Debug; then echo "****************** LOGIN: $GETDATA" >> $LOGFILE; fi - SID=$($WEBCLIENT "$FritzBoxURL$FRITZLOGIN$GETDATA" | sed -n '/.*\([^<]*\)<.*/s//\1/p') - if $Debug; then echo "****************** Logged in with SID=$SID" >> $LOGFILE; fi - else - SID=$SessionInfoSID - if $Debug; then echo "****************** LOGIN: Bereits erfolgreiche SID: $SID" >> $LOGFILE; fi - fi - if [ "$SID" = "0000000000000000" ]; then - if $Debug; then echo "****************** LOGIN: ERROR - Konnte keine gueltige SID ermitteln" >> $LOGFILE; fi - fi - } - -# Definition der Linienlänge für die Ausgabe (MEZ oder MESZ?) -# Definition of line length for output (CET or CEST?) - MESZ=$(echo $(date +"%Z") | awk '{print length($0)-3}') - line="#####################################################" - if [ "$MESZ" = "1" ]; then line="${line}#";fi - -# Die alte Log-Datei für Differenzbetrachtungen sichern -# Save the old log file for differential views - if ! $Debug; then mv ${LOGFILE} ${LOGFILE}.1; fi - -# Startmeldung zur Ausgabe -# Start message for output - echo $line > $LOGFILE - echo "Startzeit der Auswertung: $(date +"%d.%m.%Y %X %Z") #" >> $LOGFILE - echo $line >> $LOGFILE - echo >> $LOGFILE - -# Abrage der Hard-/Software-Eigenschaften, funktioniert ohne Anmeldung! -# Query the hardware / software properties, works without login! - jBoxInfo=$($WEBCLIENT "$FritzBoxURL/jason_boxinfo.xml") - fbName=$(echo "$jBoxInfo" | grep 'j:Name' | sed -n 's,.*>\(.*\)\(.*\)\(.*\)\(.*\)\(.*\) /var/log/fritzbox7490.txt - -# Verarbeitung der Daten der Seite Online-Monitor -# Processing the data of the Online Monitor page - _AKT_IP=$(echo "$_PAGE_INET_STAT" | sed -n 's/.*
IP-Adresse: \(.*\)<\/span>.*/\1/p') - _VERBAB=$(echo "$_PAGE_INET_STAT" | sed -n 's/.*verbunden seit \(.*\)<\/span>,.*/\1/p') - -# Verarbeitung der Daten der Seite Online-Zähler -# Processing the data of the page Online counter - _ONLINE_Zeit=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"time">([0-9,:]+)<\/td>.*Gestern/,arr){print arr[1]};') - _VOLUMEN_T=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"vol">([0-9]+)<\/td>.*"vol">.*"vol">.*Gestern/,arr){print arr[1]};') - _VOLUMEN_U=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"vol">.*"vol">([0-9]+)<\/td>.*"vol">.*Gestern/,arr){print arr[1]};') - _VOLUMEN_D=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"vol">.*"vol">.*"vol">([0-9]+)<\/td>.*Gestern/,arr){print arr[1]};') - _ANZ_VERB=$(echo "${_PAGE_INET_COUN}" | tr -d "\n" | awk 'match($0,/Heute<\/td>.*"conn">([0-9,:]+)<\/td>.*Gestern/,arr){print arr[1]};') - -# Verarbeitung der Daten der Seite DSL-Informationen --> DSL -# Processing the data of the page DSL information -> DSL - _DATARATE_IN=$(echo "${_PAGE_DSL_STATS}" | awk 'match($0,/Aktuelle Datenrate.*"c3">([0-9]+)<\/td>.*Nahtlose Ratenadaption/,arr){print arr[1]};') - _DATARATE_OUT=$(echo "${_PAGE_DSL_STATS}" | awk 'match($0,/Aktuelle Datenrate.*"c4">([0-9]+)<\/td>.*Nahtlose Ratenadaption/,arr){print arr[1]};') - - _LATENZ_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Latenz.*"c3">([0-9]+) ms<\/td>/,arr){print arr[1]};') - _LATENZ_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Latenz.*"c4">([0-9]+) ms<\/td>/,arr){print arr[1]};') - - _NOISEMARGIN_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/rabstandsmarge.*"c3">([0-9]+)<\/td>.*gertausch/,arr){print arr[1]};') - _NOISEMARGIN_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/rabstandsmarge.*"c4">([0-9]+)<\/td>.*gertausch/,arr){print arr[1]};') - - _DSLLINELOSS_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Leitungsd.*"c3">([0-9]+)<\/td>.*Leistungsreduzierung/,arr){print arr[1]};') - _DSLLINELOSS_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Leitungsd.*"c4">([0-9]+)<\/td>.*Leistungsreduzierung/,arr){print arr[1]};') - - _DSLESERROR_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c2">([0-9]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') - _DSLESERROR_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c2">([0-9]+)<\/td>.*table>/,arr){print arr[1]};') - - _DSLSESERROR_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c3">([0-9]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') - _DSLSESERROR_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c3">([0-9]+)<\/td>.*table>/,arr){print arr[1]};') - - _DSLCRCERROR01_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c4">([0-9,.]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') - _DSLCRCERROR01_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c4">([0-9,.]+)<\/td>.*table>/,arr){print arr[1]};') - - _DSLCRCERROR15_IN=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/FRITZ!Box<\/td>.*"c5">([0-9]+)<\/td>.*Vermittlungsstelle/,arr){print arr[1]};') - _DSLCRCERROR15_OUT=$(echo "${_PAGE_DSL_STATS}" | tr -d "\n" | awk 'match($0,/Vermittlungsstelle<\/td>.*"c5">([0-9]+)<\/td>.*table>/,arr){print arr[1]};') - -#Resyncs der letzten 24h auslesen - -#_RESYNCS=$(echo "$_PAGE_STATS_GRAPH" | awk 'BEGIN {summe = 0}; match($0, /\[\"sar:status\/StatResync\"\] = \"(.*)\"/, arr){for(i = 1; i <= split(arr[1],splitted,",");i++){summe += int(splitted[i])}};END {print summe};') - -# Schreiben der Ausgabe Datei -# Write the output file - echo "AVM Typenbezeichnung: $fbName" >> $LOGFILE - echo "Firmeware-Version: $fbVersion1" >> $LOGFILE - echo "FritzOS: $fbVersion2" >> $LOGFILE - echo "Hardware-Version: $fbHardw" >> $LOGFILE - echo "Reversion: $fbRev" >> $LOGFILE - echo "Seriennummer: $fbSN" >> $LOGFILE - - - echo "Aktuelle IP-Adresse: $_AKT_IP" >> $LOGFILE - echo "Verbunden seit: $_VERBAB" >> $LOGFILE - - echo "Datenrate IN: $_DATARATE_IN kbit/s" >> $LOGFILE - echo "Datenrate OUT: $_DATARATE_OUT kbit/s" >> $LOGFILE - echo "Latenz Empfangsrichtung: $_LATENZ_IN ms" >> $LOGFILE - echo "Latenz Senderichtung: $_LATENZ_OUT ms" >> $LOGFILE - echo "Störabstandsmarge IN: $_NOISEMARGIN_IN db" >> $LOGFILE - echo "Störabstandsmarge OUT: $_NOISEMARGIN_OUT db" >> $LOGFILE - echo "Leitungsdämpfung IN: $_DSLLINELOSS_IN db" >> $LOGFILE - echo "Leitungsdämpfung OUT: $_DSLLINELOSS_OUT db" >> $LOGFILE - echo "Sek. m. Fehlern (ES) IN: $_DSLESERROR_IN" >> $LOGFILE - echo "Sek. m. Fehlern (ES) OUT: $_DSLESERROR_OUT" >> $LOGFILE - echo "Sek. m. v. Fehl. (SES) IN: $_DSLSESERROR_IN" >> $LOGFILE - echo "Sek. m. v. Fehl. (SES) OUT: $_DSLSESERROR_OUT" >> $LOGFILE - echo "CRC Fehler (je Min) IN: $_DSLCRCERROR01_IN" >> $LOGFILE - echo "CRC Fehler (je Min) OUT: $_DSLCRCERROR01_OUT" >> $LOGFILE - echo "CRC Fehler (15 Min) IN: $_DSLCRCERROR15_IN" >> $LOGFILE - echo "CRC Fehler (15 Min) OUT: $_DSLCRCERROR15_OUT" >> $LOGFILE - - echo "Stunden Online: $_ONLINE_Zeit" >> $LOGFILE - echo "Datenvolumen (gesamt): $_VOLUMEN_T MB" >> $LOGFILE - echo "Datenvolumen (upload): $_VOLUMEN_U MB" >> $LOGFILE - echo "Datenvolumen (download): $_VOLUMEN_D MB" >> $LOGFILE - echo "Anz. der Verbindungen: $_ANZ_VERB" >> $LOGFILE - echo >> $LOGFILE - echo $line >> $LOGFILE - echo "Stoppzeit der Auswertung: $(date +"%d.%m.%Y %X %Z") #" >> $LOGFILE - echo $line >> $LOGFILE - #echo ${_PAGE_INET_COUN} From 5335ec7af62b5abf78a2b24030f9ffd1e58bf0e7 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Mon, 13 Feb 2017 09:50:15 +0100 Subject: [PATCH 26/31] Delete fritzbox7490_ --- plugins/fritz-box7490/de/fritzbox7490_ | 191 ------------------------- 1 file changed, 191 deletions(-) delete mode 100644 plugins/fritz-box7490/de/fritzbox7490_ diff --git a/plugins/fritz-box7490/de/fritzbox7490_ b/plugins/fritz-box7490/de/fritzbox7490_ deleted file mode 100644 index d2051536..00000000 --- a/plugins/fritz-box7490/de/fritzbox7490_ +++ /dev/null @@ -1,191 +0,0 @@ -#!/bin/bash - -# Munin plugin um die aktuellen Werte der Datei fritzbox7490.log auszuwerten. -# internet connection by reading the top_status.htm from the -# Don't forget zu fill in the following lines into the munin-node -# -# - normally at /etc/muni/plugin-conf.d/ - an than restart munin -# -# [fritzbox_] -# user root -# -# LLOSS: Leitungsdämpfung = line loss -# DRATE: Datenrate = data rate -# SNR: Störabstand = signal-to-noise ratio -# DATAV: Datenvolumen = data transfer -# ES: Sek. m. Fehlern = sec. w. errors -# SES: Sek. m. v. Fehlern = sec w. m. errors -# VERB: Anzahl tägl. Verb. = count of daily connections -# UPT: Zt. seit Reboot = router uptime -# Jo Hartmann (Version 16.0126) -# - -################################### -## Personal config Section Begin ## -################################### - -logfile=/var/log/fritzbox7490.log - -################################### -## Personal config section End ## -################################### - -function Echo() { -# Munin hat probleme mit Sonderzeichen ÄÖÜ äöüß -# Munin has problems with special characters ÄÖÜ ääüß - konvert=`echo $* | sed s/Ä/Ae/g | sed s/Ö/Oe/g | sed s/Ü/Oe/g | sed s/ä/ae/g | sed s/ö/ue/g | sed s/ü/ue/g | sed s/ß/ss/g` - echo $konvert -} - -# Wildcard-Text erkennen -# Detect wildcard text - id=$0 - id=${id##*_} - -# Prüfen ob die Werte-Datei existiert, wenn ja einlesen sonst Abbruch -# Check if the values ??file exists, if yes read in otherwise abort - if [ -f $logfile ]; then - werte=$(cat $logfile) - else - echo Die Datei $logfile wurde nicht gefunden! Abbruch! >&2 - exit 1 - fi - - -# Standard Config Section Begin ## - if [ "$1" = "autoconf" ]; then - echo yes - exit 0 - fi - - if [ "$1" = "config" ]; then - -# Standard Konfiguration -# Default configuration - echo graph_category DSL - echo graph_args --base 1000 -l 100 - #echo graph_printf %7.3lf%S M - echo graph_info Datenstatistik aus der FRITZ!Box 7490 - -# Wildcard-abhängige Konfiguration überschreibt den obigen Standard -# Wildcard dependent configuration overwrites the above standards - case $id in - LLOSS) - Echo graph_title Leitungsdämpfung - Echo graph_vlabel Dämpfung in db - echo u.label upload - echo d.label download - ;; - DRATE) - Echo graph_title Übertragungsgeschwindigkeit - echo graph_vlabel Datenrate in kbit/s - echo u.label upload - echo d.label download - ;; - SNR) - Echo graph_title Störabstand - echo graph_vlabel Abstand in db - echo u.label upload - echo d.label download - ;; - DATAV) - Echo graph_title tägliches Daten-Volumen - echo graph_vlabel Transfer in MB - echo u.label upload - echo d.label download - echo g.label gesamt - ;; - ES) - echo graph_title Sekunden mit Fehlern \(ES\) - echo graph_vlabel Sekunden - echo u.label upload - echo d.label download - ;; - SES) - echo graph_title Sekunden mit vielen Fehlern \(SES\) - echo graph_vlabel Sekunden - echo u.label upload - echo d.label download - ;; - CRC01) - Echo graph_title Nicht korrigierbare Fehler \(CRC\) - echo graph_vlabel Anzahl - echo u.label upload - echo d.label download - ;; - CRC15) - Echo graph_title Nicht korrigierbare Fehler in 15 Min. \(CRC\) - echo graph_vlabel Anzahl - echo u.label upload - echo d.label download - ;; - VERB) - Echo graph_title Anzahl der täglichen Wiederverbindung - echo graph_vlabel Anzahl - echo u.label upload - echo d.label download - ;; - UPT) - ;; - *) - echo " ##############################################" >&2 - echo " # Felerhafter Programmaufruf, zulässig sind: #" >&2 - echo " # - fritzbox7490_DRATE #" >&2 - echo " # - fritzbox7490_LLOSS #" >&2 - echo " # - fritzbox7490_SNR #" >&2 - echo " # - fritzbox7490_DATAV #" >&2 - echo " # - fritzbox7490_CRC01 #" >&2 - echo " # - fritzbox7490_CRC15 #" >&2 - echo " # - fritzbox7490_ES #" >&2 - echo " # - fritzbox7490_SES #" >&2 - echo " # - fritzbox7490_VERB #" >&2 -# echo " # - fritzbox7490_UPT #" >&2 - echo " ##############################################" >&2 - exit 2 - ;; - esac - exit 0 - fi -# Standard Config Section End #### - -# Wildcard-abhängige Datenauswertung -# Wildcard-dependent data evaluation - case $id in - LLOSS) - u_value=$(echo "${werte}" | awk 'match($0,/pfung OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/mpfung IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value - ;; - DRATE) - u_value=$(echo "${werte}" | awk 'match($0,/atenrate OUT:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo u.value `echo "$u_value * 1024" | bc` - d_value=$(echo "${werte}" | awk 'match($0,/Datenrate IN:.* ([0-9]+) kbit\/s/,arr){print arr[1]};'); echo d.value `echo "$d_value * 1024" | bc` - ;; - SNR) - u_value=$(echo "${werte}" | awk 'match($0,/bstandsmarge OUT:.* ([0-9]+) db/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/abstandsmarge IN:.* ([0-9]+) db/,arr){print arr[1]};'); echo d.value $d_value - ;; - DATAV) - u_value=$(echo "${werte}" | awk 'match($0,/volumen \(upload\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/volumen \(download\):.* ([0-9]+) MB/,arr){print arr[1]};'); echo d.value $d_value - g_value=$(echo "${werte}" | awk 'match($0,/volumen \(gesamt\): .* ([0-9]+) MB/,arr){print arr[1]};'); echo g.value $g_value - ;; - CRC01) - u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) IN: .* ([0-9,\.]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(je Min\) OUT:.* ([0-9,\.]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - CRC15) - u_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehler \(15 Min\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - ES) - u_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehlern \(ES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - SES) - u_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) OUT:.* ([0-9]+)/,arr){print arr[1]};'); echo u.value $u_value - d_value=$(echo "${werte}" | awk 'match($0,/Fehl. \(SES\) IN: .* ([0-9]+)/,arr){print arr[1]};'); echo d.value $d_value - ;; - *) - u_value=0 - d_value=0 - ;; - esac From 393cd49271e13b3c414c4fd6446787ba5b939108 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Mon, 13 Feb 2017 09:50:30 +0100 Subject: [PATCH 27/31] Delete read.me --- plugins/fritz-box7490/de/read.me | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 plugins/fritz-box7490/de/read.me diff --git a/plugins/fritz-box7490/de/read.me b/plugins/fritz-box7490/de/read.me deleted file mode 100644 index 7ccad11c..00000000 --- a/plugins/fritz-box7490/de/read.me +++ /dev/null @@ -1,2 +0,0 @@ -Die Versionen für die deutschsprachige Benutzeroberfläche. -The versions for the German-language user interface. From 6a30ab641e1c8c11f4557ff4424f1d05a02f8afb Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Mon, 13 Feb 2017 09:51:06 +0100 Subject: [PATCH 28/31] Delete read.me --- plugins/fritz-box7490/en/read.me | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 plugins/fritz-box7490/en/read.me diff --git a/plugins/fritz-box7490/en/read.me b/plugins/fritz-box7490/en/read.me deleted file mode 100644 index cb7f4191..00000000 --- a/plugins/fritz-box7490/en/read.me +++ /dev/null @@ -1,2 +0,0 @@ -Die Versionen für die englischsprachige Benutzeroberfläche. -The versions for the English-language user interface. From 0a7dd5e62bcef02ef29745f4728dc10b6895899b Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Mon, 13 Feb 2017 09:51:30 +0100 Subject: [PATCH 29/31] Delete read.me --- plugins/fritz-box7490/read.me | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 plugins/fritz-box7490/read.me diff --git a/plugins/fritz-box7490/read.me b/plugins/fritz-box7490/read.me deleted file mode 100644 index 8ee9aa4d..00000000 --- a/plugins/fritz-box7490/read.me +++ /dev/null @@ -1,2 +0,0 @@ -Deutsche Version (English version below) -English version (deutsche Version oberhalb) From b430482f68a332deb684db7867ede5bf18f56454 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Mon, 13 Feb 2017 18:52:37 +0100 Subject: [PATCH 30/31] Update quota2percent_ to V17.0213a fix some slips add env.low_uid follow an idea of sumpfralle --- plugins/disk/quota2percent_ | 88 +++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index fdd330eb..9ce4f8a6 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -9,6 +9,7 @@ quota2percent - Plugin to show disk usage in percent of quota hard limit. =head1 APPLICABLE SYSTEMS All systems with "bash", "quota", "repquota" and "munin" + Systems with multiple users and individual storage space limitations administered via 'quota' =head1 CONFIGURATION @@ -25,6 +26,9 @@ You could define two alert levels and the graph language env.critical [value] (default: 95) env.language [en|de|es] (default: en) env.humanuid [value] (default: 1000, only need if there is an other value define for UID_MIN in /etc/login.defs) + env.low_uid [never|no|yes] (default: never) + set to no for producing rrd files for system user, but don't show those graphs (e.g. for later analyses) + if set to yes system user graphs are drawn =head1 DESCRIPTION @@ -55,7 +59,8 @@ I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> V17.0213 fix some slips - + add env.low_uid + V17.0210 add env.humanid @@ -116,6 +121,7 @@ GPLv2 (L) Critical=${critical:-95} Language=${language:-en} Min_UID=${humanuid:-1000} + Low_UID=${low_uid:-never} # Ensure that the 'root' path is valid PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" @@ -147,6 +153,7 @@ GPLv2 (L) echo "No limitations administered via 'quota' for $Id" >&2 # If no limitatitons administered: create a dummy Quotas[0]="root -- 1 1 1 1 1 1" + Low_UID="never" fi readarray Totals < <( df "/dev/$Id" ) @@ -164,65 +171,63 @@ GPLv2 (L) # Localisation of the graphic texts case $Language in de) - echo graph_title "Quota-Hard-Limit von $Id" - echo graph_vlabel "Nutzung in % Hardlimit" - echo graph_info "Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >= $Min_UID) in Prozent des Hardlimits." + echo "graph_title Quota-Hard-Limit von $Id" + echo "graph_vlabel Nutzung in % Hardlimit" + echo "graph_info Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >= $Min_UID) in Prozent des Hardlimits." Total_txt="Su. aller Nutzer" Total_info="Inklusive Systemnutzer (UID < $Min_UID)" ;; es) - echo graph_title "Cuota de límite absoluto de $Id" - echo graph_vlabel "el % de uso del límite duro" - echo graph_info "El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID >= $Min_UID) como porcentaje de límites duros." + echo "graph_title Cuota de límite absoluto de $Id" + echo "graph_vlabel el % de uso del límite duro" + echo "graph_info El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID >= $Min_UID) como porcentaje de límites duros." Total_txt="Suma de todos los usuarios " - Total_info="La inclusión de usuario del sistema (UID < $Min_UID) " + Total_info="La inclusión de usuario del sistema (UID < $Min_UID) " ;; *) - echo graph_title "quota hard limit of $Id" - echo graph_vlabel "Usage in %" - echo graph_info "The graphic shows the allocation of the quota-regulated storage space for all regular users (UID >= $Min_UID) as a percentage of the hard limit ." + echo "graph_title quota hard limit of $Id" + echo "graph_vlabel Usage in %" + echo "graph_info The graphic shows the allocation of the quota-regulated storage space for all regular users (UID >= $Min_UID) as a percentage of the hard limit ." Total_txt="all users" Total_info="system users (UID < $Min_UID) included" ;; esac # Defaults configuration - echo graph_category disk - echo graph_args --lower-limit 0 --upper-limit 100 - echo graph_printf %5.2lf %% - echo graph_scale no + echo "graph_category disk" + echo "graph_args --lower-limit 0 --upper-limit 100" + echo "graph_printf %5.2lf %%" + echo "graph_scale no" - # For each quota user fetch his real name, solve the root problem, Output the configuration data + # Processing the individual user for((i=0; i<"$Users"; i++));do Quota=( ${Quotas[$i]} ) - UserName=${Quota[0]} - Passwd=$(grep "$UserName" /etc/passwd) - IFS=':' Infos=($Passwd) - UserInfo=${Infos[4]} - UserInfo=${UserInfo%%,*} + User=${Quota[0]} + # solve the root problem + Fieldname="$(clean_fieldname "$User")" - UserName="$(clean_fieldname "$UserName")" + # Determine the currently processing UID + Cur_UID="$(id -u "$User")" + + # skip if actual user a system user und low_uid ist set to never + if [ ! "$Low_UID" == "never" ] || [ ! "$Cur_UID" -lt "$Min_UID" ]; then - # I hate the underlines in place of blanks! - [ "$(echo "$UserName"|cut -c 1)" = "_" ] && UserInfo="$(clean_fieldname "$UserInfo")" + # No graph for none human uid if low_uid ist set to no + [ "$Cur_UID" -lt "$Min_UID" ] && echo "$Fieldname.graph $Low_UID" - # If no UserInfo found - [ ! -n "$UserInfo" ] && UserInfo="$UserName" + # configure the user lines + echo "$Fieldname.label $User" + echo "$Fieldname.warning $Warning" + echo "$Fieldname.critical $Critical" + fi - # No graph for none human uid - [ "$(id -u "${Quota[0]}")" -lt "$Min_UID" ] && echo "$UserName.graph no" - - # configure the user lines - echo "$UserName.label $UserInfo" - echo "$UserName.warning $Warning" - echo "$UserName.critical $Critical" done # configure the total line and send exit code NO ERROR happens - echo total.label "$Total_txt" - echo total.warning "$Warning" - echo total.critical "$Critical" - echo total.info "$Total_info" + echo "total.label $Total_txt" + echo "total.warning $Warning" + echo "total.critical $Critical" + echo "total.info $Total_info" exit 0 fi @@ -233,8 +238,13 @@ GPLv2 (L) # fetch the needed values (used and hard limit) for each user, work around the root problem, calculate the percent value for((i=0; i<"$Users"; i++));do Quota=( ${Quotas[$i]} ) - UserName="$(clean_fieldname "${Quota[0]}")" - echo "${Quota[2]} ${Quota[4]} $UserName.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' + Fieldname="$(clean_fieldname "${Quota[0]}")" + + # skip if actual user a system user und low_uid ist set to never + if [ ! "$Low_UID" == "never" ] || [ ! "$(id -u "${Quota[0]}")" -lt "$Min_UID" ]; then + echo "${Quota[2]} ${Quota[4]} $Fieldname.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' + fi + done # the value for the total line From e0b47d579ebba7ed936832fe398941f465963213 Mon Sep 17 00:00:00 2001 From: JoHartmann Date: Tue, 14 Feb 2017 14:57:46 +0100 Subject: [PATCH 31/31] Update quota2percent_ to V17.0214 Following some idea of "Sumpfralle! --- plugins/disk/quota2percent_ | 67 ++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/plugins/disk/quota2percent_ b/plugins/disk/quota2percent_ index 9ce4f8a6..6b3e6c62 100644 --- a/plugins/disk/quota2percent_ +++ b/plugins/disk/quota2percent_ @@ -19,7 +19,7 @@ The following is the default configuration [quota2percent_*] user root -You could define two alert levels and the graph language +You could define two alert levels, the graph language, min. human UID and dealing with system users [quota2percent_*] env.warning [value] (default: 90) @@ -52,33 +52,31 @@ I<<< ln -s //quota2percent_ quota2percent_sdb1 >>> =head1 VERSION -17.0213 +17.0214 =head1 HISTORY -V17.0213 +V17.0214 + fix hard reading logic operation for skipping by Low_UID=never fix some slips + fix some nitpicking details + add env.low_uid - -V17.0210 - add env.humanid + add env.language add check if device exist add if no limitations administered via 'quota' for the device the total line is shown only - fix some nitpicking details - add some comments - -V17.0131 - + add a few comments add POD documentation - add env.language add example graph for Munin Plugin Gallery + + remove setting a PATH remove German comments V17.0124 - first version, not munin rules conform + not pubish, first version =head1 AUTHOR @@ -123,9 +121,6 @@ GPLv2 (L) Min_UID=${humanuid:-1000} Low_UID=${low_uid:-never} -# Ensure that the 'root' path is valid - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - # Checking if repquota installed and on the path if ! repquota -V &> /dev/null ; then echo "The script 'repquota' is not installed or on the path" >&2 @@ -151,8 +146,12 @@ GPLv2 (L) readarray Quotas < <( repquota "/dev/$Id" | grep " -- " ) else echo "No limitations administered via 'quota' for $Id" >&2 - # If no limitatitons administered: create a dummy + + # If no limitatitons administered: create a dummy for regarding + # the avoidance of a divide-by-zero error Quotas[0]="root -- 1 1 1 1 1 1" + + # no rrd file need Low_UID="never" fi @@ -173,16 +172,16 @@ GPLv2 (L) de) echo "graph_title Quota-Hard-Limit von $Id" echo "graph_vlabel Nutzung in % Hardlimit" - echo "graph_info Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >= $Min_UID) in Prozent des Hardlimits." + echo "graph_info Die Grafik zeigt die Belegung des durch Quota reglementierten Speicherplatzes für alle regulären Nutzer (UID >= $Min_UID) in Prozent des Hardlimits." Total_txt="Su. aller Nutzer" Total_info="Inklusive Systemnutzer (UID < $Min_UID)" ;; es) - echo "graph_title Cuota de límite absoluto de $Id" - echo "graph_vlabel el % de uso del límite duro" - echo "graph_info El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID >= $Min_UID) como porcentaje de límites duros." + echo "graph_title Cuota de límite absoluto de $Id" + echo "graph_vlabel el % de uso del límite duro" + echo "graph_info El gráfico muestra la disponibilidad de espacio regulado por cuotas para todos los usuarios regulares (UID >= $Min_UID) como porcentaje de límites duros." Total_txt="Suma de todos los usuarios " - Total_info="La inclusión de usuario del sistema (UID < $Min_UID) " + Total_info="La inclusión de usuario del sistema (UID < $Min_UID) " ;; *) echo "graph_title quota hard limit of $Id" @@ -210,17 +209,16 @@ GPLv2 (L) Cur_UID="$(id -u "$User")" # skip if actual user a system user und low_uid ist set to never - if [ ! "$Low_UID" == "never" ] || [ ! "$Cur_UID" -lt "$Min_UID" ]; then + [ "$Cur_UID" -lt "$Min_UID" ] && [ "$Low_UID" = "never" ] && continue - # No graph for none human uid if low_uid ist set to no - [ "$Cur_UID" -lt "$Min_UID" ] && echo "$Fieldname.graph $Low_UID" - - # configure the user lines - echo "$Fieldname.label $User" - echo "$Fieldname.warning $Warning" - echo "$Fieldname.critical $Critical" - fi + # No graph for none human uid if low_uid ist set to no + [ "$Cur_UID" -lt "$Min_UID" ] && echo "$Fieldname.graph $Low_UID" + # configure the user lines + echo "$Fieldname.label $User" + echo "$Fieldname.warning $Warning" + echo "$Fieldname.critical $Critical" + done # configure the total line and send exit code NO ERROR happens @@ -241,9 +239,10 @@ GPLv2 (L) Fieldname="$(clean_fieldname "${Quota[0]}")" # skip if actual user a system user und low_uid ist set to never - if [ ! "$Low_UID" == "never" ] || [ ! "$(id -u "${Quota[0]}")" -lt "$Min_UID" ]; then - echo "${Quota[2]} ${Quota[4]} $Fieldname.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' - fi + [ "$Cur_UID" -lt "$Min_UID" ] && [ "$Low_UID" = "never" ] && continue + + # write the result zu munin + echo "${Quota[2]} ${Quota[4]} $Fieldname.value" | awk '{printf "%s %f\n",$3,$1*100/$2}' done