#!/usr/bin/env bash set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/internal-functions" fn-scheduler-docker-local-run-retire-container() { declare desc="stop a container" declare CONTAINER_ID="$1" APP="$2" local DOKKU_DOCKER_STOP_TIMEOUT="$(plugn trigger ps-get-property "$APP" stop-timeout-seconds || true)" [[ -n "$DOKKU_DOCKER_STOP_TIMEOUT" ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}" "$DOCKER_BIN" container update --restart=no "$CONTAINER_ID" &>/dev/null || true "$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$CONTAINER_ID" &>/dev/null || true "$DOCKER_BIN" container kill "$CONTAINER_ID" &>/dev/null || true "$DOCKER_BIN" container rm "$CONTAINER_ID" &>/dev/null || true local CONTAINER_STATUS if ! CONTAINER_STATUS="$("$DOCKER_BIN" container inspect "$CONTAINER_ID" --format '{{ .State.Status }}' 2>/dev/null)"; then return fi # a container started with --rm is removed by the daemon once it exits, and # stays inspectable in the removing state until that completes if [[ "$CONTAINER_STATUS" == "removing" ]]; then return fi dokku_log_warn "Unable to retire container ${CONTAINER_ID}" return 1 } fn-scheduler-docker-local-run-retire() { declare desc="stop all containers of a given type that have exceeded their active deadline" declare CONTAINER_TYPE="$1" APP="$2" local containers="" # docker ands repeated label filters, so each container type requires its own pass declare -a filters=(--filter "label=com.dokku.container-type=$CONTAINER_TYPE") if [[ -n "$APP" ]]; then filters+=(--filter "label=com.dokku.app-name=$APP") fi containers="$("$DOCKER_BIN" container ls "${filters[@]}" --format '{{.ID}} {{.CreatedAt}}')" if [[ -z "$containers" ]]; then return fi # iterate over all containers, ignoring the timezone in the last two columns echo "$containers" | awk '{NF-=2} 1' | while read -r container_id container_date container_time; do # get the cutoff time in seconds from the container's `com.dokku.active-deadline-seconds` label, # along with the owning app so the app's stop timeout is respected during the global pass container_labels="$("$DOCKER_BIN" container inspect "$container_id" --format '{{ index .Config.Labels "com.dokku.active-deadline-seconds" }}|{{ index .Config.Labels "com.dokku.app-name" }}')" active_deadline_seconds="${container_labels%%|*}" container_app="${container_labels##*|}" if [[ -z "$active_deadline_seconds" ]]; then continue fi # convert the active deadline seconds to a unix timestamp cutoff_time="$(date --date="$active_deadline_seconds seconds ago" "+%s")" # convert the container start time to unix timestamp start_time="$(date --date="$container_date $container_time" "+%s")" # if the container start time is before the cutoff time, stop the container if [[ "$start_time" -lt "$cutoff_time" ]]; then dokku_log_verbose_quiet "Retiring container ${container_id}" fn-scheduler-docker-local-run-retire-container "$container_id" "$container_app" fi done } trigger-scheduler-docker-local-scheduler-run-retire() { declare desc="retires all run and cron containers for an app that have exceeded their active deadline" declare trigger="scheduler-run-retire" declare DOKKU_SCHEDULER="$1" APP="$2" declare -a CONTAINER_TYPES=(run cron) local exit_code=0 if [[ -z "$DOKKU_SCHEDULER" ]]; then dokku_log_info1_quiet "Retiring all run and cron containers" for container_type in "${CONTAINER_TYPES[@]}"; do fn-scheduler-docker-local-run-retire "$container_type" || exit_code=1 done return "$exit_code" fi if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then return fi dokku_log_info1_quiet "Retiring run and cron containers for app ${APP}" for container_type in "${CONTAINER_TYPES[@]}"; do fn-scheduler-docker-local-run-retire "$container_type" "$APP" || exit_code=1 done return "$exit_code" } trigger-scheduler-docker-local-scheduler-run-retire "$@"