mirror of
https://github.com/mag37/dockcheck.git
synced 2026-03-02 15:10:32 +01:00
Merge 37f81de556 into 7785e869d3
This commit is contained in:
commit
2028d75c9e
4 changed files with 293 additions and 61 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -8,4 +8,11 @@ regctl
|
||||||
# ignore snooze file
|
# ignore snooze file
|
||||||
snooze.list
|
snooze.list
|
||||||
# ignore updates file
|
# ignore updates file
|
||||||
updates_available.txt
|
updates_available.txt
|
||||||
|
# ignore user compose files
|
||||||
|
compose.yaml
|
||||||
|
compose.yml
|
||||||
|
docker-compose.yaml
|
||||||
|
docker-compose.yml
|
||||||
|
# ignore log directory
|
||||||
|
/log/
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@
|
||||||
# DISABLE_DOCKCHECK_NOTIFICATION=false
|
# DISABLE_DOCKCHECK_NOTIFICATION=false
|
||||||
## Uncomment and set to true to disable notifications when notify scripts themselves have updates.
|
## Uncomment and set to true to disable notifications when notify scripts themselves have updates.
|
||||||
# DISABLE_NOTIFY_NOTIFICATION=false
|
# DISABLE_NOTIFY_NOTIFICATION=false
|
||||||
|
## Uncomment and set to true to enable a final action summary notification.
|
||||||
|
# ENABLE_SUMMARY_NOTIFICATION=false
|
||||||
#
|
#
|
||||||
## Apprise configuration variables. Set APPRISE_PAYLOAD to make a CLI call or set APPRISE_URL to make an API request instead.
|
## Apprise configuration variables. Set APPRISE_PAYLOAD to make a CLI call or set APPRISE_URL to make an API request instead.
|
||||||
# APPRISE_PAYLOAD='mailto://myemail:mypass@gmail.com
|
# APPRISE_PAYLOAD='mailto://myemail:mypass@gmail.com
|
||||||
|
|
|
||||||
292
dockcheck.sh
292
dockcheck.sh
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
VERSION="v0.7.6"
|
VERSION="v0.7.7"
|
||||||
# ChangeNotes: Bugfixes and sanitation. Cleanup of default.config - migrate settings manually (optional).
|
# ChangeNotes: Start/restart stacks once. Skip failed pulls. Final summary notification.
|
||||||
Github="https://github.com/mag37/dockcheck"
|
Github="https://github.com/mag37/dockcheck"
|
||||||
RawUrl="https://raw.githubusercontent.com/mag37/dockcheck/main/dockcheck.sh"
|
RawUrl="https://raw.githubusercontent.com/mag37/dockcheck/main/dockcheck.sh"
|
||||||
|
|
||||||
|
|
@ -13,20 +13,6 @@ ScriptArgs=( "$@" )
|
||||||
ScriptPath="$(readlink -f "$0")"
|
ScriptPath="$(readlink -f "$0")"
|
||||||
ScriptWorkDir="$(dirname "$ScriptPath")"
|
ScriptWorkDir="$(dirname "$ScriptPath")"
|
||||||
|
|
||||||
# Source helper functions
|
|
||||||
source_if_exists_or_fail() {
|
|
||||||
if [[ -s "$1" ]]; then
|
|
||||||
source "$1"
|
|
||||||
[[ "${DisplaySourcedFiles:-false}" == true ]] && echo " * sourced config: ${1}"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# User customizable defaults
|
|
||||||
source_if_exists_or_fail "${HOME}/.config/dockcheck.config" || source_if_exists_or_fail "${ScriptWorkDir}/dockcheck.config"
|
|
||||||
|
|
||||||
# Help Function
|
# Help Function
|
||||||
Help() {
|
Help() {
|
||||||
echo "Syntax: dockcheck.sh [OPTION] [comma separated names to include]"
|
echo "Syntax: dockcheck.sh [OPTION] [comma separated names to include]"
|
||||||
|
|
@ -49,6 +35,7 @@ Help() {
|
||||||
echo "-M Prints custom releasenote urls as markdown (requires template support)."
|
echo "-M Prints custom releasenote urls as markdown (requires template support)."
|
||||||
echo "-n No updates; only checking availability without interaction."
|
echo "-n No updates; only checking availability without interaction."
|
||||||
echo "-p Auto-prune dangling images after update."
|
echo "-p Auto-prune dangling images after update."
|
||||||
|
echo "-q Quiet mode. Minmal text output. Does not effect file based logging, if enabled."
|
||||||
echo "-r Allow checking/updating images created by 'docker run', containers need to be recreated manually."
|
echo "-r Allow checking/updating images created by 'docker run', containers need to be recreated manually."
|
||||||
echo "-R Skip container recreation after pulling images."
|
echo "-R Skip container recreation after pulling images."
|
||||||
echo "-s Include stopped containers in the check. (Logic: docker ps -a)."
|
echo "-s Include stopped containers in the check. (Logic: docker ps -a)."
|
||||||
|
|
@ -60,12 +47,51 @@ Help() {
|
||||||
echo "Project source: $Github"
|
echo "Project source: $Github"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Print current backups function
|
while getopts "ayb:BfFhiIlmMnpqrsuvc:e:d:t:x:R" options; do
|
||||||
print_backups() {
|
case "${options}" in
|
||||||
printf "\n%b---%b Currently backed up images %b---%b\n\n" "$c_teal" "$c_blue" "$c_teal" "$c_reset"
|
a|y) AutoMode=true ;;
|
||||||
docker images | sed -ne '/^REPOSITORY/p' -ne '/^dockcheck/p'
|
b) BackupForDays="${OPTARG}" ;;
|
||||||
|
B) PrintBackups=true ;;
|
||||||
|
c) CollectorTextFileDirectory="${OPTARG}" ;;
|
||||||
|
d) DaysOld=${OPTARG} ;;
|
||||||
|
e) Exclude=${OPTARG} ;;
|
||||||
|
f) ForceRestartStacks=true ;;
|
||||||
|
F) OnlySpecific=true ;;
|
||||||
|
i) Notify=true ;;
|
||||||
|
I) PrintReleaseURL=true ;;
|
||||||
|
l) OnlyLabel=true ;;
|
||||||
|
m) MonoMode=true ;;
|
||||||
|
M) PrintMarkdownURL=true ;;
|
||||||
|
n) DontUpdate=true; AutoMode=true;;
|
||||||
|
p) AutoPrune=true ;;
|
||||||
|
q) Quiet=true ;;
|
||||||
|
R) SkipRecreate=true ;;
|
||||||
|
r) DRunUp=true ;;
|
||||||
|
s) Stopped="-a" ;;
|
||||||
|
t) Timeout="${OPTARG}" ;;
|
||||||
|
u) AutoSelfUpdate=true ;;
|
||||||
|
v) printf "%s\n" "$VERSION"; exit 0 ;;
|
||||||
|
x) MaxAsync=${OPTARG} ;;
|
||||||
|
h|*) Help; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
|
# Source helper function
|
||||||
|
source_if_exists_or_fail() {
|
||||||
|
if [[ -s "$1" ]]; then
|
||||||
|
source "$1"
|
||||||
|
# DisplaySourcedFiles used for debugging purposes only
|
||||||
|
[[ "${DisplaySourcedFiles:-false}" == true ]] && echo " * sourced config: ${1}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# User customizable defaults
|
||||||
|
source_if_exists_or_fail "${HOME}/.config/dockcheck.config" || source_if_exists_or_fail "${ScriptWorkDir}/dockcheck.config"
|
||||||
|
|
||||||
# Initialise variables
|
# Initialise variables
|
||||||
Timeout=${Timeout:-10}
|
Timeout=${Timeout:-10}
|
||||||
MaxAsync=${MaxAsync:-1}
|
MaxAsync=${MaxAsync:-1}
|
||||||
|
|
@ -89,12 +115,17 @@ BackupForDays=${BackupForDays:-}
|
||||||
OnlySpecific=${OnlySpecific:-false}
|
OnlySpecific=${OnlySpecific:-false}
|
||||||
SpecificContainer=${SpecificContainer:-""}
|
SpecificContainer=${SpecificContainer:-""}
|
||||||
SkipRecreate=${SkipRecreate:-false}
|
SkipRecreate=${SkipRecreate:-false}
|
||||||
|
LogToFile=${LogToFile:-false}
|
||||||
|
LogDaysToKeep=${LogDaysToKeep:-14}
|
||||||
|
LOG_LEVEL=${LOG_LEVEL:-INFO}
|
||||||
|
Quiet=${Quiet:-false}
|
||||||
Excludes=()
|
Excludes=()
|
||||||
GotUpdates=()
|
GotUpdates=()
|
||||||
NoUpdates=()
|
NoUpdates=()
|
||||||
GotErrors=()
|
GotErrors=()
|
||||||
SelectedUpdates=()
|
SelectedUpdates=()
|
||||||
CurlArgs="--retry ${CurlRetryCount:=3} --retry-delay ${CurlRetryDelay:=1} --connect-timeout ${CurlConnectTimeout:=5} -sf"
|
CurlArgs="--retry ${CurlRetryCount:=3} --retry-delay ${CurlRetryDelay:=1} --connect-timeout ${CurlConnectTimeout:=5} -sf"
|
||||||
|
LatestOutput=""
|
||||||
regbin=""
|
regbin=""
|
||||||
jqbin=""
|
jqbin=""
|
||||||
|
|
||||||
|
|
@ -110,34 +141,141 @@ c_reset="\033[0m"
|
||||||
RunTimestamp=$(date +'%Y-%m-%d_%H%M')
|
RunTimestamp=$(date +'%Y-%m-%d_%H%M')
|
||||||
RunEpoch=$(date +'%s')
|
RunEpoch=$(date +'%s')
|
||||||
|
|
||||||
while getopts "ayb:BfFhiIlmMnprsuvc:e:d:t:x:R" options; do
|
# Duplicate stdout file descriptor for command output purposes
|
||||||
case "${options}" in
|
exec 5>&1
|
||||||
a|y) AutoMode=true ;;
|
|
||||||
b) BackupForDays="${OPTARG}" ;;
|
# Exec helper function
|
||||||
B) print_backups; exit 0 ;;
|
# Executes the command and arguments passed while both outputting and capturing output to the LatestOutput variable while maintaining return status code
|
||||||
c) CollectorTextFileDirectory="${OPTARG}" ;;
|
exec_command() {
|
||||||
d) DaysOld=${OPTARG} ;;
|
LatestOutput=""
|
||||||
e) Exclude=${OPTARG} ;;
|
if [[ "${Quiet}" == "false" ]]; then
|
||||||
f) ForceRestartStacks=true ;;
|
LatestOutput=$("$@" | tee >(cat - >&5))
|
||||||
F) OnlySpecific=true ;;
|
else
|
||||||
i) Notify=true ;;
|
LatestOutput=$("$@")
|
||||||
I) PrintReleaseURL=true ;;
|
fi
|
||||||
l) OnlyLabel=true ;;
|
|
||||||
m) MonoMode=true ;;
|
return $?
|
||||||
M) PrintMarkdownURL=true ;;
|
}
|
||||||
n) DontUpdate=true; AutoMode=true;;
|
|
||||||
p) AutoPrune=true ;;
|
# File Log Path
|
||||||
R) SkipRecreate=true ;;
|
LogFile="${ScriptWorkDir}/log/${RunTimestamp}.log"
|
||||||
r) DRunUp=true ;;
|
[[ "${LogToFile}" == "true" ]] && mkdir -p $(dirname "${LogFile}")
|
||||||
s) Stopped="-a" ;;
|
|
||||||
t) Timeout="${OPTARG}" ;;
|
# Assign log level to number (based on OpenTelemetry log severity values)
|
||||||
u) AutoSelfUpdate=true ;;
|
# Acceptable values are recognized strings or an integer between 0 and 24
|
||||||
v) printf "%s\n" "$VERSION"; exit 0 ;;
|
log_severity() {
|
||||||
x) MaxAsync=${OPTARG} ;;
|
local loglevel="$1"
|
||||||
h|*) Help; exit 2 ;;
|
local levelnum=0
|
||||||
|
|
||||||
|
case "${loglevel}" in
|
||||||
|
TRACE)
|
||||||
|
levelnum=1
|
||||||
|
;;
|
||||||
|
DEBUG)
|
||||||
|
levelnum=5
|
||||||
|
;;
|
||||||
|
INFO)
|
||||||
|
levelnum=9
|
||||||
|
;;
|
||||||
|
WARN)
|
||||||
|
levelnum=13
|
||||||
|
;;
|
||||||
|
ERROR)
|
||||||
|
levelnum=17
|
||||||
|
;;
|
||||||
|
FATAL)
|
||||||
|
levelnum=21
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ "${loglevel}" =~ ^[0-9]+$ ]]; then
|
||||||
|
if [[ $loglevel -ge 0 ]] && [[ $loglevel -le 24 ]]; then
|
||||||
|
levelnum=${loglevel}
|
||||||
|
else
|
||||||
|
levelnum=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
levelnum=0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
|
||||||
shift "$((OPTIND-1))"
|
echo ${levelnum}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_LEVEL_NUM=$(log_severity $LOG_LEVEL)
|
||||||
|
|
||||||
|
# Logger helper functions
|
||||||
|
# Log and print out. For script managed output.
|
||||||
|
log_print() {
|
||||||
|
local logvar="$1"
|
||||||
|
local loglevel="$2"
|
||||||
|
local format="$3"
|
||||||
|
shift 3
|
||||||
|
|
||||||
|
levelnum=$(log_severity ${loglevel})
|
||||||
|
|
||||||
|
local buffer=""
|
||||||
|
|
||||||
|
if [[ $levelnum -ge $LOG_LEVEL_NUM ]]; then
|
||||||
|
# Don't print if in quiet mode
|
||||||
|
[[ "$Quiet" == "false" ]] && printf "${format}" "$@"
|
||||||
|
# Also log to buffer and file if configured
|
||||||
|
log "$logvar" "$loglevel" "$format" "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Log only. For use with command executions that already send output or when no stdout is desired.
|
||||||
|
log() {
|
||||||
|
local logvar="$1"
|
||||||
|
local loglevel="$2"
|
||||||
|
local format="$3"
|
||||||
|
shift 3
|
||||||
|
|
||||||
|
levelnum=$(log_severity ${loglevel})
|
||||||
|
|
||||||
|
local buffer=""
|
||||||
|
|
||||||
|
if [[ $levelnum -ge $LOG_LEVEL_NUM ]]; then
|
||||||
|
printf -v buffer "${format}" "$@" # store in buffer
|
||||||
|
|
||||||
|
# optionally output to file if enabled
|
||||||
|
# Replace all newlines with literal \n and remove all color codes
|
||||||
|
[[ "${LogToFile}" == "true" ]] && \
|
||||||
|
{ printf "[%(%Y-%m-%d %H:%M:%S)T] [%-5s] ${format}" -1 "$loglevel" "$@" | \
|
||||||
|
awk 'NR > 1 {printf "%s\\n", prev} {prev = $0} END {printf "%s\n", prev}' | \
|
||||||
|
sed -r 's/\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g'; } >> "${LogFile}"
|
||||||
|
|
||||||
|
declare -n out_array="${logvar}"
|
||||||
|
out_array+=("${buffer}")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log_cleanup() {
|
||||||
|
find "$(dirname "${LogFile}")" -type f -name '*.log' -mtime +${LogDaysToKeep} -exec rm {} \;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_buffer() {
|
||||||
|
declare -n buffer="$1"
|
||||||
|
local BufToString
|
||||||
|
|
||||||
|
if [[ -n "${buffer:-}" ]] && [[ "${#buffer[@]}" -gt 0 ]]; then
|
||||||
|
if [[ "${2:-}" != "notifyonly" ]]; then
|
||||||
|
BufToString=$( printf '%s' "${buffer[@]}" )
|
||||||
|
echo "${BufToString}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${2:-}" == "notify" ]] || [[ "${2:-}" == "notifyonly" ]]; then
|
||||||
|
exec_if_exists_or_fail send_buffer_notification $1 ${3:-} || printf "Could not source buffer notification function.\n";
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print current backups function
|
||||||
|
print_backups() {
|
||||||
|
printf "\n%b---%b Currently backed up images %b---%b\n\n" "$c_teal" "$c_blue" "$c_teal" "$c_reset"
|
||||||
|
docker images --format table | sed -ne '/^REPOSITORY/p' -ne '/^dockcheck/p'
|
||||||
|
}
|
||||||
|
[[ "${PrintBackups:-false}" == "true" ]] && { exec_command print_backups; log backupbuf INFO "$LatestOutput"; exit 0; }
|
||||||
|
|
||||||
# Set $1 to a variable for name filtering later, rewriting if multiple
|
# Set $1 to a variable for name filtering later, rewriting if multiple
|
||||||
SearchName="${1:-}"
|
SearchName="${1:-}"
|
||||||
|
|
@ -406,7 +544,7 @@ list_options() {
|
||||||
# Version check & initiate self update
|
# Version check & initiate self update
|
||||||
if [[ "$LatestSnippet" != "undefined" ]]; then
|
if [[ "$LatestSnippet" != "undefined" ]]; then
|
||||||
if [[ "$VERSION" != "$LatestRelease" ]]; then
|
if [[ "$VERSION" != "$LatestRelease" ]]; then
|
||||||
printf "New version available! %b%s%b ⇒ %b%s%b \n Change Notes: %s \n" "$c_yellow" "$VERSION" "$c_reset" "$c_green" "$LatestRelease" "$c_reset" "$LatestChanges"
|
log_print mainbuf INFO "New version available! %b%s%b ⇒ %b%s%b \n Change Notes: %s \n" "$c_yellow" "$VERSION" "$c_reset" "$c_green" "$LatestRelease" "$c_reset" "$LatestChanges"
|
||||||
if [[ "$AutoMode" == false ]]; then
|
if [[ "$AutoMode" == false ]]; then
|
||||||
read -r -p "Would you like to update? y/[n]: " SelfUpdate
|
read -r -p "Would you like to update? y/[n]: " SelfUpdate
|
||||||
[[ "$SelfUpdate" =~ [yY] ]] && self_update
|
[[ "$SelfUpdate" =~ [yY] ]] && self_update
|
||||||
|
|
@ -516,7 +654,7 @@ fi
|
||||||
# Asynchronously check the image-hash of every running container VS the registry
|
# Asynchronously check the image-hash of every running container VS the registry
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
((RegCheckQue+=1))
|
((RegCheckQue+=1))
|
||||||
if [[ "$MonoMode" == false ]]; then progress_bar "$RegCheckQue" "$ContCount"; fi
|
if [[ "$MonoMode" == false ]]; then exec_command progress_bar "$RegCheckQue" "$ContCount"; fi
|
||||||
|
|
||||||
Got=${line%% *} # Extracts the first word (NoUpdates, GotUpdates, GotErrors)
|
Got=${line%% *} # Extracts the first word (NoUpdates, GotUpdates, GotErrors)
|
||||||
item=${line#* }
|
item=${line#* }
|
||||||
|
|
@ -610,17 +748,23 @@ if [[ -n "${GotUpdates:-}" ]]; then
|
||||||
if [[ "$DRunUp" == true ]]; then
|
if [[ "$DRunUp" == true ]]; then
|
||||||
docker pull "$ContImage"
|
docker pull "$ContImage"
|
||||||
printf "%s\n" "$i got a new image downloaded, rebuild manually with preferred 'docker run'-parameters"
|
printf "%s\n" "$i got a new image downloaded, rebuild manually with preferred 'docker run'-parameters"
|
||||||
|
log actionbuf INFO "Pull $ContImage;Success;Manual rebuild with 'docker run'-parameters required"
|
||||||
else
|
else
|
||||||
printf "\n%b%s%b has no compose labels, probably started with docker run - %bskipping%b\n\n" "$c_yellow" "$i" "$c_reset" "$c_yellow" "$c_reset"
|
printf "\n%b%s%b has no compose labels, probably started with docker run - %bskipping%b\n\n" "$c_yellow" "$i" "$c_reset" "$c_yellow" "$c_reset"
|
||||||
|
log actionbuf INFO "Pull $ContImage;Skipped;Started with docker run"
|
||||||
fi
|
fi
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if docker pull "$ContImage"; then
|
if exec_command docker pull "$ContImage"; then
|
||||||
# Removal of the <none>-tag image left behind from backup
|
# Removal of the <none>-tag image left behind from backup
|
||||||
if [[ ! -z "${ContRepoDigests:-}" ]] && [[ -n "${BackupForDays:-}" ]]; then docker rmi "$ContRepoDigests"; fi
|
if [[ ! -z "${ContRepoDigests:-}" ]] && [[ -n "${BackupForDays:-}" ]]; then docker rmi "$ContRepoDigests"; fi
|
||||||
|
SuccessfulUpdates+=("$i")
|
||||||
|
log actionbuf INFO "Pull $ContImage;Success"
|
||||||
else
|
else
|
||||||
printf "\n%bDocker error, exiting!%b\n" "$c_red" "$c_reset" ; exit 1
|
printf "\n%bError pulling update for %S. Skipping. %b\n" "$c_red" "$i" "$c_reset"
|
||||||
|
FailedUpdates+=("$i")
|
||||||
|
log actionbuf ERROR "Pull $ContImage;Error"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
@ -630,8 +774,9 @@ if [[ -n "${GotUpdates:-}" ]]; then
|
||||||
printf "%bSkipping container recreation due to -R.%b\n" "$c_yellow" "$c_reset"
|
printf "%bSkipping container recreation due to -R.%b\n" "$c_yellow" "$c_reset"
|
||||||
else
|
else
|
||||||
printf "%bRecreating updated containers.%b\n" "$c_blue" "$c_reset"
|
printf "%bRecreating updated containers.%b\n" "$c_blue" "$c_reset"
|
||||||
|
RestartedStacks=()
|
||||||
CurrentQue=0
|
CurrentQue=0
|
||||||
for i in "${SelectedUpdates[@]}"; do
|
for i in "${SuccessfulUpdates[@]}"; do
|
||||||
((CurrentQue+=1))
|
((CurrentQue+=1))
|
||||||
unset CompleteConfs
|
unset CompleteConfs
|
||||||
# Extract labels and metadata
|
# Extract labels and metadata
|
||||||
|
|
@ -656,14 +801,15 @@ if [[ -n "${GotUpdates:-}" ]]; then
|
||||||
printf "\n%bNow recreating (%s/%s): %b%s%b\n" "$c_teal" "$CurrentQue" "$NumberofUpdates" "$c_blue" "$i" "$c_reset"
|
printf "\n%bNow recreating (%s/%s): %b%s%b\n" "$c_teal" "$CurrentQue" "$NumberofUpdates" "$c_blue" "$i" "$c_reset"
|
||||||
else
|
else
|
||||||
printf "\n%bSkipping recreation of %b%s%b as it's not running.%b\n" "$c_yellow" "$c_blue" "$i" "$c_yellow" "$c_reset"
|
printf "\n%bSkipping recreation of %b%s%b as it's not running.%b\n" "$c_yellow" "$c_blue" "$i" "$c_yellow" "$c_reset"
|
||||||
|
log actionbuf INFO "Recreate $i;Skipped;Not Running"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Checking if compose-values are empty - hence started with docker run
|
# Checking if compose-values are empty - hence started with docker run
|
||||||
[[ -z "$ContPath" ]] && { echo "Not a compose container, skipping."; continue; }
|
[[ -z "$ContPath" ]] && { echo "Not a compose container, skipping."; log actionbuf INFO "Recreate $i;Skipped;Not compose" ; continue; }
|
||||||
|
|
||||||
# cd to the compose-file directory to account for people who use relative volumes
|
# cd to the compose-file directory to account for people who use relative volumes
|
||||||
cd "$ContPath" || { printf "\n%bPath error - skipping%b %s" "$c_red" "$c_reset" "$i"; continue; }
|
cd "$ContPath" || { printf "\n%bPath error - skipping%b %s" "$c_red" "$c_reset" "$i"; log actionbuf INFO "Recreate $i;Skipped;Path error" ; continue; }
|
||||||
# Reformatting path + multi compose
|
# Reformatting path + multi compose
|
||||||
if [[ $ContConfigFile == '/'* ]]; then
|
if [[ $ContConfigFile == '/'* ]]; then
|
||||||
CompleteConfs=$(for conf in ${ContConfigFile//,/ }; do printf -- "-f %s " "$conf"; done)
|
CompleteConfs=$(for conf in ${ContConfigFile//,/ }; do printf -- "-f %s " "$conf"; done)
|
||||||
|
|
@ -678,9 +824,34 @@ if [[ -n "${GotUpdates:-}" ]]; then
|
||||||
|
|
||||||
# Check if the whole stack should be restarted
|
# Check if the whole stack should be restarted
|
||||||
if [[ "$ContRestartStack" == true ]] || [[ "$ForceRestartStacks" == true ]]; then
|
if [[ "$ContRestartStack" == true ]] || [[ "$ForceRestartStacks" == true ]]; then
|
||||||
${DockerBin} ${CompleteConfs} stop; ${DockerBin} ${CompleteConfs} ${ContEnvs} up -d || { printf "\n%bDocker error, exiting!%b\n" "$c_red" "$c_reset" ; exit 1; }
|
# Restart if compose path has not already been restarted
|
||||||
|
if [[ "${RestartedStacks[@]}" != *"$ContPath"* ]]; then # Restart if stack has not already been restarted
|
||||||
|
if ${DockerBin} ${CompleteConfs} stop; ${DockerBin} ${CompleteConfs} ${ContEnvs} up -d; then
|
||||||
|
log actionbuf INFO "Recreate $i;Success;Full stack restart"
|
||||||
|
RestartedStacks+=("$ContPath")
|
||||||
|
else
|
||||||
|
printf "\n%bFailed to recreate $i, skipping.%b\n" "$c_red" "$c_reset"
|
||||||
|
log actionbuf INFO "Recreate $i;Error;Failed to start stack"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf "%bStack already restarted. Skipping.%b\n" "$c_yellow" "$c_reset"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
${DockerBin} ${CompleteConfs} ${ContEnvs} up -d ${SpecificContainer} || { printf "\n%bDocker error, exiting!%b\n" "$c_red" "$c_reset" ; exit 1; }
|
# Restart if compose path has not already been restarted or specific container(s) are configured to be restarted individually
|
||||||
|
if [[ "${RestartedStacks[@]}" != *"$ContPath"* ]] || [[ -n "${SpecificContainer:-}" ]]; then
|
||||||
|
if ${DockerBin} ${CompleteConfs} ${ContEnvs} up -d ${SpecificContainer}; then
|
||||||
|
log actionbuf INFO "Recreate $i;Success;${SpecificContainer:-Stack}"
|
||||||
|
# Consider stack restarted only if specific container is not set
|
||||||
|
if [[ -z "${SpecificContainer:-}" ]]; then
|
||||||
|
RestartedStacks+=("$ContPath")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf "\n%bFailed to recreate $i, skipping.%b\n" "$c_red" "$c_reset"
|
||||||
|
log actionbuf INFO "Recreate $i;Error;Failed to start ${SpecificContainer:-Stack}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf "%bStack already restarted. Skipping.%b\n" "$c_yellow" "$c_reset"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
@ -689,7 +860,7 @@ if [[ -n "${GotUpdates:-}" ]]; then
|
||||||
# Trigger pruning only when backup-function is not used
|
# Trigger pruning only when backup-function is not used
|
||||||
if [[ -z "${BackupForDays:-}" ]]; then
|
if [[ -z "${BackupForDays:-}" ]]; then
|
||||||
if [[ "$AutoPrune" == false ]] && [[ "$AutoMode" == false ]]; then printf "\n"; read -rep "Would you like to prune all dangling images? y/[n]: " AutoPrune; fi
|
if [[ "$AutoPrune" == false ]] && [[ "$AutoMode" == false ]]; then printf "\n"; read -rep "Would you like to prune all dangling images? y/[n]: " AutoPrune; fi
|
||||||
if [[ "$AutoPrune" == true ]] || [[ "$AutoPrune" =~ [yY] ]]; then printf "\nAuto pruning.."; docker image prune -f; fi
|
if [[ "$AutoPrune" == true ]] || [[ "$AutoPrune" =~ [yY] ]]; then printf "\nAuto pruning.."; docker image prune -f && log actionbuf INFO "Prune images;Success"; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
@ -702,4 +873,11 @@ fi
|
||||||
# Clean up old backup image tags if -b is used
|
# Clean up old backup image tags if -b is used
|
||||||
[[ -n "${BackupForDays:-}" ]] && remove_backups
|
[[ -n "${BackupForDays:-}" ]] && remove_backups
|
||||||
|
|
||||||
|
# Send final summary notification if enabled
|
||||||
|
[[ "${Notify}" == true ]] && [[ "${ENABLE_SUMMARY_NOTIFICATION:-}" == true ]] && print_buffer actionbuf notifyonly Actions;
|
||||||
|
|
||||||
|
if [[ -d $(dirname "${LogFile}") ]]; then
|
||||||
|
log_cleanup
|
||||||
|
fi
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
NOTIFY_V2_VERSION="v0.7"
|
NOTIFY_V2_VERSION="v0.8"
|
||||||
#
|
#
|
||||||
# If migrating from an older notify template, remove your existing notify.sh file.
|
# If migrating from an older notify template, remove your existing notify.sh file.
|
||||||
# Leave (or place) this file in the "notify_templates" subdirectory within the same directory as the main dockcheck.sh script.
|
# Leave (or place) this file in the "notify_templates" subdirectory within the same directory as the main dockcheck.sh script.
|
||||||
|
|
@ -180,7 +180,9 @@ format_output() {
|
||||||
local FormattedTextTemplate="$3"
|
local FormattedTextTemplate="$3"
|
||||||
local tempcsv=""
|
local tempcsv=""
|
||||||
|
|
||||||
if [[ ! "${UpdateType}" == "dockcheck_update" ]]; then
|
if [[ "${UpdateType}" == "buffer" ]]; then
|
||||||
|
tempcsv="${UpdToString//;/,}"
|
||||||
|
elif [[ ! "${UpdateType}" == "dockcheck_update" ]]; then
|
||||||
tempcsv="${UpdToString// -> /,}"
|
tempcsv="${UpdToString// -> /,}"
|
||||||
tempcsv="${tempcsv//.sh /.sh,}"
|
tempcsv="${tempcsv//.sh /.sh,}"
|
||||||
else
|
else
|
||||||
|
|
@ -194,12 +196,17 @@ format_output() {
|
||||||
FormattedOutput="${tempcsv}"
|
FormattedOutput="${tempcsv}"
|
||||||
fi
|
fi
|
||||||
elif [[ "${OutputFormat}" == "json" ]]; then
|
elif [[ "${OutputFormat}" == "json" ]]; then
|
||||||
if [[ -z "${UpdToString}" ]]; then
|
if [[ "${UpdateType}" == "buffer" ]] && [[ -z "${UpdToString}" ]]; then
|
||||||
|
FormattedOutput='{"buffer": []}'
|
||||||
|
elif [[ -z "${UpdToString}" ]]; then
|
||||||
FormattedOutput='{"updates": []}'
|
FormattedOutput='{"updates": []}'
|
||||||
else
|
else
|
||||||
if [[ "${UpdateType}" == "container_update" ]]; then
|
if [[ "${UpdateType}" == "container_update" ]]; then
|
||||||
# container updates case
|
# container updates case
|
||||||
FormattedOutput=$(jq --compact-output --null-input --arg updates "${tempcsv}" '($updates | split("\\n")) | map(split(",")) | {"updates": map({"container_name": .[0], "release_notes": .[1]})} | del(..|nulls)')
|
FormattedOutput=$(jq --compact-output --null-input --arg updates "${tempcsv}" '($updates | split("\\n")) | map(split(",")) | {"updates": map({"container_name": .[0], "release_notes": .[1]})} | del(..|nulls)')
|
||||||
|
elif [[ "${UpdateType}" == "buffer" ]]; then
|
||||||
|
# buffer notification case
|
||||||
|
FormattedOutput=$(jq --compact-output --null-input --arg buffer "${tempcsv}" '($buffer | split("\\n")) | map(split(",")) | {"events": map({"event": .[0], "result": .[1], "description": .[2]})} | del(..|nulls)')
|
||||||
elif [[ "${UpdateType}" == "notify_update" ]]; then
|
elif [[ "${UpdateType}" == "notify_update" ]]; then
|
||||||
# script updates case
|
# script updates case
|
||||||
FormattedOutput=$(jq --compact-output --null-input --arg updates "${tempcsv}" '($updates | split("\\n")) | map(split(",")) | {"updates": map({"script_name": .[0], "installed_version": .[1], "latest_version": .[2]})}')
|
FormattedOutput=$(jq --compact-output --null-input --arg updates "${tempcsv}" '($updates | split("\\n")) | map(split(",")) | {"updates": map({"script_name": .[0], "installed_version": .[1], "latest_version": .[2]})}')
|
||||||
|
|
@ -216,6 +223,8 @@ format_output() {
|
||||||
else
|
else
|
||||||
if [[ "${UpdateType}" == "container_update" ]]; then
|
if [[ "${UpdateType}" == "container_update" ]]; then
|
||||||
FormattedOutput="${FormattedTextTemplate/<insert_text_cu>/${UpdToString}}"
|
FormattedOutput="${FormattedTextTemplate/<insert_text_cu>/${UpdToString}}"
|
||||||
|
elif [[ "${UpdateType}" == "buffer" ]]; then
|
||||||
|
FormattedOutput="${FormattedTextTemplate/<insert_text_sn>/${UpdToString}}"
|
||||||
elif [[ "${UpdateType}" == "notify_update" ]]; then
|
elif [[ "${UpdateType}" == "notify_update" ]]; then
|
||||||
FormattedOutput="${FormattedTextTemplate/<insert_text_nu>/${UpdToString}}"
|
FormattedOutput="${FormattedTextTemplate/<insert_text_nu>/${UpdToString}}"
|
||||||
elif [[ "${UpdateType}" == "dockcheck_update" ]]; then
|
elif [[ "${UpdateType}" == "dockcheck_update" ]]; then
|
||||||
|
|
@ -301,6 +310,42 @@ send_notification() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
### Set notification settings in dockcheck.config
|
||||||
|
### to send buffer notifications
|
||||||
|
send_buffer_notification() {
|
||||||
|
Notified="false"
|
||||||
|
|
||||||
|
declare -n buffer="$1"
|
||||||
|
|
||||||
|
MessageTitle="$FromHost - ${2:-$1}"
|
||||||
|
|
||||||
|
UpdToString=$( printf '%s' "${buffer[@]}" )
|
||||||
|
|
||||||
|
for channel in "${enabled_notify_channels[@]}"; do
|
||||||
|
local SkipNotification=$(skip_notification "${channel}" "1" "buffer")
|
||||||
|
if [[ "${SkipNotification}" == "false" ]]; then
|
||||||
|
local template=$(get_channel_template "${channel}")
|
||||||
|
|
||||||
|
# Formats UpdToString variable per channel settings
|
||||||
|
format_output "buffer" "$(output_format "${channel}")" "🐋 ${2:-Events} on $FromHost:\n<insert_text_sn>\n"
|
||||||
|
|
||||||
|
# Setting the MessageBody variable here.
|
||||||
|
printf -v MessageBody "${FormattedOutput}"
|
||||||
|
|
||||||
|
printf "\nSending ${channel} buffer notification"
|
||||||
|
exec_if_exists_or_fail trigger_${template}_notification "${channel}" || \
|
||||||
|
printf "\nAttempted to send buffer notification to channel ${channel}, but the function was not found. Make sure notify_${template}.sh is available in the ${ScriptWorkDir} directory or notify_templates subdirectory."
|
||||||
|
Notified="true"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "${Notified}" == "true" ]]; then
|
||||||
|
printf "\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
### Set DISABLE_DOCKCHECK_NOTIFICATION=false in dockcheck.config
|
### Set DISABLE_DOCKCHECK_NOTIFICATION=false in dockcheck.config
|
||||||
### to not send notifications when dockcheck itself has updates.
|
### to not send notifications when dockcheck itself has updates.
|
||||||
dockcheck_notification() {
|
dockcheck_notification() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue