You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
5.3 KiB

#!/bin/bash -e
############################################################################ begin logging
# see if it supports colors...
ncolors=$(tput colors)
if test -n "$ncolors" && test $ncolors -ge 8; then
bold="$(tput bold)"
underline="$(tput smul)"
standout="$(tput smso)"
normal="$(tput sgr0)"
black="$(tput setaf 0)"
red="$(tput setaf 1)"
green="$(tput setaf 2)"
yellow="$(tput setaf 3)"
blue="$(tput setaf 4)"
magenta="$(tput setaf 5)"
cyan="$(tput setaf 6)"
white="$(tput setaf 7)"
fi
append_msg() {
if test $# -ne 0; then
echo -n ": ${bold}$*"
fi
echo "${normal}"
}
# write a message
message() {
if test $# -eq 0; then
return
fi
echo "${bold}${while}$*${normal}" 1>&2
}
# write a success message
success() {
echo -n "${bold}${green}success" 1>&2
append_msg $* 1>&2
}
# write a notice
notice() {
echo -n "${bold}${yellow}notice" 1>&2
append_msg $* 1>&2
}
# write a warning message
warning() {
echo -en "${bold}${red}warning" 1>&2
append_msg $* 1>&2
}
# write error message
error() {
echo -en "${bold}${red}error" 1>&2
append_msg $* 1>&2
}
# run a command, print the result and abort in case of error
# option: --ignore: ignore the result, continue in case of error
run() {
ignore=1
while test $# -gt 0; do
case "$1" in
(--ignore) ignore=0;;
(*) break;;
esac
shift;
done
echo -n "${bold}${yellow}running:${white} $*${normal}"
set +e
result=$($* 2>&1)
res=$?
set -e
if test $res -ne 0; then
if test $ignore -eq 1; then
error "failed with return code: $res"
if test -n "$result"; then
echo "$result"
fi
exit 1
else
warning "ignored return code: $res"
fi
else
success
fi
}
############################################################################ error handler
function traperror() {
set +x
local err=($1) # error status
local line="$2" # LINENO
local linecallfunc="$3"
local command="$4"
local funcstack="$5"
IFS=" "
for e in ${err[@]}; do
if test -n "$e" -a "$e" != "0"; then
error "line $line - command '$command' exited with status: $e (${err[@]})"
if [ "${funcstack}" != "main" -o "$linecallfunc" != "0" ]; then
echo -n " ... error at ${funcstack} " 1>&2
if [ "$linecallfunc" != "" ]; then
echo -n "called at line $linecallfunc" 1>&2
fi
echo
fi
exit $e
fi
done
exit 0
}
# catch errors
trap 'traperror "$? ${PIPESTATUS[@]}" $LINENO $BASH_LINENO "$BASH_COMMAND" "${FUNCNAME[@]}" "${FUNCTION}"' ERR SIGINT INT TERM EXIT
######################################################### commandline parameter evaluation
exec=0
stop=0
log=0
stacks=
short=0
while test $# -gt 0; do
case "$1" in
(--help|-h) less <<EOF
SYNOPSIS
$0 [OPTIONS] [stacks]
OPTIONS
--help, -h show this help
--log, -l show log command
--exec, -e show exec command
--stop, -x show stop command
--short, -s only show errors
stacks optional space separated list of stacks
DESCRIPTION
Show status of all docker swarm stacks. The problems of docker swarm ps are, that you can only specify one stack to analyze, and then you get too much output. So this command lists all stacks and clearly shows which stacks are running and which stacks have a problem.
EOF
exit;;
(--log|-l) log=1;;
(--exec|-e) exec=1;;
(--stop|-x) stop=1;;
(--short|-s) short=1;;
(*) stacks="$*"; break;;
esac
if test $# -eq 0; then
error "missing parameter, try $0 --help"; exit 1
fi
shift;
done
##################################################################################### Main
stacks=${stacks:-$(docker stack ls --format='{{.Name}}')}
services=$(for stack in ${stacks}; do
status=$(docker stack ps --no-trunc --filter="desired-state=running" --format="{{.CurrentState}};{{.Name}};{{.Node}};{{.DesiredState}};{{.CurrentState}};{{.ID}};{{.Error}}" ${stack} | sed 's,^[^ ]* ,,')
IFS="
"
for service in ${status}; do
time=${service%%;*}
echo "$(date +%s -d "$(sed 's,about an* ,1 ,;s,less than an* ,0 ,' <<<${time})");${service#*;}"
done
done | sort -hr)
IFS="
"
for service in ${services}; do
awk -F';' -v dolog=$log -v doexec=$exec -v dostop=$stop -v doshort=$short '
{color="'"${green}"'"}
$5 ~ /second|minute/ {color="'"${yellow}"'"}
$5 !~ /^Running/ {printf "'"${red}"'%-15s%-40s%s %s%s\n", $3, $2, $5, $7, "'"${normal}"'"}
$5 ~ /^Running/ && doshort==0 {printf "%s%-15s%-40s%s%s\n", color, $3, $2, $5, "'"${normal}"'"}
dolog==1 && (doshort==0 || $5 !~ /^Running/) {printf "ssh %s docker logs -f %s.%s\n", $3, $2, $6}
doexec==1 && (dohort==0 || $5 !~ /^Running/) {printf "ssh -t %s docker exec -it %s.%s bash\n", $3, $2, $6}
dostop==1 && (dohort==0 || $5 !~ /^Running/) {printf "ssh %s docker stop %s.%s\n", $3, $2, $6}
' <<<${service}
done