#!/usr/bin/env bash ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## watch-containers.sh ## ## ## ## Watch running containers and report ## ## any changes to Healthchecks ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## Information ## (don't touch unless you are me) ## NAME="watch-containers.sh" DESCRIPTION="Watch running containers and report any changes to Healthchecks" VERSION="0.2.0" AUTHOR="david@socialnerds.org" LICENSE="MIT" WEBSITE="https://git.socialnerds.org/david/scripts" CHANGELOG=("[2023-10-30][v0.2.0] Complete rewrite based on the new template.sh" "[2022-01-22][v0.1.0] Initial version") ## ## Configuration ## EXECUTABLE="$(basename $0)" LIBRARIES="lib.sh" DEPENDENCIES="basename dirname readlink cat jq docker" REQUIRE_ROOT=1 #TODO: make the cache file configurable with an option flag CACHE_FILE="/var/cache/watch-containers.json" ## ## Functions ## # Print help information function print_help() { printf "%s\n\n%s\n%b\n\n%s\n %-15s %s\n %-15s %s\n %-15s %s\n %-15s %s\n %-15s %s\n" \ "$DESCRIPTION" "Usage:" "$LIB_BOLD$EXECUTABLE [healthchecks-url]$LIB_CLEAR" "Options:" \ "-s, --state" "Save current state to file and exit" \ "-h, --help" "Print help screen and exit" \ "-i, --info" "Print script information and exit" \ "-v, --verbose" "More verbose output" \ "-q, --quiet" "No output except errors (overrides -v)" } ## ## Preflight ## # Load BASH libraries SCRIPT_PATH=$(readlink -f "$0") SCRIPT_DIR=$(dirname "$SCRIPT_PATH") for LIBRARY in $LIBRARIES; do if [[ -r "$SCRIPT_DIR/$LIBRARY" ]]; then #echo "Loading library file [$SCRIPT_DIR/$LIBRARY]" source "$SCRIPT_DIR/$LIBRARY" else echo "Error: Cannot load library file [$SCRIPT_DIR/$LIBRARY]" exit 1 fi done # Check for root privileges if ! lib_amiroot && [[ $REQUIRE_ROOT -eq 1 ]]; then lib_print "!You need to have root privileges" exit 1 fi # Check for dependencies MISSING_COMMANDS=$(lib_missing_commands $DEPENDENCIES) if [[ -n "$MISSING_COMMANDS" ]]; then lib_print "!One or more commands missing [$MISSING_COMMANDS]" lib_print "Try installing them with your package manager" exit 1 fi ## ## Liftoff ## while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in -s|--state) S=1 ;; -h|--help) H=1 ;; -i|--info) I=1 ;; -v|--verbose) V=1 ;; -q|--quiet) Q=1 ;; *) lib_print "!Unknown option [$1]" lib_print "Try --help or -h for available options" exit 1 ;; esac shift done if [[ "$1" == '--' ]]; then shift fi if [[ $I -eq 1 ]]; then lib_print_info exit 0 elif [[ $H -eq 1 ]]; then print_help exit 0 elif [[ $S -eq 1 ]]; then docker ps --no-trunc --format json > $CACHE_FILE lib_print "Saving current state to cache file [$CACHE_FILE]" exit 0 fi # Get containers from cache file if [[ -r "$CACHE_FILE" ]]; then lib_print "?Reading cache from file [$CACHE_FILE]" CACHE=($(cat $CACHE_FILE | jq -r .Names)) else lib_print "!No cache file found [$CACHE_FILE]" exit 1 fi # Get currently running containers CURRENT=($(docker ps --no-trunc --format json | jq -r .Names)) # Iterate through the $CACHE array and check if each element is in the $CURRENT array for I in "${CACHE[@]}"; do if [[ " ${CURRENT[*]} " != *" $I "* ]]; then ONLY_IN_CACHE+=("$I") fi done # Iterate through the $CURRENT array and check if each element is in the CACHE array for I in "${CURRENT[@]}"; do if [[ " ${CACHE[*]} " != *" $I "* ]]; then ONLY_IN_CURRENT+=("$I") fi done # Construct result if [[ -n "${ONLY_IN_CACHE[@]}" ]] && [[ -n "${ONLY_IN_CURRENT[@]}" ]]; then RESULT=$(printf "Missing container(s): %s\nNew container(s): %s\n" "${ONLY_IN_CACHE[@]}" "${ONLY_IN_CURRENT[@]}") elif [[ -n "${ONLY_IN_CACHE[@]}" ]]; then RESULT=$(printf "Missing container(s): %s\n" "${ONLY_IN_CACHE[@]}") elif [[ -n "${ONLY_IN_CURRENT[@]}" ]]; then RESULT=$(printf "New container(s): %s\n" "${ONLY_IN_CURRENT[@]}") else RESULT=$(printf "No changes detected") fi # Post result to Healthchecks if [[ -n "$1" ]] && lib_is_url "$1"; then if [[ "$RESULT" == "No changes detected" ]]; then lib_healthchecks "$1" "$RESULT" else lib_healthchecks "${1%/}/fail" "$RESULT" fi fi # Print result to screen lib_print "$RESULT" ## ## Here be dragons ## exit 0