Last active
March 9, 2021 14:44
-
-
Save jlinoff/132de624716b97392ce5f670cd00a7b3 to your computer and use it in GitHub Desktop.
Bash shell script that runs a simple command (like ping) periodically and tests the results.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Run a simple command every 15 seconds and report whether it passes | |
# or fails. It can be used to check for disconnected hosts (a | |
# heartbeat test). | |
# | |
# The minimum valid interval depends on the time it takes to execute | |
# the command. | |
# | |
# Usage: | |
# $ ./heartbeat.sh CMD # every 15 seconds, forever | |
# $ INTERVAL=60 ./heartbeat.sh CMD # every 60 seconds, forever | |
# $ MAX=15 INTERVAL=60 ./heartbeat.sh CMD # every 60 seconds, for 15 minutes | |
# | |
# Example: | |
# $ ./heartbeat.sh ping -c 10 -i 0.5 my-test-host | |
# $ ./heartbeat.sh ping -c 10 -i 0.5 my-test-host '>' /dev/null | |
# $ INTERVAL=60 ./heartbeat.sh ping -c 10 -i 0.5 my-test-host '>' /dev/null | |
# $ MAX=10 INTERVAL=60 ./heartbeat.sh ping -c 10 -i 0.5 my-test-host '>' /dev/null | |
# | |
: ${INTERVAL:=15} | |
: ${SLEEP:=0.5} | |
: ${MAX:=0} | |
CMD="$@" | |
# For systems like macs that use BSD date. | |
DATE=gdate | |
if ! $DATE --version >/dev/null 2>&1 ; then | |
DATE=date | |
fi | |
# Print a bit of status information. | |
printf 'Cmd : %s\n' "$CMD" | |
printf 'Interval : %d\n' $INTERVAL | |
printf 'Sleep : %s\n' $SLEEP | |
printf 'Max : %d\n' $MAX | |
if [ -z "$CMD" ] ; then | |
echo -e "\033[31mERROR: A command must be specified!\033[0m" | |
exit 1 | |
fi | |
if ! $DATE --version >/dev/null 2>&1 ; then | |
echo -e "\033[31mERROR:$LINENO: gnu compatible date program not found \033[0m" | |
fi | |
# Iterate forever, keep track of the number of times the test was | |
# performed in COUNT. | |
COUNT=0 | |
START=0 | |
while (( 1 )) ; do | |
SECONDS=$($DATE +'%s') | |
# Tests occur when the modulus is 0. | |
if (( (SECONDS % INTERVAL) == 0 )) ; then | |
(( COUNT++ )) | |
echo -ne "\033[1m" | |
printf '%5d %d ' $COUNT $MAX | |
# Print the time elapsed first. | |
# The first time through, print 00:00:00. | |
CURR=$($DATE +'%s') | |
(( START == 0 )) && START=$CURR | |
ELAPSED=$(( CURR - START )) | |
ELAPSED_STR=$($DATE -ud "@$ELAPSED" +'%H:%M:%S' | tr -d '\n') | |
printf '%s ' $ELAPSED_STR | |
# Print the current date/time with seconds resolution. | |
CURR_DATE=$($DATE -Iseconds | tr -d '\n') | |
# Print and run the command. | |
echo -n "$CURR_DATE - $CMD" | |
echo -e "\033[0m" | |
# Use eval so that users can specify commands like: | |
# ./tester/.sh ping -c 5 -i 0.5 HOST '>' /dev/null | |
eval "$CMD" | |
# Capture the exit status and report the current status. | |
EXIT_CODE=$? | |
if (( EXIT_CODE )) ; then | |
echo -e "\033[31mSTATUS: FAILED $EXIT_CODE $COUNT $ELAPSED_STR $CURR_DATE\033[0m" | |
else | |
echo -e "\033[32mSTATUS: PASSED $EXIT_CODE $COUNT $ELAPSED_STR $CURR_DATE\033[0m" | |
fi | |
# Exit if the max threshold is exceeded. | |
# If MAX < 1, then the loop never finishes. | |
if (( COUNT >= MAX )) ; then | |
break | |
fi | |
# Cross the modulus threshold to avoid running the command | |
# more than once in the same time interval. | |
SECONDS=$($DATE +'%s') | |
while (( (SECONDS % INTERVAL) == 0 )) ; do | |
sleep 0.1 | |
SECONDS=$($DATE +'%s') | |
done | |
fi | |
# Pause for a bit to avoid continuous date testing. | |
sleep $SLEEP | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment