diff --git a/plugins/run/internal-functions b/plugins/run/internal-functions index 2a15e60ef..af7d3c18b 100755 --- a/plugins/run/internal-functions +++ b/plugins/run/internal-functions @@ -206,13 +206,17 @@ cmd-run-logs() { dokku_log_fail "No container or app specified" fi + if ! is_number "$NUM"; then + dokku_log_fail "Invalid value for num: must be an integer" + fi + if [[ -n "$CONTAINER_NAME" ]]; then if [[ "$(echo "$CONTAINER_NAME" | grep -o '\.' | wc -l)" -ne 2 ]]; then dokku_log_fail "Invalid container name specified: $CONTAINER_NAME" fi if [[ -n "$APP" ]] && [[ "$APP" != "$(echo "$CONTAINER_NAME" | cut -d'.' -f1)" ]]; then - dokku_log_fail "Specified app does not app in container name" + dokku_log_fail "Specified app does not match app in container name" fi APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)" diff --git a/plugins/scheduler-docker-local/scheduler-logs b/plugins/scheduler-docker-local/scheduler-logs index 83a6a0ff8..d7131ab36 100755 --- a/plugins/scheduler-docker-local/scheduler-logs +++ b/plugins/scheduler-docker-local/scheduler-logs @@ -3,18 +3,31 @@ set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +fn-scheduler-docker-local-container-logs() { + declare desc="outputs logs for a single app container" + declare CID="$1" DYNO="$2" PRETTY_PRINT="$3" COLOR="$4" + shift 4 + + if [[ "$PRETTY_PRINT" == "true" ]]; then + "$DOCKER_BIN" logs "$@" "$CID" 2>&1 + return + fi + + "$DOCKER_BIN" logs -t "$@" "$CID" 2>&1 | sed -u -r "s/^([^Z]+Z )/\x1b[${COLOR}m\1app[${DYNO}]:\x1b[0m /gm" +} + trigger-scheduler-docker-local-scheduler-logs() { declare desc="scheduler-docker-local scheduler-logs plugin trigger" declare trigger="scheduler-logs" declare DOKKU_SCHEDULER="$1" APP="$2" PROCESS_TYPE="$3" TAIL="$4" PRETTY_PRINT="$5" NUM="$6" - local DOKKU_LOGS_ARGS="" + local DOCKER_LOGS_ARGS=("--tail" "$NUM") if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then return fi if [[ "$TAIL" == "true" ]]; then - DOKKU_LOGS_ARGS="--follow " + DOCKER_LOGS_ARGS+=("--follow") fi local APP_ROOT="$DOKKU_ROOT/$APP" @@ -26,25 +39,19 @@ trigger-scheduler-docker-local-scheduler-logs() { fi [[ -z $(stat -t "${CONTAINERS[0]}" 2>/dev/null) ]] && exit 0 - local DOKKU_LOGS_ARGS+="--tail $NUM" - ((MAX_INDEX = ${#CONTAINERS[*]} - 1)) || true - for i in ${!CONTAINERS[*]}; do - local DYNO=$(echo "${CONTAINERS[i]}" | sed -r 's/.*CONTAINER\.(.*)/\1/') - local CID=$(<"${CONTAINERS[i]}") - local COLOR=${COLORS[i % ${#COLORS[*]}]} - if [[ $PRETTY_PRINT == "true" ]]; then - local DOKKU_LOGS_CMD+="($DOCKER_BIN logs $DOKKU_LOGS_ARGS $CID 2>&1)" + local MAX_INDEX + ((MAX_INDEX = ${#CONTAINERS[@]} - 1)) || true + for i in "${!CONTAINERS[@]}"; do + local DYNO="$(echo "${CONTAINERS[i]}" | sed -r 's/.*CONTAINER\.(.*)/\1/')" + local CID="$(<"${CONTAINERS[i]}")" + local COLOR="${COLORS[i % ${#COLORS[@]}]}" + if [[ "$i" != "$MAX_INDEX" ]]; then + fn-scheduler-docker-local-container-logs "$CID" "$DYNO" "$PRETTY_PRINT" "$COLOR" "${DOCKER_LOGS_ARGS[@]}" & else - local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -u -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'" - local DOKKU_LOGS_CMD+="($DOCKER_BIN logs -t $DOKKU_LOGS_ARGS $CID 2>&1 | $DOKKU_LOGS_PRETTY_PRINT_CMD)" - fi - if [[ $i != "$MAX_INDEX" ]]; then - local DOKKU_LOGS_CMD+="& " - else - local DOKKU_LOGS_CMD+="; " + fn-scheduler-docker-local-container-logs "$CID" "$DYNO" "$PRETTY_PRINT" "$COLOR" "${DOCKER_LOGS_ARGS[@]}" fi done - bash -c "($DOKKU_LOGS_CMD)" + wait } trigger-scheduler-docker-local-scheduler-logs "$@" diff --git a/plugins/scheduler-docker-local/scheduler-logs-failed b/plugins/scheduler-docker-local/scheduler-logs-failed index d3cc93346..660f14f97 100755 --- a/plugins/scheduler-docker-local/scheduler-logs-failed +++ b/plugins/scheduler-docker-local/scheduler-logs-failed @@ -8,7 +8,7 @@ trigger-scheduler-docker-local-scheduler-logs-failed() { declare trigger="scheduler-logs-failed" declare DOKKU_SCHEDULER="$1" APP="$2" local FAILED_CONTAINERS_FILE="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/failed-containers" - local DEAD_CONTAINERS=() DOKKU_LOGS_CMD=() RUNNING_CONTAINERS=() + local DEAD_CONTAINERS=() RUNNING_CONTAINERS=() local CID LINE PREFIX shift 2 @@ -41,17 +41,16 @@ trigger-scheduler-docker-local-scheduler-logs-failed() { return fi - ((MAX_INDEX = ${#RUNNING_CONTAINERS[*]} - 1)) || true - for i in ${!RUNNING_CONTAINERS[*]}; do - local CID="${RUNNING_CONTAINERS[i]}" - DOKKU_LOGS_CMD+="($DOCKER_BIN logs $DOKKU_LOGS_ARGS $CID 2>&1)" - if [[ $i != "$MAX_INDEX" ]]; then - local DOKKU_LOGS_CMD+="& " + local MAX_INDEX + ((MAX_INDEX = ${#RUNNING_CONTAINERS[@]} - 1)) || true + for i in "${!RUNNING_CONTAINERS[@]}"; do + if [[ "$i" != "$MAX_INDEX" ]]; then + "$DOCKER_BIN" logs "${RUNNING_CONTAINERS[i]}" 2>&1 & else - local DOKKU_LOGS_CMD+="; " + "$DOCKER_BIN" logs "${RUNNING_CONTAINERS[i]}" 2>&1 fi done - bash -c "($DOKKU_LOGS_CMD)" + wait } trigger-scheduler-docker-local-scheduler-logs-failed "$@" diff --git a/plugins/scheduler-docker-local/scheduler-run-logs b/plugins/scheduler-docker-local/scheduler-run-logs index b657729f3..9fa30c66a 100755 --- a/plugins/scheduler-docker-local/scheduler-run-logs +++ b/plugins/scheduler-docker-local/scheduler-run-logs @@ -3,51 +3,59 @@ set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +fn-scheduler-docker-local-run-container-logs() { + declare desc="outputs logs for a single run container" + declare CONTAINER_NAME="$1" PRETTY_PRINT="$2" COLOR="$3" + shift 3 + local DYNO="$(echo "$CONTAINER_NAME" | cut -d. -f3)" + + if [[ "$PRETTY_PRINT" == "true" ]]; then + "$DOCKER_BIN" logs "$@" "$CONTAINER_NAME" 2>&1 + return + fi + + "$DOCKER_BIN" logs -t "$@" "$CONTAINER_NAME" 2>&1 | sed -u -r "s/^([^Z]+Z )/\x1b[${COLOR}m\1app[${DYNO}]:\x1b[0m /gm" +} + trigger-scheduler-docker-local-scheduler-logs() { declare desc="scheduler-docker-local scheduler-logs plugin trigger" declare trigger="scheduler-logs" declare DOKKU_SCHEDULER="$1" APP="$2" CONTAINER_NAME="$3" TAIL="$4" PRETTY_PRINT="$5" NUM="$6" - local DOKKU_LOGS_ARGS="" + local DOCKER_LOGS_ARGS=("--tail" "$NUM") + local COLORS=(36 33 32 35 31) + local CONTAINERS=() NAME NAMES if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then return fi if [[ "$TAIL" == "true" ]]; then - DOKKU_LOGS_ARGS="--follow " + DOCKER_LOGS_ARGS+=("--follow") fi - local COLORS=(36 33 32 35 31) - - if [[ -n "$CONTAINER_NAME" ]]; then - local CONTAINERS=("$CONTAINER_NAME") - else - local CONTAINERS=() - NAMES="$("$DOCKER_BIN" container ls --all --filter "label=com.dokku.app-name=$APP" --filter "label=com.dokku.container-type=run" --format '{{ .Names }}')" - while IFS= read -r CONTAINER_NAME; do - CONTAINERS+=("$CONTAINER_NAME") - done <<<"$NAMES" - fi - - local DOKKU_LOGS_ARGS+="--tail $NUM" - ((MAX_INDEX = ${#CONTAINERS[*]} - 1)) || true - for i in ${!CONTAINERS[*]}; do - local DYNO="$(echo "${CONTAINERS[i]}" | cut -d. -f3)" - local CID="${CONTAINERS[i]}" - local COLOR=${COLORS[i % ${#COLORS[*]}]} - if [[ $PRETTY_PRINT == "true" ]]; then - local DOKKU_LOGS_CMD+="($DOCKER_BIN logs $DOKKU_LOGS_ARGS $CID 2>&1)" - else - local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -u -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'" - local DOKKU_LOGS_CMD+="($DOCKER_BIN logs -t $DOKKU_LOGS_ARGS $CID 2>&1 | $DOKKU_LOGS_PRETTY_PRINT_CMD)" + NAMES="$("$DOCKER_BIN" container ls --all --filter "label=com.dokku.app-name=$APP" --filter "label=com.dokku.container-type=run" --format '{{ .Names }}')" + while IFS= read -r NAME; do + [[ -z "$NAME" ]] && continue + if [[ -z "$CONTAINER_NAME" ]] || [[ "$NAME" == "$CONTAINER_NAME" ]]; then + CONTAINERS+=("$NAME") fi - if [[ $i != "$MAX_INDEX" ]]; then - local DOKKU_LOGS_CMD+="& " + done <<<"$NAMES" + + if [[ -n "$CONTAINER_NAME" ]] && [[ ${#CONTAINERS[@]} -eq 0 ]]; then + dokku_log_fail "Specified container does not exist" + fi + + local MAX_INDEX + ((MAX_INDEX = ${#CONTAINERS[@]} - 1)) || true + for i in "${!CONTAINERS[@]}"; do + local COLOR="${COLORS[i % ${#COLORS[@]}]}" + if [[ "$i" != "$MAX_INDEX" ]]; then + fn-scheduler-docker-local-run-container-logs "${CONTAINERS[i]}" "$PRETTY_PRINT" "$COLOR" "${DOCKER_LOGS_ARGS[@]}" & else - local DOKKU_LOGS_CMD+="; " + fn-scheduler-docker-local-run-container-logs "${CONTAINERS[i]}" "$PRETTY_PRINT" "$COLOR" "${DOCKER_LOGS_ARGS[@]}" fi done - bash -c "($DOKKU_LOGS_CMD)" + wait } trigger-scheduler-docker-local-scheduler-logs "$@" diff --git a/tests/unit/run_1.bats b/tests/unit/run_1.bats index 91fda6ce9..b87bb0ffd 100644 --- a/tests/unit/run_1.bats +++ b/tests/unit/run_1.bats @@ -140,3 +140,65 @@ teardown() { assert_success assert_output_not_contains "$container_id" } + +@test "(run:logs) run:logs" { + run deploy_app + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku run:detached $TEST_APP worker" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku run:list $TEST_APP --format json | jq -r '.[0].name'" + echo "output: $output" + echo "status: $status" + assert_success + local RUN_CONTAINER="$output" + sleep 5 + + run /bin/bash -c "dokku run:logs $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "sleeping for 60 seconds" + + run /bin/bash -c "dokku run:logs $TEST_APP -n 1 -q" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "sleeping for 60 seconds" + + run /bin/bash -c "dokku run:logs --container $RUN_CONTAINER -q" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "sleeping for 60 seconds" + + run /bin/bash -c "dokku run:stop $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success +} + +@test "(run:logs) invalid arguments" { + run /bin/bash -c "dokku run:logs $TEST_APP -n abc" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "Invalid value for num: must be an integer" + + run /bin/bash -c "dokku run:logs $TEST_APP --container other-app.run.1" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "Specified app does not match app in container name" + + run /bin/bash -c "dokku run:logs --container $TEST_APP.run.1" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "Specified container does not exist" +}