Skip to content

Instantly share code, notes, and snippets.

@Semmu
Last active September 21, 2022 00:38
Show Gist options
  • Save Semmu/2936d11b9e62981026b28fcc85bb6c99 to your computer and use it in GitHub Desktop.
Save Semmu/2936d11b9e62981026b28fcc85bb6c99 to your computer and use it in GitHub Desktop.
super simple shell-based host monitor script wrapped in Docker publishing availability to the local MQTT broker

features:

  • script periodically pings hosts in parallel
  • sends multiple packets, only reports host down on 100% packet loss
  • compares host availability with previous value
  • sends simple message to local MQTT broker if host state change is detected
    • to topic: host-monitor/$HOSTNAME
    • payload: {"online": "0"} (or 1)
  • wrapped in Docker as i run most things in Docker on my server

missing features:

  • should report host down on all monitored hosts when stopping the script
  • should support some external configuration file: monitored hosts, mqtt credentials, etc.
  • should distribute it as a ready-to-use docker container on dockerhub

i personally to use this to monitor if my internet provider is down while im away (e.g. 8.8.8.8 is reachable) and also my devices on my personal VPN (check out Tailscale!)

these MQTT messages are then processed by a Node-RED instance, which in turn pushes the data to an InfluxDB, so then i can visualize the historical data in Grafana


example output:

tries=5 interval=30 timeout=5 | starting host-monitor
ip=100.94.190.72 name=important-host | start monitoring
ip=100.94.190.72 name=important-host | checking host
ip=8.8.8.8 name=ISP | start monitoring
ip=8.8.8.8 name=ISP | checking host
ip=8.8.8.8 name=ISP | results 0% packet loss
ip=8.8.8.8 name=ISP | comparing prev=-1 isonline=1
ip=8.8.8.8 name=ISP | state changed, sending to mqtt
ip=8.8.8.8 name=ISP | waiting a bit before next check
ip=100.94.190.72 name=important-host | results 0% packet loss
ip=100.94.190.72 name=important-host | comparing prev=-1 isonline=1
ip=100.94.190.72 name=important-host | state changed, sending to mqtt
ip=100.94.190.72 name=important-host | waiting a bit before next check
ip=8.8.8.8 name=ISP | checking host
ip=100.94.190.72 name=important-host | checking host
ip=8.8.8.8 name=ISP | results 0% packet loss
ip=8.8.8.8 name=ISP | comparing prev=1 isonline=1
ip=8.8.8.8 name=ISP | waiting a bit before next check
ip=100.94.190.72 name=important-host | results 0% packet loss
ip=100.94.190.72 name=important-host | comparing prev=1 isonline=1
ip=100.94.190.72 name=important-host | waiting a bit before next check
...

host previous state prev=-1 on script start is to force it to report the host state to mqtt no matter if its down or up

FROM eclipse-mosquitto:latest # as we need mosquitto_pub
COPY monitor.sh .
CMD ["/bin/sh", "monitor.sh"]
#!/bin/sh
# to kill parallel/background processes when the script is stopped
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
TRIES=5
INTERVAL=30
TIMEOUT=5
function log {
echo $@
}
function monitor {
IP=$1
NAME=$2
if [[ "$IP" == "" ]] ; then
log called with no IP, bailing
return
fi
if [[ "$2" == "" ]] ; then
NAME=$IP
fi
log ip=$IP name=$NAME \| start monitoring
PREVIOUS=-1 # this forces mqtt pub every time the script starts
ISONLINE=1
while [[ true ]] ; do
log ip=$IP name=$NAME \| checking host
PACKETLOSS=$(ping -c $TRIES -W $TIMEOUT $IP | grep "packet loss" | cut -d',' -f3)
log ip=$IP name=$NAME \| results $PACKETLOSS
echo $PACKETLOSS | grep "100%" 1>/dev/null 2>&1
ISONLINE=$?
log ip=$IP name=$NAME \| comparing prev=$PREVIOUS isonline=$ISONLINE
if [[ "$ISONLINE" -ne "$PREVIOUS" ]] ; then
log ip=$IP name=$NAME \| state changed, sending to mqtt
# only sending mqtt messages on state change
mosquitto_pub -t host-monitor/$NAME -m "{\"online\":\"$ISONLINE\"}"
PREVIOUS=$ISONLINE
fi
log ip=$IP name=$NAME \| waiting a bit before next check
sleep $INTERVAL
done
}
log tries=$TRIES interval=$INTERVAL timeout=$TIMEOUT \| starting host-monitor
# list your IPs and hostnames here
monitor 8.8.8.8 www & # use & at the end of line for parallel running
monitor 1.2.3.4 important-vps & # use & at the end of line for parallel running
# ...
monitor 6.7.8.9 my-phone-on-personal-vpn # dont use & on the last line!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment