Files
dokku/plugins/scheduler-docker-local/internal-functions
Jose Diaz-Gonzalez dac566e75e refactor: move all shellcheck disable definitions to .shellcheckrc file
This makes standard use of shellcheck work without needing to provide extra configuration anywhere.

Also remove use of inline 'shellcheck disable' calls that are already defined in the .shellcheckrc and don't need to be set inline.
2023-08-05 10:58:57 -04:00

254 lines
7.8 KiB
Bash
Executable File

#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-scheduler-docker-local-report() {
declare desc="displays a scheduler-docker-local report for one or more apps"
declare cmd="scheduler-docker-local:report"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1" INFO_FLAG="$2"
if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then
INFO_FLAG="$APP"
APP=""
fi
if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then
INFO_FLAG="true"
fi
if [[ -z "$APP" ]]; then
for app in $(dokku_apps); do
cmd-scheduler-docker-local-report-single "$app" "$INFO_FLAG" | tee || true
done
else
cmd-scheduler-docker-local-report-single "$APP" "$INFO_FLAG"
fi
}
cmd-scheduler-docker-local-report-single() {
declare APP="$1" INFO_FLAG="$2"
if [[ "$INFO_FLAG" == "true" ]]; then
INFO_FLAG=""
fi
verify_app_name "$APP"
local flag_map=(
"--scheduler-docker-local-disable-chown: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "disable-chown" "")"
"--scheduler-docker-local-init-process: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "init-process" "true")"
"--scheduler-docker-local-parallel-schedule-count: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "parallel-schedule-count" "")"
)
if [[ -z "$INFO_FLAG" ]]; then
dokku_log_info2_quiet "${APP} scheduler-docker-local information"
for flag in "${flag_map[@]}"; do
key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')"
dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")"
done
else
local match=false
local value_exists=false
for flag in "${flag_map[@]}"; do
valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)"
if [[ "$flag" == "${INFO_FLAG}:"* ]]; then
value=${flag#*: }
size="${#value}"
if [[ "$size" -ne 0 ]]; then
echo "$value" && match=true && value_exists=true
else
match=true
fi
fi
done
[[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}"
[[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed"
fi
}
fn-scheduler-docker-local-retire-container() {
declare APP="$1" CID="$2"
local STATE
dokku_log_verbose_quiet "Attempting to retire $APP container $CID"
STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)"
if [[ -z "$STATE" ]]; then
return
fi
DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)"
[[ $DOKKU_DOCKER_STOP_TIMEOUT ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}"
if [[ "$STATE" == "restarting" ]]; then
"$DOCKER_BIN" container update --restart=no "$CID" >/dev/null 2>&1
fi
if [[ "$STATE" != "dead" ]] && [[ "$STATE" != "exited" ]]; then
# Attempt to stop, if that fails, then force a kill as docker seems
# to not send SIGKILL as the docs would indicate. If that fails, move
# on to the next.
"$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$CID" \
|| "$DOCKER_BIN" container kill "$CID" \
|| dokku_log_warn "Unable to kill container ${CID}"
fi
STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)"
if [[ -z "$STATE" ]]; then
return
fi
if [[ "$STATE" != "dead" ]] && [[ "$STATE" != "exited" ]]; then
if ! "$DOCKER_BIN" container kill "$CID"; then
dokku_log_warn "Unable to kill container ${CID}"
fi
fi
}
fn-scheduler-docker-local-retire-containers() {
local DEAD_CONTAINER_FILE="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/dead-containers"
local APP CID CURRENT_TIME DEAD_TIME STATE
declare SCHEDULER="$1" APP="$2"
if [[ ! -f "$DEAD_CONTAINER_FILE" ]]; then
return
fi
DEAD_CONTAINERS=()
while read line; do
[[ -z "$line" ]] && continue
CURRENT_TIME="$(date +%s)"
RETIRE_APP="$(echo "$line" | cut -d ' ' -f1)"
CID="$(echo "$line" | cut -d ' ' -f2)"
DEAD_TIME="$(echo "$line" | cut -d ' ' -f3)"
if [[ -n "$APP" ]] && [[ "$APP" != "$RETIRE_APP" ]]; then
continue
fi
if [[ "$CURRENT_TIME" -le "$DEAD_TIME" ]]; then
continue
fi
fn-scheduler-docker-local-retire-container "$RETIRE_APP" "$CID"
STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)"
if [[ -z "$STATE" ]]; then
DEAD_CONTAINERS+=("$CID")
continue
fi
if [[ "$STATE" == "running" ]]; then
dokku_log_warn "Container ${CID} still running"
continue
fi
"$DOCKER_BIN" container rm --force "$CID" >/dev/null 2>&1 || true
if "$DOCKER_BIN" container inspect "${CID}" >/dev/null 2>&1; then
dokku_log_warn "Container ${CID} still running"
continue
fi
DEAD_CONTAINERS+=("$CID")
done <"$DEAD_CONTAINER_FILE"
for CID in "${DEAD_CONTAINERS[@]}"; do
sed -i "/${CID}/d" "$DEAD_CONTAINER_FILE"
done
}
fn-scheduler-docker-local-retire-images() {
local DEAD_IMAGE_FILE="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/dead-images"
local APP IMAGE_ID CURRENT_TIME DEAD_TIME STATE RM_OUTPUT
declare SCHEDULER="$1" APP="$2"
if [[ ! -f "$DEAD_IMAGE_FILE" ]]; then
return
fi
DEAD_IMAGES=()
while read line; do
[[ -z "$line" ]] && continue
CURRENT_TIME="$(date +%s)"
RETIRE_APP="$(echo "$line" | cut -d ' ' -f1)"
IMAGE_ID="$(echo "$line" | cut -d ' ' -f2)"
DEAD_TIME="$(echo "$line" | cut -d ' ' -f3)"
if [[ -n "$APP" ]] && [[ "$APP" != "$RETIRE_APP" ]]; then
continue
fi
if [[ "$CURRENT_TIME" -le "$DEAD_TIME" ]]; then
continue
fi
STATE="$("$DOCKER_BIN" image inspect --format "{{ .Id }}" "$IMAGE_ID" 2>/dev/null || true)"
if [[ -z "$STATE" ]]; then
DEAD_IMAGES+=("$IMAGE_ID")
continue
fi
dokku_log_verbose_quiet "Attempting to retire $RETIRE_APP image $IMAGE_ID"
if RM_OUTPUT="$("$DOCKER_BIN" image remove "$IMAGE_ID" 2>&1)"; then
DEAD_IMAGES+=("$IMAGE_ID")
continue
fi
if echo "$RM_OUTPUT" | grep -q "image has dependent child images"; then
TAG_COUNT="$(docker inspect "$IMAGE_ID" --format '{{ json .RepoTags }}' | jq '. | length')"
if [[ "$TAG_COUNT" -eq 0 ]]; then
dokku_log_warn "Image ${IMAGE_ID} has children images and is untagged, skipping rm and marking dead"
DEAD_IMAGES+=("$IMAGE_ID")
continue
fi
dokku_log_warn "Image ${IMAGE_ID} has children images and has $TAG_COUNT tags, skipping rm"
continue
fi
if echo "$RM_OUTPUT" | grep -q "image is being used by running container"; then
dokku_log_warn "Image ${IMAGE_ID} has running containers, skipping rm"
continue
fi
dokku_log_warn "Image ${IMAGE_ID} still running"
done <"$DEAD_IMAGE_FILE"
for IMAGE_ID in "${DEAD_IMAGES[@]}"; do
sed -i "/${IMAGE_ID}/d" "$DEAD_IMAGE_FILE"
done
sort -o "$DEAD_IMAGE_FILE" -r "$DEAD_IMAGE_FILE"
}
fn-scheduler-docker-local-register-retired() {
declare TYPE="$1" APP="$2" DOCKER_ID="$3" WAIT="$4"
local DEAD_FILE="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/dead-containers"
if [[ "$TYPE" == "image" ]]; then
local DEAD_FILE="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/dead-images"
fi
local CURRENT_TIME DEAD_TIME
CURRENT_TIME="$(date +%s)"
DEAD_TIME=$((CURRENT_TIME + WAIT))
touch "$DEAD_FILE"
if ! grep -q "$DOCKER_ID" "$DEAD_FILE"; then
echo "${APP} ${DOCKER_ID} ${DEAD_TIME}" >>"${DEAD_FILE}"
fi
}
fn-scheduler-docker-local-start-app-container() {
declare desc="starts a single app container"
declare APP="$1"
shift
declare -a DOCKER_ARGS
for i in "$@"; do
DOCKER_ARGS+=("$i")
done
set -- "${DOCKER_ARGS[@]}"
eval "$(config_export app "$APP" --merged)"
# shellcheck disable=SC2124
"$DOCKER_BIN" container create "$@"
}