first commit

This commit is contained in:
2023-04-01 02:08:39 +02:00
commit 08385e02fb
16 changed files with 293 additions and 0 deletions

4
.env.example Normal file
View File

@@ -0,0 +1,4 @@
INFLUX_SERVER=127.0.0.1
INFLUX_ORG=my-org
INFLUX_BUCKET=customer-xyz
INFLUX_TOKEN="<secret-influxdb-api-token>"

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.env

19
README.md Normal file
View File

@@ -0,0 +1,19 @@
# Bash based logging Script for InfluxDB
## Short description:
This script logs various inputs and sensors to test reachability and read out
data from devices on the network. The data will be stored in an InfluxDB for
processing in other applications.
## Reasonable features to include:
- Modular design with sensors being run from a sensors.d directory
- Common functions and variables passed to the sensors for ease of programming
- Sensor types:
- [x] Ping (int, latency)
- [x] TCP Port (Bool, open or not)
- [ ] SSH command (int, return code)
- [ ] SSH command (string, output)
- [ ] Speedtest Internet (int, Download Bandwith in Mb/s)
- [ ] Speedtest Internet (int, Upload Bandwidth in Mb/s)
- [x] Speedtest IPerf (int, Download Bandwidth in Mb/s)
- [x] Speedtest IPerf (int, Upload Bandwith in Mb/s)

6
inc/bash-colors.sh Normal file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
BG_RED="\e[41m\e[97m"
FG_BLUE="\e[34m"
FG_YELLOW="\e[33m"
C_RESET="\e[0m"

38
inc/main-inc.sh Normal file
View File

@@ -0,0 +1,38 @@
#!/bin/bash
pushd $(dirname ${BASH_SOURCE[0]}) >/dev/null
# Include configuration
source ../.env
export INFLUX_TOKEN
# Include other functions
source output.sh
# Include all sensor scripts
if [ -d "sensor-scripts" ]; then
for script in $(ls sensor-scripts/*.sh 2>/dev/null); do
log "Loading sensor function $(basename ${script} .sh)"
source "${script}"
done
fi
# Test if influxdb2 CLI is installed
if ! which influx >/dev/null; then
logError "Influx CLI not found!"
exit 1
fi
# Write data to influx DB
function writeData {
MEASURE="$1"
TAGS="$2"
FIELDS="$3"
influx write \
-b ${INFLUX_BUCKET} \
-o ${INFLUX_ORG} \
-p s \
"${MEASURE},${TAGS} ${FIELDS}"
}
popd >/dev/null

42
inc/output.sh Normal file
View File

@@ -0,0 +1,42 @@
#!/bin/bash
source "bash-colors.sh"
# Echo formatted time right now
function _now {
date +"%y/%m/%d %H:%M:%S"
}
# Write log to stdout
function log {
echo "[ $(_now) :: INFO ] $@"
}
# Log with custom tag
function logAdv {
TAG="${1}"
shift
echo -e "${FG_BLUE}[ $(_now) :: ${TAG} ] ${@}${C_RESET}"
}
# Log tagged for sensor scripts, can be muted with main.sh -qs
function logScript {
if ! [ "${SCRIPTS_QUIET}" = "yes" ]; then
echo -e "[ $(_now) :: SENS ] ${@}"
fi
}
# Write error to stderr
function logError {
echo -e "${BG_RED}[ $(_now) :: FAIL ] ${@}${C_RESET}" >&2
}
# Write pipe input to stdout
function logPipe {
PREFIX="PIPE"
[ "${1}" = "" ] || PREFIX="${@}"
while read -r LINE; do
echo -e "${FG_YELLOW}[ $(_now) :: ${PREFIX} ] ${LINE}${C_RESET}"
done
}

View File

@@ -0,0 +1,55 @@
#!/bin/bash
SCRIPT_NAME=$(basename ${BASH_SOURCE[0]})
if ! which jq >/dev/null; then
logError "${SCRIPT_NAME}: Did not find jq in path!"
return
elif ! which iperf3 >/dev/null; then
logError "${SCRIPT_NAME}: Did not find iperf3 in path!"
return
fi
# Usage: doIperfTest <target-host> [<time>] [<additional-iperf-args>]
function doIperfTest {
HOST="${1}"
shift
TIME=10
if ! [ "${1}" = "" ]; then
TIME=${1}
LOG_SUFFIX=" for ${TIME} seconds"
shift
fi
logScript "Doing IPerf3 test to ${HOST}${LOG_SUFFIX}"
OUT=$(iperf3 -c "${HOST}" -t ${TIME} -i0 -J ${@})
SUCCESS=$( [ "$(echo ${OUT} | jq -r .error)" = null ] && echo true || echo false )
PROTO=$(echo ${OUT} | jq -r .start.test_start.protocol)
REMOTE_HOST=$(echo ${OUT} | jq -r .start.connected[0].remote_host)
REMOTE_PORT=$(echo ${OUT} | jq -r .start.connected[0].remote_port)
NUM_STREAMS=$(echo ${OUT} | jq -r .start.test_start.num_streams)
REVERSE=$(echo ${OUT} | jq -r .start.test_start.reverse)
SENT_SECONDS=$(echo ${OUT} | jq -r .end.sum_sent.seconds)
SENT_BPS=$(echo ${OUT} | jq -r .end.sum_sent.bits_per_second)
SENT_RETRANSMITS=$(echo ${OUT} | jq -r .end.sum_sent.retransmits)
RECEIVED_SECONDS=$(echo ${OUT} | jq -r .end.sum_received.seconds)
RECEIVED_BPS=$(echo ${OUT} | jq -r .end.sum_received.bits_per_second)
if ! [ "${SUCCESS}" = "true" ]; then
NUM_STREAMS=0
REVERSE=0
SENT_SECONDS=0
SENT_BPS=0
SENT_RETRANSMITS=0
RECEIVED_SECONDS=0
RECEIVED_BPS=0
fi
writeData \
iperf3 \
"sourceHost=$(hostname -f),targetHost=${HOST}" \
"success=${SUCCESS},connected_host=\"${REMOTE_HOST}:${REMOTE_PORT}\",proto=\"${PROTO}\",num_streams=${NUM_STREAMS},reverse=${REVERSE},retransmits=${SENT_RETRANSMITS},sent_seconds=${SENT_SECONDS},sent_bps=${SENT_BPS},received_seconds=${RECEIVED_SECONDS},received_bps=${RECEIVED_BPS}"
}

View File

@@ -0,0 +1,37 @@
#!/bin/bash
# Usage: doPingTest <target-host> [<count>]
function doPingTest {
HOST=${1}
logScript "Doing ping to ${HOST}"
COUNT=1
[ "${2}" = "" ] || COUNT=${2}
ping "${HOST}" -W 10 -c ${COUNT} | {
read -r HEADER
RESOLVED_NAME=$(echo ${HEADER} | sed 's/.* (\(.*\)) .*/\1/')
while read -r PINGLINE; do
if [[ "${PINGLINE}" == *" bytes from "* ]]; then
SUCCESS=true
BYTES=$(echo ${PINGLINE} | awk '{ print $1 }')
TTL=$(echo ${PINGLINE} | sed 's/.*ttl=\([0-9]\+\) .*/\1/')
LATENCY=$(echo ${PINGLINE} | sed 's/.*time=\([0-9\.]\+\) .*/\1/')
elif [ "${PINGLINE}" = "" ]; then
SUCCESS=false
BYTES=0
TTL=0
LATENCY=-1
else
continue
fi
writeData \
ping \
"sourceHost=$(hostname -f),targetHost=${HOST}" \
"success=${SUCCESS},resolved=\"${RESOLVED_NAME}\",latency=${LATENCY},ttl=${TTL},bytes=${BYTES}"
done
}
}

