#!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x has_tty() { if [[ "$(/usr/bin/tty || true)" == "not a tty" ]]; then return 1 else return 0 fi } dokku_log_info1() { echo "-----> $@" } dokku_log_info2() { echo "=====> $@" } dokku_log_info1_quiet() { if [[ -z "$DOKKU_QUIET_OUTPUT" ]];then echo "-----> $@" else return 0 fi } dokku_log_info2_quiet() { if [[ -z "$DOKKU_QUIET_OUTPUT" ]];then echo "=====> $@" else return 0 fi } dokku_col_log_info1() { printf "%-25s %-25s %-25s %-25s\n" "-----> $@" } dokku_col_log_info1_quiet() { if [[ -z "$DOKKU_QUIET_OUTPUT" ]];then printf "%-25s %-25s %-25s %-25s\n" "-----> $@" else return 0 fi } dokku_col_log_info2() { printf "%-25s %-25s %-25s %-25s\n" "=====> $@" } dokku_col_log_info2_quiet() { if [[ -z "$DOKKU_QUIET_OUTPUT" ]];then printf "%-25s %-25s %-25s %-25s\n" "=====> $@" else return 0 fi } dokku_col_log_msg() { printf "%-25s %-25s %-25s %-25s\n" "$@" } dokku_col_log_msg_quiet() { if [[ -z "$DOKKU_QUIET_OUTPUT" ]];then printf "%-25s %-25s %-25s %-25s\n" "$@" else return 0 fi } dokku_log_verbose_quiet() { if [[ -z "$DOKKU_QUIET_OUTPUT" ]];then echo " $@" else return 0 fi } dokku_log_verbose() { echo " $@" } dokku_log_warn() { echo " ! $@" } dokku_log_fail() { echo "$@" 1>&2 exit 1 } dokku_log_event() { logger -t dokku -i -- "$@" } dokku_log_pluginhook_call() { local l_hook l_hook="$1" ; shift dokku_log_event "INVOKED: ${l_hook}( $@ )" } dokku_container_log_verbose_quiet() { local CID=$1; shift OIFS=$IFS IFS=$'\n' for line in $(docker logs $CID 2>&1); do dokku_log_verbose_quiet "$line" done IFS=$OIFS } verify_app_name() { local APP="$1" [[ ! -n "$APP" ]] && dokku_log_fail "(verify_app_name) APP must not be null" [[ ! -d "$DOKKU_ROOT/$APP" ]] && dokku_log_fail "App $APP does not exist" return 0 } verify_image() { local IMAGE="$1" if (docker inspect "$IMAGE" &>/dev/null); then return 0 else return 1 fi } get_app_image_repo() { # central definition of our image repo pattern local APP="$1"; local IMAGE_REPO="dokku/$APP" [[ -z "$APP" ]] && dokku_log_fail "(get_app_image_repo) APP must not be null" echo $IMAGE_REPO } get_app_image_name() { # return image identifier for a given app, tag tuple. validate if tag is presented local APP="$1"; local IMAGE_TAG="$2"; local IMAGE_REPO=$(get_app_image_repo $APP) [[ -z "$APP" ]] && dokku_log_fail "(get_app_image_name) APP must not be null" if [[ -n "$IMAGE_TAG" ]]; then IMAGE="$IMAGE_REPO:$IMAGE_TAG" verify_image "$IMAGE" || dokku_log_fail "app image ($IMAGE) not found" else IMAGE="$IMAGE_REPO:latest" fi echo $IMAGE } get_running_image_tag() { # retrieve current image tag for a given app. returns empty string if no deployed containers are found local APP="$1" [[ ! -n "$APP" ]] && dokku_log_fail "(get_running_image_tag) APP must not be null" verify_app_name "$APP" CIDS=( $(get_app_container_ids $APP) ) RUNNING_IMAGE_TAG=$(docker ps -a --no-trunc | egrep ${CIDS[0]} 2>/dev/null | awk '{ print $2 }' | awk -F: '{ print $2 }' || echo '') echo $RUNNING_IMAGE_TAG } is_image_herokuish_based() { # circleci can't support --rm as they run lxc in lxc [[ ! -f "/home/ubuntu/.circlerc" ]] && local DOCKER_ARGS="--rm" docker run --entrypoint="/bin/sh" $DOCKER_ARGS "$@" -c "test -f /exec" } is_number() { local NUMBER=$1; local NUM_RE='^[0-9]+$' if [[ $NUMBER =~ $NUM_RE ]];then return 0 else return 1 fi } parse_args() { for arg in "$@"; do case "$arg" in --quiet) export DOKKU_QUIET_OUTPUT=1 ;; --trace) export DOKKU_TRACE=1 ;; --rm-container|--rm) export DOKKU_RM_CONTAINER=1 ;; --force) export DOKKU_APPS_FORCE_DELETE=1 ;; esac done return 0 } copy_from_image() { local IMAGE="$1"; local SRC_FILE="$2"; local DST_DIR="$3" verify_app_name $APP if verify_image "$IMAGE"; then CID=$(docker run -d $IMAGE bash) docker cp "$CID:$SRC_FILE" "$DST_DIR" docker rm -f "$CID" &> /dev/null else return 1 fi } get_app_container_ids() { local APP="$1"; local CONTAINER_TYPE="$2" verify_app_name $APP [[ -f $DOKKU_ROOT/$APP/CONTAINER ]] && DOKKU_CIDS+=$(< $DOKKU_ROOT/$APP/CONTAINER) if [[ -n "$CONTAINER_TYPE" ]]; then CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE.*" if [[ $CONTAINER_TYPE == *.* ]]; then CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE" [[ ! -f $CONTAINER_PATTERN ]] && echo "" && return 0 fi else CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.*" fi shopt -s nullglob for DOKKU_CID_FILE in $CONTAINER_PATTERN; do DOKKU_CIDS+=" " DOKKU_CIDS+=$(< $DOKKU_CID_FILE) DOKKU_CIDS+=" " done shopt -u nullglob echo $DOKKU_CIDS } get_dockerfile_exposed_port() { local DOCKERFILE_PORT=$(grep "^EXPOSE \+[[:digit:]]\+\(\/tcp\)\? *$" $1 | head -1 | sed 's/EXPOSE \+\([[:digit:]]\+\)\(\/tcp\)\?.*/\1/' || true) echo "$DOCKERFILE_PORT" } get_app_running_container_ids() { local APP=$1 verify_app_name $APP ! (is_deployed $APP) && dokku_log_fail "App $APP has not been deployed" local CIDS=$(get_app_container_ids $APP) for CID in $CIDS;do local APP_CONTAINER_STATUS=$(docker inspect -f '{{.State.Running}}' "$CID" || true) [[ "$APP_CONTAINER_STATUS" == "true" ]] && local APP_RUNNING_CONTAINER_IDS+="$CID " done echo "$APP_RUNNING_CONTAINER_IDS" } is_deployed() { local APP="$1" if [[ -f "$DOKKU_ROOT/$APP/CONTAINER" ]] || [[ $(ls $DOKKU_ROOT/$APP/CONTAINER.* &> /dev/null; echo $?) -eq 0 ]];then return 0 else return 1 fi } is_container_running () { local CID=$1 local CONTAINER_STATUS=$(docker inspect -f '{{.State.Running}}' "$CID" || true) if [[ "$CONTAINER_STATUS" == "true" ]]; then return 0 else return 1 fi } is_container_status () { local CID=$1 local TEMPLATE="{{.State.$2}}" local CONTAINER_STATUS=$(docker inspect -f "$TEMPLATE" "$CID" || true) if [[ "$CONTAINER_STATUS" == "true" ]]; then return 0 else return 1 fi } is_app_running() { local APP="$1" verify_app_name $APP local APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids $APP) if [[ -n "$APP_RUNNING_CONTAINER_IDS" ]]; then return 0 else return 1 fi } release_and_deploy() { local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_app_image_name $APP $IMAGE_TAG) verify_app_name "$APP" if verify_image "$IMAGE"; then if is_image_herokuish_based "$IMAGE"; then IMAGE_SOURCE_TYPE="herokuish" else IMAGE_SOURCE_TYPE="dockerfile" fi dokku_log_info1 "Releasing $APP ($IMAGE)..." dokku release "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" dokku_log_info1 "Deploying $APP ($IMAGE)..." dokku deploy "$APP" "$IMAGE_TAG" dokku_log_info2 "Application deployed:" dokku urls $APP | sed "s/^/ /" echo fi }