2015-02-05 11:32:46 -08:00
#!/usr/bin/env bash
2019-01-07 01:04:17 -05:00
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
2015-02-05 11:32:46 -08:00
2015-02-07 10:57:30 -08:00
has_tty() {
2016-03-08 15:30:34 -05:00
declare desc="return 0 if we have a tty"
2021-07-27 13:16:33 -04:00
if [[ "$DOKKU_DISABLE_TTY" == "true" ]]; then
2021-07-27 02:26:15 -04:00
return 1
fi
2019-09-16 04:02:54 -04:00
if [[ "$(LC_ALL=C /usr/bin/tty || true)" == "not a tty" ]]; then
2015-02-05 11:32:46 -08:00
return 1
else
return 0
fi
}
2015-11-13 16:40:22 -08:00
dokku_apps() {
2016-03-08 15:30:34 -05:00
declare desc="prints list of all local apps"
2020-05-08 23:57:30 -04:00
local INSTALLED_APPS=$(find "$DOKKU_ROOT" -follow -maxdepth 1 -mindepth 1 -type d ! -name '.*' -printf "%f\n" 2>/dev/null | sort) || (dokku_log_fail "You haven't deployed any applications yet")
2016-02-22 10:16:57 -08:00
[[ $INSTALLED_APPS ]] && echo "$INSTALLED_APPS"
2015-11-13 16:40:22 -08:00
}
2021-01-23 12:32:31 -05:00
dokku_version() {
if [[ -f "$DOKKU_LIB_ROOT/STABLE_VERSION" ]]; then
DOKKU_VERSION=$(cat "${DOKKU_LIB_ROOT}/STABLE_VERSION")
elif [[ -f "$DOKKU_LIB_ROOT/VERSION" ]]; then
DOKKU_VERSION=$(cat "${DOKKU_LIB_ROOT}/VERSION")
else
dokku_log_fail "Unable to determine dokku's version"
fi
echo "dokku version ${DOKKU_VERSION}"
}
2018-04-27 03:55:00 -04:00
dokku_log_quiet() {
declare desc="log quiet formatter"
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
echo "$*"
fi
}
2015-02-07 10:57:30 -08:00
dokku_log_info1() {
2016-03-08 15:30:34 -05:00
declare desc="log info1 formatter"
2015-11-02 17:54:02 -06:00
echo "-----> $*"
2015-02-05 11:32:46 -08:00
}
2015-02-07 10:57:30 -08:00
dokku_log_info2() {
2016-03-08 15:30:34 -05:00
declare desc="log info2 formatter"
2015-11-02 17:54:02 -06:00
echo "=====> $*"
2015-02-05 11:32:46 -08:00
}
2015-02-07 10:57:30 -08:00
dokku_log_info1_quiet() {
2016-03-08 15:30:34 -05:00
declare desc="log info1 formatter (with quiet option)"
2015-09-14 21:20:35 -07:00
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
2015-11-02 17:54:02 -06:00
echo "-----> $*"
2015-02-05 12:38:59 -08:00
fi
}
2015-02-07 10:57:30 -08:00
dokku_log_info2_quiet() {
2016-03-08 15:30:34 -05:00
declare desc="log info2 formatter (with quiet option)"
2015-09-14 21:20:35 -07:00
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
2015-11-02 17:54:02 -06:00
echo "=====> $*"
2015-02-05 12:38:59 -08:00
fi
}
2015-04-24 10:49:18 -07:00
dokku_col_log_info1() {
2016-03-08 15:30:34 -05:00
declare desc="columnar log info1 formatter"
2015-11-02 17:54:02 -06:00
printf "%-6s %-18s %-25s %-25s %-25s\n" "----->" "$@"
2015-02-07 14:09:39 -08:00
}
2015-04-24 10:49:18 -07:00
dokku_col_log_info1_quiet() {
2016-03-08 15:30:34 -05:00
declare desc="columnar log info1 formatter (with quiet option)"
2015-09-14 21:20:35 -07:00
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
2015-11-02 17:54:02 -06:00
printf "%-6s %-18s %-25s %-25s %-25s\n" "----->" "$@"
2015-02-07 14:09:39 -08:00
fi
}
2015-04-24 10:49:18 -07:00
dokku_col_log_info2() {
2016-03-08 15:30:34 -05:00
declare desc="columnar log info2 formatter"
2015-11-02 17:54:02 -06:00
printf "%-6s %-18s %-25s %-25s %-25s\n" "=====>" "$@"
2015-02-07 14:09:39 -08:00
}
2015-04-24 10:49:18 -07:00
dokku_col_log_info2_quiet() {
2016-03-08 15:30:34 -05:00
declare desc="columnar log info2 formatter (with quiet option)"
2015-09-14 21:20:35 -07:00
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
2015-11-02 17:54:02 -06:00
printf "%-6s %-18s %-25s %-25s %-25s\n" "=====>" "$@"
2015-02-07 14:09:39 -08:00
fi
}
2015-04-24 10:49:18 -07:00
dokku_col_log_msg() {
2016-03-08 15:30:34 -05:00
declare desc="columnar log formatter"
2015-04-24 10:49:18 -07:00
printf "%-25s %-25s %-25s %-25s\n" "$@"
2015-02-07 14:09:39 -08:00
}
2015-04-24 10:49:18 -07:00
dokku_col_log_msg_quiet() {
2016-03-08 15:30:34 -05:00
declare desc="columnar log formatter (with quiet option)"
2015-09-14 21:20:35 -07:00
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
2015-04-24 10:49:18 -07:00
printf "%-25s %-25s %-25s %-25s\n" "$@"
2015-02-07 14:09:39 -08:00
fi
}
2015-03-20 08:29:35 -07:00
dokku_log_verbose_quiet() {
2016-03-08 15:30:34 -05:00
declare desc="log verbose formatter (with quiet option)"
2015-09-14 21:20:35 -07:00
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
2015-11-02 17:54:02 -06:00
echo " $*"
2015-03-20 08:29:35 -07:00
fi
}
2015-02-07 10:57:30 -08:00
dokku_log_verbose() {
2016-03-08 15:30:34 -05:00
declare desc="log verbose formatter"
2015-11-02 17:54:02 -06:00
echo " $*"
2015-02-05 11:32:46 -08:00
}
2019-03-12 12:34:45 -04:00
dokku_log_exclaim_quiet() {
declare desc="log exclaim formatter"
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
echo " ! $*"
fi
}
dokku_log_exclaim() {
declare desc="log exclaim formatter"
echo " ! $*"
}
2018-11-05 01:20:34 -05:00
dokku_log_warn_quiet() {
declare desc="log warning formatter"
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
echo " ! $*" 1>&2
fi
}
2015-02-07 10:57:30 -08:00
dokku_log_warn() {
2016-03-08 15:30:34 -05:00
declare desc="log warning formatter"
2017-03-13 00:16:32 -06:00
echo " ! $*" 1>&2
2015-02-05 11:32:46 -08:00
}
2019-01-11 11:21:56 -05:00
dokku_log_exit_quiet() {
declare desc="log exit formatter"
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
echo "$@" 1>&2
fi
exit 0
}
dokku_log_exit() {
declare desc="log exit formatter"
2020-02-08 15:57:01 -05:00
echo "$@" 1>&2
2019-01-11 11:21:56 -05:00
exit 0
}
2018-11-05 01:20:34 -05:00
dokku_log_fail_quiet() {
declare desc="log fail formatter"
if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then
2021-02-13 02:31:01 -05:00
echo " ! $*" 1>&2
2018-11-05 01:20:34 -05:00
fi
2021-02-03 04:28:59 -05:00
exit ${DOKKU_FAIL_EXIT_CODE:=1}
2018-11-05 01:20:34 -05:00
}
2015-02-07 10:57:30 -08:00
dokku_log_fail() {
2016-03-08 15:30:34 -05:00
declare desc="log fail formatter"
2021-02-13 02:31:01 -05:00
echo " ! $*" 1>&2
2021-02-03 04:28:59 -05:00
exit ${DOKKU_FAIL_EXIT_CODE:=1}
2015-02-05 11:32:46 -08:00
}
2020-02-08 15:56:45 -05:00
dokku_log_stderr() {
declare desc="log stderr formatter"
echo "$@" 1>&2
}
2015-06-26 13:14:04 +01:00
dokku_log_event() {
2016-03-08 15:30:34 -05:00
declare desc="log dokku events"
2019-07-17 17:59:38 -04:00
logger -t dokku-event -i -- "$@"
2015-06-26 13:14:04 +01:00
}
2015-09-07 03:55:37 -04:00
dokku_log_plugn_trigger_call() {
2016-03-08 15:30:34 -05:00
declare desc="log plugn trigger calls"
2015-06-26 13:14:04 +01:00
2019-01-07 01:04:17 -05:00
local l_hook="$1"
shift
2021-01-02 05:23:12 -05:00
dokku_log_event "INVOKED: ${l_hook}( $* ) NAME=$NAME FINGERPRINT=$FINGERPRINT DOKKU_PID=$DOKKU_PID"
2015-06-26 13:14:04 +01:00
}
2015-03-20 08:29:35 -07:00
dokku_container_log_verbose_quiet() {
2016-03-08 15:30:34 -05:00
declare desc="log verbose container output (with quiet option)"
2019-01-07 01:04:17 -05:00
local CID=$1
2015-03-20 08:29:35 -07:00
shift
OIFS=$IFS
IFS=$'\n'
2016-03-02 10:50:09 -08:00
local line
2019-05-29 04:05:24 -04:00
for line in $("$DOCKER_BIN" container logs "$CID" 2>&1); do
2015-03-20 08:29:35 -07:00
dokku_log_verbose_quiet "$line"
done
IFS=$OIFS
}
2021-01-09 07:40:45 -05:00
fn-is-valid-app-name() {
2020-12-21 18:35:09 -05:00
declare desc="verify that the app name matches naming restrictions"
2015-09-03 16:07:23 -07:00
local APP="$1"
2020-12-21 18:35:09 -05:00
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
2019-01-07 01:04:17 -05:00
if [[ "$APP" =~ ^[a-z].* ]] || [[ "$APP" =~ ^[0-9].* ]]; then
2020-09-09 20:06:53 -04:00
if [[ ! $APP =~ [A-Z] ]] && [[ ! $APP =~ [:] ]] && [[ ! $APP =~ [_] ]]; then
2018-02-13 03:30:27 -05:00
return 0
fi
2015-12-22 12:02:18 -08:00
fi
2018-02-13 03:30:27 -05:00
2021-01-09 07:40:45 -05:00
return 1
2017-08-19 19:16:16 -04:00
}
2021-01-09 07:40:45 -05:00
fn-is-valid-app-name-old() {
2020-12-21 18:35:09 -05:00
declare desc="verify that the app name matches the old naming restrictions"
local APP="$1"
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
if [[ "$APP" =~ ^[a-z].* ]] || [[ "$APP" =~ ^[0-9].* ]]; then
if [[ ! $APP =~ [A-Z] ]] && [[ ! $APP =~ [:] ]]; then
return 0
fi
fi
2021-01-09 07:40:45 -05:00
return 1
}
is_valid_app_name() {
declare desc="verify that the app name matches naming restrictions"
local APP="$1"
if fn-is-valid-app-name "$APP"; then
return
fi
dokku_log_fail "App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, colons, or underscores"
}
is_valid_app_name_old() {
declare desc="verify that the app name matches the old naming restrictions"
local APP="$1"
if fn-is-valid-app-name-old "$APP"; then
return
fi
2020-12-21 18:35:09 -05:00
dokku_log_fail "App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, or colons"
}
2017-08-19 19:16:16 -04:00
verify_app_name() {
declare desc="verify app name format and app existence"
2020-12-21 18:35:09 -05:00
declare APP="$1"
local VALID_NEW=false
local VALID_OLD=false
2021-01-09 07:40:45 -05:00
if fn-is-valid-app-name "$APP" 2>/dev/null; then
VALID_NEW=true
fi
if fn-is-valid-app-name-old "$APP" 2>/dev/null; then
VALID_OLD=true
fi
2020-12-21 18:35:09 -05:00
if [[ "$VALID_NEW" == "false" ]] && [[ "$VALID_OLD" == "false" ]]; then
dokku_log_fail "App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, colons, or underscores"
fi
2021-02-03 04:29:11 -05:00
[[ ! -d "$DOKKU_ROOT/$APP" ]] && DOKKU_FAIL_EXIT_CODE=20 dokku_log_fail "App $APP does not exist"
2015-06-10 14:21:47 -07:00
2015-02-05 11:32:46 -08:00
return 0
}
2015-04-21 20:25:05 -07:00
verify_image() {
2016-03-08 15:30:34 -05:00
declare desc="verify image existence"
2015-04-21 20:25:05 -07:00
local IMAGE="$1"
2019-05-29 04:05:24 -04:00
if "$DOCKER_BIN" image inspect "$IMAGE" &>/dev/null; then
2015-04-18 15:39:08 -07:00
return 0
else
return 1
fi
}
2015-09-03 17:05:49 -07:00
get_app_image_repo() {
2016-03-08 15:30:34 -05:00
declare desc="central definition of image repo pattern"
2019-01-07 01:04:17 -05:00
local APP="$1"
local IMAGE_REPO="dokku/$APP"
2016-02-22 10:16:57 -08:00
echo "$IMAGE_REPO"
2015-09-03 17:05:49 -07:00
}
2016-04-14 19:10:03 -04:00
get_deploying_app_image_name() {
2016-07-29 04:51:36 -04:00
declare desc="return deploying image identifier for a given app, tag tuple. validate if tag is presented"
2019-01-07 01:04:17 -05:00
local APP="$1"
local IMAGE_TAG="$2"
IMAGE_REPO="$3"
2016-04-14 19:10:03 -04:00
local IMAGE_REMOTE_REPOSITORY=$(plugn trigger deployed-app-repository "$APP")
local NEW_IMAGE_TAG=$(plugn trigger deployed-app-image-tag "$APP")
2016-07-05 02:34:13 -04:00
local NEW_IMAGE_REPO=$(plugn trigger deployed-app-image-repo "$APP")
2016-04-14 19:10:03 -04:00
2016-07-29 04:51:36 -04:00
[[ -n "$NEW_IMAGE_REPO" ]] && IMAGE_REPO="$NEW_IMAGE_REPO"
[[ -n "$NEW_IMAGE_TAG" ]] && IMAGE_TAG="$NEW_IMAGE_TAG"
[[ -z "$IMAGE_REPO" ]] && IMAGE_REPO=$(get_app_image_repo "$APP")
[[ -z "$IMAGE_TAG" ]] && IMAGE_TAG="latest"
2016-07-05 02:34:13 -04:00
2016-07-29 04:51:36 -04:00
local IMAGE="${IMAGE_REMOTE_REPOSITORY}${IMAGE_REPO}:${IMAGE_TAG}"
2018-04-03 01:21:50 -04:00
verify_image "$IMAGE" || dokku_log_fail "App image ($IMAGE) not found"
2016-04-14 19:10:03 -04:00
echo "$IMAGE"
}
2015-09-03 17:05:49 -07:00
get_app_image_name() {
2016-03-08 15:30:34 -05:00
declare desc="return image identifier for a given app, tag tuple. validate if tag is presented"
2019-01-07 01:04:17 -05:00
local APP="$1"
local IMAGE_TAG="$2"
IMAGE_REPO="$3"
2015-09-03 16:07:23 -07:00
2016-07-05 02:34:13 -04:00
if [[ -z "$IMAGE_REPO" ]]; then
IMAGE_REPO=$(get_app_image_repo "$APP")
fi
2015-09-03 16:07:23 -07:00
if [[ -n "$IMAGE_TAG" ]]; then
2016-03-02 10:50:09 -08:00
local IMAGE="$IMAGE_REPO:$IMAGE_TAG"
2018-04-03 01:21:50 -04:00
verify_image "$IMAGE" || dokku_log_fail "App image ($IMAGE) not found"
2015-09-03 16:07:23 -07:00
else
2016-03-02 10:50:09 -08:00
local IMAGE="$IMAGE_REPO:latest"
2015-09-03 16:07:23 -07:00
fi
2016-02-22 10:16:57 -08:00
echo "$IMAGE"
2015-09-03 16:07:23 -07:00
}
2018-09-30 21:36:53 -04:00
get_app_scheduler() {
declare desc="fetch the scheduler for a given application"
declare APP="$1"
2018-12-18 02:30:11 -05:00
local DOKKU_APP_SCHEDULER DOKKU_GLOBAL_SCHEDULER DOKKU_SCHEDULER
2018-09-30 21:36:53 -04:00
2019-07-18 04:28:45 -04:00
if [[ "$APP" == "--global" ]]; then
APP=""
fi
2019-04-17 03:04:43 -04:00
source "$PLUGIN_AVAILABLE_PATH/config/functions"
2018-12-18 02:30:11 -05:00
[[ -n "$APP" ]] && DOKKU_APP_SCHEDULER="$(config_get "$APP" DOKKU_SCHEDULER || true)"
2018-09-30 21:36:53 -04:00
DOKKU_GLOBAL_SCHEDULER="$(config_get --global DOKKU_SCHEDULER || true)"
DOKKU_SCHEDULER=${DOKKU_APP_SCHEDULER:="$DOKKU_GLOBAL_SCHEDULER"}
if [[ -z "$DOKKU_SCHEDULER" ]]; then
DOKKU_SCHEDULER="docker-local"
fi
echo "$DOKKU_SCHEDULER"
}
2015-06-10 14:21:47 -07:00
get_running_image_tag() {
2016-03-08 15:30:34 -05:00
declare desc="retrieve current image tag for a given app. returns empty string if no deployed containers are found"
2015-06-10 14:21:47 -07:00
local APP="$1"
2019-01-07 01:04:17 -05:00
local CIDS=($(get_app_container_ids "$APP"))
2019-05-29 04:05:24 -04:00
local RUNNING_IMAGE_TAG=$("$DOCKER_BIN" container inspect --format '{{ .Config.Image }}' "${CIDS[0]}" 2>/dev/null | awk -F: '{ print $2 }' || echo '')
2016-02-22 10:16:57 -08:00
echo "$RUNNING_IMAGE_TAG"
2015-06-10 14:21:47 -07:00
}
2020-12-01 14:49:39 -05:00
is_image_cnb_based() {
declare desc="returns true if app image is based on cnb"
declare IMAGE="$1"
if [[ -z "$IMAGE" ]]; then
return 1
fi
CNB_STACK_ID="$("$DOCKER_BIN" image inspect --format '{{ index .Config.Labels "io.buildpacks.stack.id" }}' "$IMAGE")"
if [[ -n "$CNB_STACK_ID" ]]; then
return 0
fi
return 1
}
2015-04-20 16:32:18 -07:00
is_image_herokuish_based() {
2020-12-01 14:49:39 -05:00
declare desc="returns true if app image is based on herokuish or a buildpack-like env"
2020-02-10 01:40:30 -05:00
declare IMAGE="$1" APP="$2"
2019-11-19 12:14:37 -07:00
local DOKKU_APP_USER
fix: Only override the `WORKDIR` in copy_from_image if the image is `gliderlabs/herokuish` based
Rather than always assuming a missing `WORKDIR` means herokuish, we instead inspect the image to verify that it is. If it is, then and _only_ then do we set WORKDIR. Otherwise, we respect the decision of `docker cp` to execute from within the last known `WORKDIR` context, which is inherited at the image level, not image metadata level.
Additionally, speed up `is_image_herokuish_based` by inspecting the environment variables on the image. When there is a "USER=herokuishuser", we can more or less safely assume it is an image that Dokku built, and is therefore a herokuish image. While possible, it would be very strange if a non-herokuish image had this environment variable set, so it is a relatively safe change.
2019-03-05 23:28:59 -05:00
local USER_VALUE
2019-05-12 07:37:21 -04:00
if [[ -z "$IMAGE" ]]; then
return 1
fi
2020-12-01 14:49:39 -05:00
if is_image_cnb_based "$IMAGE"; then
return 0
fi
if [[ -n "$APP" ]]; then
DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true)
fi
DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"}
2019-11-19 12:14:37 -07:00
# due to how the build process works, all herokuish images have the Environment variable USER=$DOKKU_APP_USER
USER_VALUE="$("$DOCKER_BIN" image inspect --format '{{range .Config.Env}}{{if eq . "USER='"$DOKKU_APP_USER"'"}}{{println .}}{{end}}{{end}}' "$IMAGE")"
fix: Only override the `WORKDIR` in copy_from_image if the image is `gliderlabs/herokuish` based
Rather than always assuming a missing `WORKDIR` means herokuish, we instead inspect the image to verify that it is. If it is, then and _only_ then do we set WORKDIR. Otherwise, we respect the decision of `docker cp` to execute from within the last known `WORKDIR` context, which is inherited at the image level, not image metadata level.
Additionally, speed up `is_image_herokuish_based` by inspecting the environment variables on the image. When there is a "USER=herokuishuser", we can more or less safely assume it is an image that Dokku built, and is therefore a herokuish image. While possible, it would be very strange if a non-herokuish image had this environment variable set, so it is a relatively safe change.
2019-03-05 23:28:59 -05:00
[[ "$USER_VALUE" == "" ]] && return 1
return 0
2015-02-07 10:47:04 -08:00
}
2016-09-22 09:33:15 -07:00
get_docker_version() {
2019-05-29 04:05:24 -04:00
CLIENT_VERSION_STRING="$("$DOCKER_BIN" version --format "{{ .Client.Version }}")"
2016-09-22 09:33:15 -07:00
echo "$CLIENT_VERSION_STRING"
}
2015-04-18 15:39:08 -07:00
is_number() {
2016-03-08 15:30:34 -05:00
declare desc="returns 0 if input is a number"
2019-01-07 01:04:17 -05:00
local NUMBER=$1
local NUM_RE='^[0-9]+$'
2015-09-14 21:20:35 -07:00
if [[ $NUMBER =~ $NUM_RE ]]; then
2015-04-18 15:39:08 -07:00
return 0
else
return 1
fi
}
2016-02-14 15:37:24 -05:00
is_abs_path() {
2016-03-08 15:30:34 -05:00
declare desc="returns 0 if input path is absolute"
2016-02-14 15:37:24 -05:00
local TEST_PATH=$1
2016-03-02 10:50:09 -08:00
if [[ "$TEST_PATH" == /* ]]; then
2019-01-07 01:04:17 -05:00
return 0
else
return 1
2016-02-14 15:37:24 -05:00
fi
}
2015-02-07 10:57:30 -08:00
parse_args() {
2016-03-08 15:30:34 -05:00
declare desc="top-level cli arg parser"
2019-01-07 01:04:17 -05:00
local next_index=1
local skip=false
local args=("$@")
2019-09-16 23:07:01 -04:00
local flags
2015-02-05 11:32:46 -08:00
for arg in "$@"; do
2017-01-09 02:13:52 -07:00
if [[ "$skip" == "true" ]]; then
2019-01-07 01:04:17 -05:00
next_index=$((next_index + 1))
2017-01-09 02:13:52 -07:00
skip=false
continue
fi
2015-02-05 11:32:46 -08:00
case "$arg" in
2015-02-09 16:59:07 -08:00
--quiet)
2015-02-05 11:32:46 -08:00
export DOKKU_QUIET_OUTPUT=1
;;
2016-05-02 00:02:37 -04:00
--detach)
2021-07-27 02:11:43 -04:00
dokku_log_warn_quiet "Deprecated: use run:detached instead of using the --detach flag"
2016-05-02 00:02:37 -04:00
export DOKKU_DETACH_CONTAINER=1
;;
2015-02-09 16:59:07 -08:00
--trace)
2015-02-05 11:32:46 -08:00
export DOKKU_TRACE=1
;;
2019-01-07 01:04:17 -05:00
--rm-container | --rm)
2021-07-27 01:55:16 -04:00
dokku_log_warn_quiet "Deprecated: all run containers are now removed on exit by default"
2015-02-05 11:32:46 -08:00
;;
2015-02-09 16:59:07 -08:00
--force)
2015-02-05 11:32:46 -08:00
export DOKKU_APPS_FORCE_DELETE=1
;;
2016-01-10 14:05:33 -05:00
--app)
2019-01-07 01:04:17 -05:00
export DOKKU_APP_NAME=${args[$next_index]}
skip=true
2016-01-10 14:05:33 -05:00
;;
2015-02-05 11:32:46 -08:00
esac
2019-09-16 23:07:01 -04:00
if [[ "$skip" == "true" ]]; then
flags="${flags} ${arg}"
elif [[ "$arg" == "--app" ]]; then
flags="${flags} ${arg}=${args[$next_index]}"
elif [[ "$arg" =~ ^--.* ]]; then
flags="${flags} ${arg}"
fi
2019-01-07 01:04:17 -05:00
next_index=$((next_index + 1))
2015-02-05 11:32:46 -08:00
done
2019-09-16 23:07:01 -04:00
if [[ -z "$DOKKU_GLOBAL_FLAGS" ]]; then
export DOKKU_GLOBAL_FLAGS="$(echo -e "${flags}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
fi
2015-02-05 11:32:46 -08:00
return 0
}
2015-04-17 15:23:59 -07:00
copy_from_image() {
2016-03-08 15:30:34 -05:00
declare desc="copy file from named image to destination"
2019-08-01 19:33:52 -04:00
declare IMAGE="$1" SRC_FILE="$2" DST_FILE="$3"
fix: Only override the `WORKDIR` in copy_from_image if the image is `gliderlabs/herokuish` based
Rather than always assuming a missing `WORKDIR` means herokuish, we instead inspect the image to verify that it is. If it is, then and _only_ then do we set WORKDIR. Otherwise, we respect the decision of `docker cp` to execute from within the last known `WORKDIR` context, which is inherited at the image level, not image metadata level.
Additionally, speed up `is_image_herokuish_based` by inspecting the environment variables on the image. When there is a "USER=herokuishuser", we can more or less safely assume it is an image that Dokku built, and is therefore a herokuish image. While possible, it would be very strange if a non-herokuish image had this environment variable set, so it is a relatively safe change.
2019-03-05 23:28:59 -05:00
local WORK_DIR=""
2015-04-17 15:23:59 -07:00
2019-07-19 15:50:55 -04:00
local DOCKER_CREATE_LABEL_ARGS="--label=com.dokku.app-name=$APP"
2019-06-29 15:33:24 -04:00
2015-04-21 20:25:05 -07:00
if verify_image "$IMAGE"; then
2016-02-22 10:16:57 -08:00
if ! is_abs_path "$SRC_FILE"; then
2021-02-11 06:48:38 -05:00
if is_image_cnb_based "$IMAGE"; then
2021-01-14 08:33:26 -05:00
WORKDIR="/workspace"
2021-02-11 06:48:38 -05:00
elif is_image_herokuish_based "$IMAGE" "$APP"; then
WORKDIR="/app"
fix: Only override the `WORKDIR` in copy_from_image if the image is `gliderlabs/herokuish` based
Rather than always assuming a missing `WORKDIR` means herokuish, we instead inspect the image to verify that it is. If it is, then and _only_ then do we set WORKDIR. Otherwise, we respect the decision of `docker cp` to execute from within the last known `WORKDIR` context, which is inherited at the image level, not image metadata level.
Additionally, speed up `is_image_herokuish_based` by inspecting the environment variables on the image. When there is a "USER=herokuishuser", we can more or less safely assume it is an image that Dokku built, and is therefore a herokuish image. While possible, it would be very strange if a non-herokuish image had this environment variable set, so it is a relatively safe change.
2019-03-05 23:28:59 -05:00
else
2019-05-29 04:05:24 -04:00
WORKDIR="$("$DOCKER_BIN" image inspect --format '{{.Config.WorkingDir}}' "$IMAGE")"
fix: Only override the `WORKDIR` in copy_from_image if the image is `gliderlabs/herokuish` based
Rather than always assuming a missing `WORKDIR` means herokuish, we instead inspect the image to verify that it is. If it is, then and _only_ then do we set WORKDIR. Otherwise, we respect the decision of `docker cp` to execute from within the last known `WORKDIR` context, which is inherited at the image level, not image metadata level.
Additionally, speed up `is_image_herokuish_based` by inspecting the environment variables on the image. When there is a "USER=herokuishuser", we can more or less safely assume it is an image that Dokku built, and is therefore a herokuish image. While possible, it would be very strange if a non-herokuish image had this environment variable set, so it is a relatively safe change.
2019-03-05 23:28:59 -05:00
fi
if [[ -n "$WORKDIR" ]]; then
SRC_FILE="${WORKDIR}/${SRC_FILE}"
fi
2016-02-14 15:37:24 -05:00
fi
2019-08-01 19:33:52 -04:00
2019-08-12 18:16:16 -04:00
TMP_FILE_COMMAND_OUTPUT=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
2019-08-12 17:39:01 -04:00
trap "rm -rf '$TMP_FILE_COMMAND_OUTPUT' >/dev/null 2>&1 || true" RETURN
2019-08-01 19:33:52 -04:00
2019-05-29 04:05:24 -04:00
local CID=$("$DOCKER_BIN" container create "${DOCKER_CREATE_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "$IMAGE")
"$DOCKER_BIN" container cp "$CID:$SRC_FILE" "$TMP_FILE_COMMAND_OUTPUT" 2>/dev/null || true
"$DOCKER_BIN" container rm --force "$CID" &>/dev/null
2020-11-22 16:57:39 -05:00
plugn trigger scheduler-register-retired "$APP" "$CID"
2019-08-01 19:40:30 -04:00
# docker cp exits with status 1 when run as non-root user when it tries to chown the file
# after successfully copying the file. Thus, we suppress stderr.
# ref: https://github.com/dotcloud/docker/issues/3986
if [[ ! -s "$TMP_FILE_COMMAND_OUTPUT" ]]; then
2019-05-18 14:41:59 -07:00
return 1
fi
2019-08-01 19:33:52 -04:00
# workaround for CHECKS file when owner is root. seems to only happen when running inside docker
2019-08-05 15:24:15 -04:00
dos2unix -l <"$TMP_FILE_COMMAND_OUTPUT" >"$DST_FILE"
2019-08-01 19:33:52 -04:00
2019-08-01 19:35:24 -04:00
# add trailing newline for certain places where file parsing depends on it
if [[ "$(tail -c1 "$DST_FILE")" != "" ]]; then
echo "" >>"$DST_FILE"
fi
2015-04-18 10:37:17 -07:00
else
return 1
fi
2015-04-17 15:23:59 -07:00
}
2015-04-17 18:57:37 -07:00
2015-07-13 08:24:46 -07:00
get_app_container_ids() {
2016-06-28 20:32:04 -07:00
declare desc="returns list of docker container ids for given app and optional container_type"
2019-01-07 01:04:17 -05:00
local APP="$1"
local CONTAINER_TYPE="$2"
[[ -f $DOKKU_ROOT/$APP/CONTAINER ]] && DOKKU_CIDS+=$(<"$DOKKU_ROOT/$APP/CONTAINER")
2015-04-17 18:57:37 -07:00
2015-08-25 23:00:49 -04:00
if [[ -n "$CONTAINER_TYPE" ]]; then
2016-03-02 10:50:09 -08:00
local CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE.*"
2015-08-25 23:00:49 -04:00
if [[ $CONTAINER_TYPE == *.* ]]; then
2016-03-02 10:50:09 -08:00
local CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE"
2015-08-25 23:00:49 -04:00
[[ ! -f $CONTAINER_PATTERN ]] && echo "" && return 0
fi
else
2016-03-02 10:50:09 -08:00
local CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.*"
2015-08-25 23:00:49 -04:00
fi
2015-04-17 18:57:37 -07:00
shopt -s nullglob
2016-03-02 10:50:09 -08:00
local DOKKU_CID_FILE
2015-08-25 23:00:49 -04:00
for DOKKU_CID_FILE in $CONTAINER_PATTERN; do
2016-03-02 10:50:09 -08:00
local DOKKU_CIDS+=" "
2019-01-07 01:04:17 -05:00
local DOKKU_CIDS+=$(<"$DOKKU_CID_FILE")
2016-03-02 10:50:09 -08:00
local DOKKU_CIDS+=" "
2015-04-17 18:57:37 -07:00
done
shopt -u nullglob
2016-02-22 10:16:57 -08:00
echo "$DOKKU_CIDS"
2015-04-17 18:57:37 -07:00
}
2015-07-12 15:56:52 -07:00
2015-07-13 08:24:46 -07:00
get_app_running_container_ids() {
2016-06-28 20:32:04 -07:00
declare desc="return list of running docker container ids for given app and optional container_type"
local APP="$1" CONTAINER_TYPE="$2"
2017-03-26 05:03:16 -06:00
local CIDS
2015-07-13 08:24:46 -07:00
2016-02-22 10:16:57 -08:00
! (is_deployed "$APP") && dokku_log_fail "App $APP has not been deployed"
2017-03-26 05:03:16 -06:00
CIDS=$(get_app_container_ids "$APP" "$CONTAINER_TYPE")
2015-07-13 08:24:46 -07:00
2015-09-14 21:20:35 -07:00
for CID in $CIDS; do
2018-02-12 02:21:34 -05:00
(is_container_status "$CID" "Running") && local APP_RUNNING_CONTAINER_IDS+="$CID "
2015-07-13 08:24:46 -07:00
done
echo "$APP_RUNNING_CONTAINER_IDS"
}
2016-05-11 11:52:29 -07:00
get_app_running_container_types() {
declare desc="return list of running container types for given app"
local APP=$1 CONTAINER_TYPES
! (is_deployed "$APP") && dokku_log_fail "App $APP has not been deployed"
2016-08-26 13:46:05 -07:00
CONTAINER_TYPES="$(find "$DOKKU_ROOT/$APP" -maxdepth 1 -name "CONTAINER.*" -print0 2>/dev/null | xargs -0)"
2016-05-11 11:52:29 -07:00
if [[ -n "$CONTAINER_TYPES" ]]; then
CONTAINER_TYPES="${CONTAINER_TYPES//$DOKKU_ROOT\/$APP\//}"
2019-01-07 01:04:17 -05:00
CONTAINER_TYPES="$(tr " " $'\n' <<<"$CONTAINER_TYPES" | awk -F. '{ print $2 }' | sort | uniq | xargs)"
2016-05-11 11:52:29 -07:00
fi
echo "$CONTAINER_TYPES"
}
2015-07-13 08:24:46 -07:00
is_deployed() {
2016-03-08 15:30:34 -05:00
declare desc="return 0 if given app has a running container"
2015-09-03 18:55:52 -07:00
local APP="$1"
2019-05-10 17:02:26 -04:00
2021-02-13 00:46:35 -05:00
"$PLUGIN_CORE_AVAILABLE_PATH/common/common" --quiet is-deployed "$APP"
2015-07-13 08:24:46 -07:00
}
2018-04-10 20:21:25 -04:00
is_container_running() {
declare desc="return 0 if given docker container id is in running state"
declare deprecated=true
2018-04-28 01:27:34 -04:00
declare CID="$1"
local CONTAINER_STATUS
dokku_log_warn "Deprecated: common#is_container_status"
2019-05-29 04:05:24 -04:00
CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format '{{.State.Running}}' "$CID" || true)
2018-04-10 20:21:25 -04:00
if [[ "$CONTAINER_STATUS" == "true" ]]; then
return 0
fi
2018-04-28 01:27:34 -04:00
return 1
2018-04-10 20:21:25 -04:00
}
2016-07-29 04:51:36 -04:00
is_container_status() {
2016-03-08 15:30:34 -05:00
declare desc="return 0 if given docker container id is in given state"
2015-08-29 02:31:03 -04:00
local CID=$1
local TEMPLATE="{{.State.$2}}"
2019-05-29 04:05:24 -04:00
local CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format "$TEMPLATE" "$CID" 2>/dev/null || true)
2015-08-29 02:31:03 -04:00
if [[ "$CONTAINER_STATUS" == "true" ]]; then
return 0
fi
2018-04-28 01:27:34 -04:00
return 1
2015-08-29 02:31:03 -04:00
}
2015-07-13 08:24:46 -07:00
is_app_running() {
2016-03-08 15:30:34 -05:00
declare desc="return 0 if given app has a running container"
2018-04-28 01:27:34 -04:00
declare deprecated=true
2015-07-13 08:24:46 -07:00
local APP="$1"
2018-04-28 01:27:34 -04:00
2020-07-17 19:45:52 -04:00
dokku_log_warn "Deprecated: ps#fn-ps-is-app-running"
2015-07-13 08:24:46 -07:00
2019-09-20 12:31:12 -04:00
local APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP" 2>/dev/null)
2015-07-13 08:24:46 -07:00
if [[ -n "$APP_RUNNING_CONTAINER_IDS" ]]; then
return 0
2015-07-12 15:56:52 -07:00
else
2015-07-13 08:24:46 -07:00
return 1
2015-07-12 15:56:52 -07:00
fi
}
2015-06-10 14:21:47 -07:00
2016-06-17 16:40:35 -07:00
dokku_build() {
declare desc="build phase"
2019-07-30 14:29:48 -04:00
declare APP="$1" IMAGE_SOURCE_TYPE="$2" SOURCECODE_WORK_DIR="$3"
2016-06-17 16:40:35 -07:00
2019-07-30 14:29:48 -04:00
plugn trigger builder-build "$IMAGE_SOURCE_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
2016-06-17 16:40:35 -07:00
}
dokku_release() {
declare desc="release phase"
2019-06-29 15:33:24 -04:00
declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE_TAG="$3"
2020-12-01 14:49:39 -05:00
local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
if is_image_cnb_based "$IMAGE"; then
2021-02-28 16:02:22 -05:00
IMAGE_SOURCE_TYPE="pack"
2020-12-01 14:49:39 -05:00
fi
2019-07-30 14:29:48 -04:00
plugn trigger builder-release "$IMAGE_SOURCE_TYPE" "$APP" "$IMAGE_TAG"
2016-06-17 16:40:35 -07:00
}
2020-02-09 22:41:39 -05:00
cmd-deploy() {
2016-06-17 16:40:35 -07:00
declare desc="deploy phase"
2018-02-07 15:41:59 -07:00
declare APP="$1" IMAGE_TAG="$2"
2018-06-04 11:42:42 -04:00
source "$PLUGIN_AVAILABLE_PATH/config/functions"
2016-06-17 16:40:35 -07:00
2020-12-25 01:45:35 -05:00
verify_app_name "$APP"
2018-09-30 21:36:53 -04:00
local DOKKU_SCHEDULER=$(get_app_scheduler "$APP")
2018-02-07 15:41:59 -07:00
plugn trigger scheduler-deploy "$DOKKU_SCHEDULER" "$APP" "$IMAGE_TAG"
2016-06-17 16:40:35 -07:00
}
2015-06-10 14:21:47 -07:00
release_and_deploy() {
2016-03-08 15:30:34 -05:00
declare desc="main function for releasing and deploying an app"
2016-03-02 10:50:09 -08:00
source "$PLUGIN_AVAILABLE_PATH/config/functions"
2019-01-07 01:04:17 -05:00
local APP="$1"
2021-08-05 04:16:49 -04:00
local IMAGE_TAG="${2:-latest}"
2019-01-07 01:04:17 -05:00
local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
2017-03-26 05:03:16 -06:00
local DOKKU_DOCKERFILE_PORTS
2015-06-10 14:21:47 -07:00
if verify_image "$IMAGE"; then
2019-11-19 12:14:37 -07:00
if is_image_herokuish_based "$IMAGE" "$APP"; then
2016-03-01 13:26:35 -08:00
local IMAGE_SOURCE_TYPE="herokuish"
2015-06-10 14:21:47 -07:00
else
2016-03-01 13:26:35 -08:00
local IMAGE_SOURCE_TYPE="dockerfile"
2017-03-26 05:03:16 -06:00
DOKKU_DOCKERFILE_PORTS=$(config_get "$APP" DOKKU_DOCKERFILE_PORTS || true)
2016-05-06 11:30:22 -07:00
if [[ -z "$DOKKU_DOCKERFILE_PORTS" ]]; then
local DOCKER_IMAGE_PORTS=$(get_exposed_ports_from_image "$IMAGE")
[[ -n "$DOCKER_IMAGE_PORTS" ]] && config_set --no-restart "$APP" DOKKU_DOCKERFILE_PORTS="$DOCKER_IMAGE_PORTS"
fi
2015-06-10 14:21:47 -07:00
fi
2016-03-02 10:50:09 -08:00
local DOKKU_APP_SKIP_DEPLOY="$(config_get "$APP" DOKKU_SKIP_DEPLOY || true)"
local DOKKU_GLOBAL_SKIP_DEPLOY="$(config_get --global DOKKU_SKIP_DEPLOY || true)"
2015-12-17 21:07:58 +01:00
2016-03-01 13:26:35 -08:00
local DOKKU_SKIP_DEPLOY=${DOKKU_APP_SKIP_DEPLOY:="$DOKKU_GLOBAL_SKIP_DEPLOY"}
2015-12-17 21:07:58 +01:00
2020-05-05 23:39:38 -04:00
dokku_log_info1 "Releasing $APP..."
2021-08-05 04:16:49 -04:00
plugn trigger pre-deploy "$APP" "$IMAGE_TAG"
2016-06-17 16:40:35 -07:00
dokku_release "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG"
2015-12-17 21:07:58 +01:00
if [[ "$DOKKU_SKIP_DEPLOY" != "true" ]]; then
2020-05-05 23:39:38 -04:00
dokku_log_info1 "Deploying $APP..."
2020-02-09 22:41:39 -05:00
cmd-deploy "$APP" "$IMAGE_TAG"
2015-12-17 21:07:58 +01:00
dokku_log_info2 "Application deployed:"
2016-03-02 10:50:09 -08:00
get_app_urls urls "$APP" | sed "s/^/ /"
2015-12-17 21:07:58 +01:00
else
dokku_log_info1 "Skipping deployment"
fi
2015-06-10 14:21:47 -07:00
echo
fi
}
2015-09-06 19:21:12 -04:00
2016-06-17 16:40:35 -07:00
dokku_receive() {
declare desc="receives an app kicks off deploy process"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
2019-01-07 01:04:17 -05:00
local APP="$1"
local IMAGE=$(get_app_image_name "$APP")
local IMAGE_SOURCE_TYPE="$2"
local TMP_WORK_DIR="$3"
2020-12-01 14:49:39 -05:00
2017-07-02 16:54:26 -06:00
docker_cleanup "$APP"
2020-12-01 14:49:39 -05:00
local DOKKU_CNB_EXPERIMENTAL="$(config_get "$APP" DOKKU_CNB_EXPERIMENTAL || true)"
if [[ "$DOKKU_CNB_EXPERIMENTAL" == "1" ]]; then
2021-02-28 16:02:22 -05:00
IMAGE_SOURCE_TYPE="pack"
2020-12-01 14:49:39 -05:00
fi
2019-03-12 21:08:47 -04:00
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_APP_TYPE="$IMAGE_SOURCE_TYPE"
2016-06-17 16:40:35 -07:00
dokku_build "$APP" "$IMAGE_SOURCE_TYPE" "$TMP_WORK_DIR"
2020-10-10 17:32:21 -04:00
plugn trigger release-and-deploy "$APP"
2016-06-17 16:40:35 -07:00
}
2015-09-06 19:21:12 -04:00
docker_cleanup() {
2016-03-08 15:30:34 -05:00
declare desc="cleans up all exited/dead containers and removes all dangling images"
2017-07-02 16:54:26 -06:00
declare APP="$1" FORCE_CLEANUP="$2"
local DOKKU_APP_SKIP_CLEANUP
2018-02-12 02:17:44 -05:00
source "$PLUGIN_AVAILABLE_PATH/config/functions"
2017-07-02 16:54:26 -06:00
2017-07-02 17:20:04 -06:00
if [[ "$FORCE_CLEANUP" != "true" ]]; then
2018-12-18 02:30:11 -05:00
[[ -n "$APP" ]] && DOKKU_APP_SKIP_CLEANUP="$(config_get "$APP" DOKKU_SKIP_CLEANUP || true)"
2017-07-02 16:54:26 -06:00
if [[ -n "$DOKKU_SKIP_CLEANUP" ]] || [[ -n "$DOKKU_APP_SKIP_CLEANUP" ]]; then
dokku_log_info1 "DOKKU_SKIP_CLEANUP set. Skipping dokku cleanup"
return
fi
fi
dokku_log_info1 "Cleaning up..."
2018-09-30 21:36:53 -04:00
local DOKKU_SCHEDULER=$(get_app_scheduler "$APP")
2019-07-18 04:28:45 -04:00
if [[ "$APP" == "--global" ]]; then
APP=""
fi
2018-04-02 23:28:29 -04:00
plugn trigger scheduler-docker-cleanup "$DOKKU_SCHEDULER" "$APP" "$FORCE_CLEANUP"
2017-07-02 16:54:26 -06:00
2019-07-18 04:28:45 -04:00
if [[ -n "$APP" ]]; then
# delete all non-running containers
# shellcheck disable=SC2046
2019-05-29 04:05:24 -04:00
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true
2019-07-18 04:28:45 -04:00
# delete all dead containers
# shellcheck disable=SC2046
2019-05-29 04:05:24 -04:00
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true
2015-09-08 11:21:38 -04:00
2019-07-18 04:28:45 -04:00
# delete danging images
# shellcheck disable=SC2046
2019-05-29 04:05:24 -04:00
"$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true
2015-10-15 13:49:42 +02:00
2019-07-18 04:28:45 -04:00
# delete unused images
2019-08-03 14:21:34 -04:00
"$DOCKER_BIN" image prune --all --filter "label=com.dokku.app-name=$APP" --force &>/dev/null || true
2019-07-18 04:28:45 -04:00
else
# delete all non-running containers
# shellcheck disable=SC2046
2019-05-29 04:05:24 -04:00
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true
2019-07-18 04:28:45 -04:00
# delete all dead containers
# shellcheck disable=SC2046
2019-05-29 04:05:24 -04:00
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true
2019-07-18 04:28:45 -04:00
# delete danging images
# shellcheck disable=SC2046
2019-05-29 04:05:24 -04:00
"$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --quiet) &>/dev/null || true
2019-07-18 04:28:45 -04:00
fi
2015-09-06 19:21:12 -04:00
}
2015-09-17 19:09:29 -07:00
2015-09-18 15:46:46 -07:00
get_available_port() {
2016-03-08 15:30:34 -05:00
declare desc="returns first currently unused port > 1024"
2015-09-17 19:09:29 -07:00
while true; do
local port=$(shuf -i 1025-65535 -n 1)
2016-02-22 10:16:57 -08:00
if ! nc -z 0.0.0.0 "$port"; then
echo "$port"
2015-09-17 19:09:29 -07:00
return 0
else
continue
fi
done
}
2015-11-08 15:36:04 -05:00
dokku_auth() {
2016-03-08 15:30:34 -05:00
declare desc="calls user-auth plugin trigger"
2015-11-08 15:36:04 -05:00
export SSH_USER=${SSH_USER:=$USER}
export SSH_NAME=${NAME:="default"}
2019-08-01 20:18:14 -04:00
# this plugin trigger exists in the core `20_events` plugin
if [[ $(find "$PLUGIN_PATH"/enabled/*/user-auth 2>/dev/null | wc -l) == 1 ]]; then
return 0
fi
2019-01-07 01:04:17 -05:00
if ! plugn trigger user-auth "$SSH_USER" "$SSH_NAME" "$@"; then
2015-11-08 15:36:04 -05:00
return 1
fi
return 0
}
2015-11-19 09:10:04 -05:00
_ipv4_regex() {
2016-03-08 15:30:34 -05:00
declare desc="ipv4 regex"
2015-11-19 09:10:04 -05:00
echo "([0-9]{1,3}[\.]){3}[0-9]{1,3}"
}
_ipv6_regex() {
2016-03-08 15:30:34 -05:00
declare desc="ipv6 regex"
2015-11-19 09:10:04 -05:00
local RE_IPV4="$(_ipv4_regex)"
2019-01-07 01:04:17 -05:00
local RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8
local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7::
local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8
local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8
local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8
local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8
local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8
local RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8
local RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::
local RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index)
local RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33
2015-11-19 09:10:04 -05:00
echo "$RE_IPV6"
}
get_ipv4_regex() {
2016-03-08 15:30:34 -05:00
declare desc="returns ipv4 regex"
2015-11-19 09:10:04 -05:00
local RE_IPV4="$(_ipv4_regex)"
# Ensure the ip address continues to the end of the line
2021-08-05 23:29:43 -04:00
# Fixes using a wildcard dns service such as sslip.io which allows for *.<ip address>.sslip.io
2015-11-19 09:10:04 -05:00
echo "${RE_IPV4}\$"
}
get_ipv6_regex() {
2016-03-08 15:30:34 -05:00
declare desc="returns ipv6 regex"
2016-01-14 23:30:10 +09:00
local RE_IPV6="$(_ipv6_regex)"
2015-11-19 09:10:04 -05:00
# Ensure the ip address continues to the end of the line
2021-08-05 23:29:43 -04:00
# Fixes using a wildcard dns service such as sslip.io which allows for *.<ip address>.sslip.io
2015-11-19 09:10:04 -05:00
echo "${RE_IPV6}\$"
}
2016-02-14 18:43:40 -08:00
get_dockerfile_exposed_ports() {
2016-03-08 15:30:34 -05:00
declare desc="return all exposed ports from passed file path"
2020-02-17 05:59:52 -05:00
local DOCKERFILE_PORTS=$(grep -E "^EXPOSE " "$1" | awk '{ print $2 }' | xargs) || true
2016-02-14 18:43:40 -08:00
echo "$DOCKERFILE_PORTS"
}
2016-05-06 11:30:22 -07:00
get_exposed_ports_from_image() {
declare desc="return all exposed ports from passed image name"
2019-01-07 01:04:17 -05:00
local IMAGE="$1"
verify_image "$IMAGE"
2016-05-06 11:30:22 -07:00
# shellcheck disable=SC2016
2019-05-29 04:05:24 -04:00
local DOCKER_IMAGE_EXPOSED_PORTS="$("$DOCKER_BIN" image inspect --format '{{range $key, $value := .Config.ExposedPorts}}{{$key}} {{end}}' "$IMAGE")"
2016-05-06 11:30:22 -07:00
echo "$DOCKER_IMAGE_EXPOSED_PORTS"
}
get_entrypoint_from_image() {
declare desc="return .Config.Entrypoint from passed image name"
2019-01-07 01:04:17 -05:00
local IMAGE="$1"
verify_image "$IMAGE"
2019-05-29 04:05:24 -04:00
local DOCKER_IMAGE_ENTRYPOINT="$("$DOCKER_BIN" image inspect --format '{{range .Config.Entrypoint}}{{.}} {{end}}' "$IMAGE")"
2016-05-06 11:30:22 -07:00
echo "ENTRYPOINT $DOCKER_IMAGE_ENTRYPOINT"
}
get_cmd_from_image() {
declare desc="return .Config.Cmd from passed image name"
2019-01-07 01:04:17 -05:00
local IMAGE="$1"
verify_image "$IMAGE"
2019-05-29 04:05:24 -04:00
local DOCKER_IMAGE_CMD="$("$DOCKER_BIN" image inspect --format '{{range .Config.Cmd}}{{.}} {{end}}' "$IMAGE")"
2016-05-06 11:30:22 -07:00
DOCKER_IMAGE_CMD="${DOCKER_IMAGE_CMD/\/bin\/sh -c/}"
echo "CMD $DOCKER_IMAGE_CMD"
}
2016-04-01 13:47:22 -07:00
extract_directive_from_dockerfile() {
declare desc="return requested directive from passed file path"
2019-01-07 01:04:17 -05:00
local FILE_PATH="$1"
local SEARCH_STRING="$2"
2020-02-17 05:59:52 -05:00
local FOUND_LINE=$(grep -E "^${SEARCH_STRING} " "$FILE_PATH" | tail -n1) || true
2016-04-01 13:47:22 -07:00
echo "$FOUND_LINE"
}
2016-02-14 18:43:40 -08:00
get_app_raw_tcp_ports() {
2016-03-08 15:30:34 -05:00
declare desc="extracts raw tcp port numbers from DOCKERFILE_PORTS config variable"
2016-03-01 13:26:35 -08:00
source "$PLUGIN_AVAILABLE_PATH/config/functions"
2019-01-07 01:04:17 -05:00
local APP="$1"
2016-02-22 10:16:57 -08:00
local DOCKERFILE_PORTS="$(config_get "$APP" DOKKU_DOCKERFILE_PORTS)"
2016-02-14 18:43:40 -08:00
for p in $DOCKERFILE_PORTS; do
if [[ ! "$p" =~ .*udp.* ]]; then
2019-01-07 01:04:17 -05:00
p=${p//\/tcp/}
2016-02-14 18:43:40 -08:00
raw_tcp_ports+="$p "
fi
done
2019-01-07 01:04:17 -05:00
local raw_tcp_ports="$(echo "$raw_tcp_ports" | xargs)"
2016-02-14 18:43:40 -08:00
echo "$raw_tcp_ports"
}
get_container_ports() {
2016-03-08 15:30:34 -05:00
declare desc="returns published ports from app containers"
2019-01-07 01:04:17 -05:00
local APP="$1"
2016-02-22 10:16:57 -08:00
local APP_CIDS="$(get_app_container_ids "$APP")"
2016-02-14 18:43:40 -08:00
local cid
for cid in $APP_CIDS; do
2019-05-29 04:05:24 -04:00
local container_ports="$("$DOCKER_BIN" container port "$cid" | awk '{ print $3 "->" $1}' | awk -F ":" '{ print $2 }')"
2016-02-14 18:43:40 -08:00
done
2016-02-22 10:16:57 -08:00
echo "$container_ports"
2016-02-14 18:43:40 -08:00
}
get_app_urls() {
2018-04-26 19:21:29 -04:00
declare desc="print an app's available urls"
declare URL_TYPE="$1" APP="$2"
local urls
urls=$(plugn trigger app-urls "$APP" "$URL_TYPE")
if [[ -n "$urls" ]]; then
echo "$urls" | sort
else
2021-02-13 03:52:28 -05:00
internal_get_app_urls "$URL_TYPE" "$APP" | sort
2018-04-26 19:21:29 -04:00
fi
}
internal_get_app_urls() {
2016-03-08 15:30:34 -05:00
declare desc="print an app's available urls"
2016-07-11 15:41:05 +02:00
source "$PLUGIN_AVAILABLE_PATH/certs/functions"
2016-03-01 13:26:35 -08:00
source "$PLUGIN_AVAILABLE_PATH/config/functions"
2020-07-04 00:08:44 +02:00
2018-04-26 19:21:29 -04:00
local APP="$2"
2016-02-14 18:43:40 -08:00
local URLS_FILE="$DOKKU_ROOT/$APP/URLS"
2016-06-14 17:36:26 -07:00
local DOKKU_PROXY_PORT_MAP=$(config_get "$APP" DOKKU_PROXY_PORT_MAP || true)
2016-02-14 18:43:40 -08:00
if [[ -s "$URLS_FILE" ]]; then
2020-02-17 05:59:52 -05:00
local app_urls="$(grep -v -E "^#" "$URLS_FILE")"
2016-06-14 17:36:26 -07:00
if [[ -n "$DOKKU_PROXY_PORT_MAP" ]]; then
local port_map app_vhost
2020-05-06 00:16:51 -04:00
local app_vhosts=$(plugn trigger domains-list "$APP")
2016-06-14 17:36:26 -07:00
for port_map in $DOKKU_PROXY_PORT_MAP; do
2019-01-07 01:04:17 -05:00
local scheme="$(awk -F ':' '{ print $1 }' <<<"$port_map")"
local listen_port="$(awk -F ':' '{ print $2 }' <<<"$port_map")"
2016-06-14 17:36:26 -07:00
for app_vhost in $app_vhosts; do
if [[ "$listen_port" != "80" ]] && [[ "$listen_port" != "443" ]]; then
port_urls+=" $scheme://$app_vhost:$listen_port "
else
port_urls+=" $scheme://$app_vhost "
fi
2016-02-14 18:43:40 -08:00
done
done
fi
2019-01-07 01:04:17 -05:00
local port_urls="$(echo "$port_urls" | xargs)"
2016-06-14 17:36:26 -07:00
local URLS="$(merge_dedupe_list "$port_urls $app_urls" " ")"
2016-02-14 18:43:40 -08:00
case "$1" in
url)
2016-07-11 15:41:05 +02:00
if is_ssl_enabled "$APP"; then
echo "$URLS" | tr ' ' '\n' | grep https | head -n1
else
echo "$URLS" | tr ' ' '\n' | head -n1
fi
2019-01-07 01:04:17 -05:00
;;
2016-02-14 18:43:40 -08:00
urls)
2016-06-14 17:36:26 -07:00
echo "$URLS" | tr ' ' '\n' | sort
2019-01-07 01:04:17 -05:00
;;
2016-02-14 18:43:40 -08:00
esac
else
2021-08-06 17:48:39 -04:00
if [[ -s "$DOKKU_ROOT/VHOST" ]]; then
while read -r VHOST || [[ -n "$VHOST" ]]; do
internal_get_app_url_with_vhost "$APP" "$VHOST"
done <"$DOKKU_ROOT/VHOST"
else
internal_get_app_url_with_vhost "$APP" "$(hostname -f)"
2016-02-14 18:43:40 -08:00
fi
2021-08-06 17:48:39 -04:00
fi
}
2016-02-14 18:43:40 -08:00
2021-08-06 17:48:39 -04:00
internal_get_app_url_with_vhost() {
declare APP="$1" VHOST="$2"
local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"
local DOKKU_PROXY_PORT_MAP=$(config_get "$APP" DOKKU_PROXY_PORT_MAP || true)
local SCHEME="http"
local SSL="$DOKKU_ROOT/$APP/tls"
if [[ -e "$SSL/server.crt" && -e "$SSL/server.key" ]]; then
local SCHEME="https"
fi
if [[ "$(plugn trigger proxy-is-enabled "$APP")" == "false" ]]; then
if [[ -n "$RAW_TCP_PORTS" ]]; then
local APP_CONTAINER_PORTS="$(get_container_ports "$APP")"
local app_port
for app_port in $APP_CONTAINER_PORTS; do
echo "$VHOST:$app_port (container)"
2016-02-14 18:43:40 -08:00
done
else
2021-08-06 17:48:39 -04:00
local DOKKU_APP_WEB_LISTENERS PORT
DOKKU_APP_WEB_LISTENERS="$(plugn trigger network-get-listeners "$APP" "web" | xargs)"
for DOKKU_APP_WEB_LISTENER in $DOKKU_APP_WEB_LISTENERS; do
PORT="$(echo "$DOKKU_APP_WEB_LISTENER" | cut -d ':' -f2)"
echo "$SCHEME://$VHOST:$PORT (container)"
done
shopt -u nullglob
2016-02-14 18:43:40 -08:00
fi
2021-08-06 17:48:39 -04:00
elif [[ -n "$DOKKU_PROXY_PORT_MAP" ]]; then
local port_map
for port_map in $DOKKU_PROXY_PORT_MAP; do
local scheme="$(awk -F ':' '{ print $1 }' <<<"$port_map")"
local listen_port="$(awk -F ':' '{ print $2 }' <<<"$port_map")"
echo "$scheme://$VHOST:$listen_port"
done
elif [[ -n "$RAW_TCP_PORTS" ]]; then
for p in $RAW_TCP_PORTS; do
echo "http://$VHOST:$p"
done
else
echo "$SCHEME://$VHOST"
2016-02-14 18:43:40 -08:00
fi
}
2016-01-06 18:18:57 -08:00
get_json_value() {
2016-03-08 15:30:34 -05:00
declare desc="return value of provided json key from a json stream on stdin"
2016-01-06 18:18:57 -08:00
# JSON_NODE should be expresses as either a top-level object that has no children
2019-09-17 03:06:00 -04:00
# or in the format of .json.node.path
2016-01-06 18:18:57 -08:00
local JSON_NODE="$1"
2019-09-17 03:06:00 -04:00
cat | jq -r "${JSON_NODE} | select (.!=null)" 2>/dev/null
2016-01-06 18:18:57 -08:00
}
2016-03-29 16:14:08 -07:00
strip_inline_comments() {
declare desc="removes bash-style comment from input line"
local line="$1"
local stripped_line="${line%[[:space:]]#*}"
echo "$stripped_line"
}
2016-06-09 16:17:45 -07:00
is_val_in_list() {
declare desc="return true if value ($1) is in list ($2) separated by delimiter ($3); delimiter defaults to comma"
local value="$1" list="$2" delimiter="${3:-,}"
local IFS="$delimiter" val_in_list=false
for val in $list; do
if [[ "$val" == "$value" ]]; then
val_in_list=true
fi
done
echo "$val_in_list"
}
2016-05-09 16:03:07 -07:00
2019-12-19 02:15:18 -05:00
fn-in-array() {
declare desc="return true if value ($1) is in list (all other arguments)"
local e
for e in "${@:2}"; do
[[ "$e" == "$1" ]] && return 0
done
return 1
}
2016-05-09 16:03:07 -07:00
remove_val_from_list() {
declare desc="remove value ($1) from list ($2) separated by delimiter ($3) (delimiter defaults to comma) and return list"
local value="$1" list="$2" delimiter="${3:-,}"
list="${list//$value/}"
list="${list//$delimiter$delimiter/$delimiter}"
list="${list/#$delimiter/}"
list="${list/%$delimiter/}"
echo "$list"
}
add_val_to_list() {
declare desc="add value ($1) to list ($2) separated by delimiter ($3) (delimiter defaults to comma) and return list"
local value="$1" list="$2" delimiter="${3:-,}"
list+="${delimiter}$value"
echo "$list"
}
2016-06-14 17:36:26 -07:00
merge_dedupe_list() {
declare desc="combine lists ($1) separated by delimiter ($2) (delimiter defaults to comma), dedupe and return list"
local input_lists="$1" delimiter="${2:-,}"
2019-01-07 01:04:17 -05:00
local merged_list="$(tr "$delimiter" $'\n' <<<"$input_lists" | sort | uniq | xargs)"
2016-06-14 17:36:26 -07:00
echo "$merged_list"
}
2016-06-17 15:25:46 -07:00
acquire_app_deploy_lock() {
declare desc="acquire advisory lock for use in git/tar deploys"
2019-01-07 01:04:17 -05:00
local APP="$1"
2016-06-17 16:10:51 -07:00
local LOCK_TYPE="${2:-waiting}"
2016-06-17 15:25:46 -07:00
local APP_DEPLOY_LOCK_FILE="$DOKKU_ROOT/$APP/.deploy.lock"
2018-03-04 01:04:21 -05:00
local LOCK_WAITING_MSG="$APP currently has a deploy lock in place. Waiting..."
local LOCK_FAILED_MSG="$APP currently has a deploy lock in place. Exiting..."
2018-07-20 02:53:17 -04:00
acquire_advisory_lock "$APP_DEPLOY_LOCK_FILE" "$LOCK_TYPE" "$LOCK_WAITING_MSG" "$LOCK_FAILED_MSG"
}
release_app_deploy_lock() {
declare desc="release advisory lock used in git/tar deploys"
2019-01-07 01:04:17 -05:00
local APP="$1"
2018-07-20 02:53:17 -04:00
local APP_DEPLOY_LOCK_FILE="$DOKKU_ROOT/$APP/.deploy.lock"
release_advisory_lock "$APP_DEPLOY_LOCK_FILE"
}
acquire_advisory_lock() {
declare desc="acquire advisory lock"
local LOCK_FILE="$1" LOCK_TYPE="$2" LOCK_WAITING_MSG="$3" LOCK_FAILED_MSG="$4"
local LOCK_FD="200"
2016-06-17 15:25:46 -07:00
local SHOW_MSG=true
2018-07-26 10:09:02 -04:00
eval "exec $LOCK_FD>$LOCK_FILE"
2016-06-17 16:10:51 -07:00
if [[ "$LOCK_TYPE" == "waiting" ]]; then
2019-01-07 01:04:17 -05:00
while [[ $(
flock -n "$LOCK_FD" &>/dev/null
echo $?
) -ne 0 ]]; do
2016-06-17 16:10:51 -07:00
if [[ "$SHOW_MSG" == "true" ]]; then
echo "$LOCK_WAITING_MSG"
SHOW_MSG=false
fi
sleep 1
done
else
2021-07-11 21:33:32 -04:00
if ! flock -n "$LOCK_FD" &>/dev/null; then
dokku_log_warn "$LOCK_FAILED_MSG"
dokku_log_fail "Run 'apps:unlock' to release the existing deploy lock"
fi
2016-06-17 16:10:51 -07:00
fi
2016-06-17 15:25:46 -07:00
}
2018-07-20 02:53:17 -04:00
release_advisory_lock() {
declare desc="release advisory lock"
local LOCK_FILE="$1"
local LOCK_FD="200"
2016-06-17 15:25:46 -07:00
2019-01-07 01:04:17 -05:00
flock -u "$LOCK_FD" && rm -f "$LOCK_FILE" &>/dev/null
2016-06-17 15:25:46 -07:00
}
2018-03-05 23:47:10 -05:00
suppress_output() {
declare desc="suppress all output from a given command unless there is an error"
local TMP_COMMAND_OUTPUT
2019-08-12 18:16:16 -04:00
TMP_COMMAND_OUTPUT=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
2019-05-20 17:57:13 -07:00
trap "rm -rf '$TMP_COMMAND_OUTPUT' >/dev/null" RETURN
2018-03-05 23:47:10 -05:00
2019-01-07 01:04:17 -05:00
"$@" >"$TMP_COMMAND_OUTPUT" 2>&1 || {
2018-03-05 23:47:10 -05:00
local exit_code="$?"
cat "$TMP_COMMAND_OUTPUT"
return "$exit_code"
}
return 0
2018-04-10 14:12:10 -04:00
}