View File

@@ -0,0 +1,26 @@
#!/bin/bash
if ! which nc >/dev/null; then
logError "${SCRIPT_NAME}: Did not find nc in path!"
return
fi
# Usage: doTcpPortTest <target-host> <target-port> [<timeout>]
function doTcpPortTest {
HOST=${1}
PORT=${2}
TIMEOUT=5
[ "${3}" = "" ] || TIMEOUT=${3}
logScript "Doing TCP port test to ${HOST}:${PORT}"
SUCCESS=false
if nc -z -w ${TIMEOUT} ${HOST} ${PORT}; then
SUCCESS=true
fi
writeData \
tcp-port \
"sourceHost=$(hostname -f),targetHost=${HOST},targetPort=${PORT}" \
"open=${SUCCESS}"
}

40
main.sh Normal file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
cd $(dirname ${0}) >/dev/null
source inc/main-inc.sh
START_TIME=$(date +%s)
# Load all sensor scripts and their intervals
declare -A SCRIPTS
for SCRIPT in $(ls sensors.d/*.sh); do
BASENAME="$(basename ${SCRIPT})"
eval $(cat "${SCRIPT}" | head -n1)
log "Loaded sensor '$(basename ${SCRIPT})', runs every ${INTERVAL} seconds"
SCRIPTS["${BASENAME}"]=${INTERVAL}
done
log "Starting Scheduler routine"
if [[ "$@" == *"-qs"* ]]; then
log "Will suppress sensor script outputs"
export SCRIPTS_QUIET=yes
fi
while true; do
NOW=$(date +%s)
DIFF=$(expr ${START_TIME} - ${NOW})
for SCRIPT in "${!SCRIPTS[@]}"; do
SCRIPT_EVERY=${SCRIPTS[${SCRIPT}]}
if [ $( expr ${DIFF} % ${SCRIPT_EVERY} ) -eq 0 ]; then
logAdv "SCHD" "Launching $(basename ${SCRIPT})"
source "sensors.d/${SCRIPT}" ${QUIET_SCRIPT_PARAM} &
fi
done
# Wait one second to make sure the if statements don't fire repeatedly
# during any specific unix time second, not elegant but works
sleep 1
done

9
sensors.d/00-example.sh Normal file
View File

@@ -0,0 +1,9 @@
INTERVAL=10
# The INTERVAL=<secs> paramter must ALWAYS be the first line in any
# sensor.d script! It sets the interval in seconds that the sensor
# script shall be run by main.sh
# Do a ping to 1.1.1.1 with a 3 second timeout and log the results
doPingTest 1.1.1.1 3

View File

@@ -0,0 +1,3 @@
INTERVAL=120
doIperfTest localhost

View File

@@ -0,0 +1,3 @@
INTERVAL=5
doPingTest 1.1.1.1 3

View File

@@ -0,0 +1,3 @@
INTERVAL=5
doPingTest 8.8.8.8 3

3
sensors.d/ping-router.sh Normal file
View File

@@ -0,0 +1,3 @@
INTERVAL=3
doPingTest 192.168.0.1 3

4
sensors.d/tcp-example.sh Normal file
View File

@@ -0,0 +1,4 @@
INTERVAL=5
# Do a TCP open port test to example.org on port 80 with a three second timeout
doTcpPortTest example.org 80 3