From 5fd8657dd48fc750ce76800dce8342c9b62e2bd9 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 10 Nov 2022 11:36:02 +0000 Subject: [PATCH 1/4] fix: Misc improvements to `scripts/develop.sh` * Use new `/healthz` endpoint for checking API liveness * Improved credential handling/retrying in failure scenarios * Separate site (`vite`) logs with prefix and date, additionally this method also disables the `vite` clearing of the screen * Show all interfaces coder API is listening on (due to `0.0.0.0`) --- scripts/develop.sh | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/scripts/develop.sh b/scripts/develop.sh index 1902cf4b66475..823661e28184e 100755 --- a/scripts/develop.sh +++ b/scripts/develop.sh @@ -6,7 +6,7 @@ # Coder enterprise features). SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") -# shellcheck disable=SC1091,SC1090 +# shellcheck source=scripts/lib.sh source "${SCRIPT_DIR}/lib.sh" # Allow toggling verbose output @@ -62,18 +62,24 @@ CODER_DEV_SHIM="${PROJECT_ROOT}/scripts/coder-dev.sh" "${CODER_DEV_SHIM}" server --address 0.0.0.0:3000 || kill -INT -$$ & echo '== Waiting for Coder to become ready' - timeout 60s bash -c 'until curl -s --fail http://localhost:3000 > /dev/null 2>&1; do sleep 0.5; done' + timeout 60s bash -c 'until curl -s --fail http://localhost:3000/healthz > /dev/null 2>&1; do sleep 0.5; done' + + # Check if credentials are already set up to avoid setting up again. + "${CODER_DEV_SHIM}" list >/dev/null 2>&1 && touch "${PROJECT_ROOT}/.coderv2/developsh-did-first-setup" if [ ! -f "${PROJECT_ROOT}/.coderv2/developsh-did-first-setup" ]; then # Try to create the initial admin user. - "${CODER_DEV_SHIM}" login http://127.0.0.1:3000 --first-user-username=admin --first-user-email=admin@coder.com --first-user-password="${password}" || + if "${CODER_DEV_SHIM}" login http://127.0.0.1:3000 --first-user-username=admin --first-user-email=admin@coder.com --first-user-password="${password}"; then + # Only create this file if an admin user was successfully + # created, otherwise we won't retry on a later attempt. + touch "${PROJECT_ROOT}/.coderv2/developsh-did-first-setup" + else echo 'Failed to create admin user. To troubleshoot, try running this command manually.' + fi # Try to create a regular user. "${CODER_DEV_SHIM}" users create --email=member@coder.com --username=member --password="${password}" || echo 'Failed to create regular user. To troubleshoot, try running this command manually.' - - touch "${PROJECT_ROOT}/.coderv2/developsh-did-first-setup" fi # If we have docker available and the "docker" template doesn't already @@ -97,14 +103,31 @@ CODER_DEV_SHIM="${PROJECT_ROOT}/scripts/coder-dev.sh" fi # Start the frontend once we have a template up and running - CODER_HOST=http://127.0.0.1:3000 yarn --cwd=./site dev || kill -INT -$$ & + CODER_HOST=http://127.0.0.1:3000 yarn --cwd=./site dev --host | { + while read -r line; do + echo "[SITE] $(date -Iseconds): $line" + done + } || kill -INT -$$ & + + interfaces=(localhost) + if which ip >/dev/null 2>&1; then + # shellcheck disable=SC2207 + interfaces+=($(ip a | awk '/inet / {print $2}' | cut -d/ -f1)) + elif which ifconfig >/dev/null 2>&1; then + # shellcheck disable=SC2207 + interfaces+=($(ifconfig | awk '/inet / {print $2}')) + fi log log "====================================================================" log "== ==" log "== Coder is now running in development mode. ==" - log "== API: http://localhost:3000 ==" - log "== Web UI: http://localhost:8080 ==" + for iface in "${interfaces[@]}"; do + log "$(printf "== API: http://%s:3000%$((26 - ${#iface}))s==" "$iface" "")" + done + for iface in "${interfaces[@]}"; do + log "$(printf "== Web UI: http://%s:8080%$((26 - ${#iface}))s==" "$iface" "")" + done log "== ==" log "== Use ./scripts/coder-dev.sh to talk to this instance! ==" log "====================================================================" From 3e438e7962293a254f13b0350cb5911acc359587 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 10 Nov 2022 12:32:01 +0000 Subject: [PATCH 2/4] Amen PR comment, name the padding --- scripts/develop.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/develop.sh b/scripts/develop.sh index 823661e28184e..f2fdac6674d31 100755 --- a/scripts/develop.sh +++ b/scripts/develop.sh @@ -118,15 +118,17 @@ CODER_DEV_SHIM="${PROJECT_ROOT}/scripts/coder-dev.sh" interfaces+=($(ifconfig | awk '/inet / {print $2}')) fi + # Space padding used after the URLs to align "==". + space_padding=26 log log "====================================================================" log "== ==" log "== Coder is now running in development mode. ==" for iface in "${interfaces[@]}"; do - log "$(printf "== API: http://%s:3000%$((26 - ${#iface}))s==" "$iface" "")" + log "$(printf "== API: http://%s:3000%$((space_padding - ${#iface}))s==" "$iface" "")" done for iface in "${interfaces[@]}"; do - log "$(printf "== Web UI: http://%s:8080%$((26 - ${#iface}))s==" "$iface" "")" + log "$(printf "== Web UI: http://%s:8080%$((space_padding - ${#iface}))s==" "$iface" "")" done log "== ==" log "== Use ./scripts/coder-dev.sh to talk to this instance! ==" From 7f1f744e771289cf982e2f426a8494a0c597feed Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 10 Nov 2022 12:49:23 +0000 Subject: [PATCH 3/4] Amen PR comment, use curl instead of timeout --- scripts/develop.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/develop.sh b/scripts/develop.sh index f2fdac6674d31..e8d071d3a0f20 100755 --- a/scripts/develop.sh +++ b/scripts/develop.sh @@ -62,7 +62,11 @@ CODER_DEV_SHIM="${PROJECT_ROOT}/scripts/coder-dev.sh" "${CODER_DEV_SHIM}" server --address 0.0.0.0:3000 || kill -INT -$$ & echo '== Waiting for Coder to become ready' - timeout 60s bash -c 'until curl -s --fail http://localhost:3000/healthz > /dev/null 2>&1; do sleep 0.5; done' + curl --silent --fail --connect-timeout 1 --max-time 1 --retry 60 --retry-delay 1 --retry-max-time 60 --retry-all-errors 'http://localhost:3000/healthz' || + { + echo '== ERROR: Coder did not become ready in time' + kill -INT -$$ + } # Check if credentials are already set up to avoid setting up again. "${CODER_DEV_SHIM}" list >/dev/null 2>&1 && touch "${PROJECT_ROOT}/.coderv2/developsh-did-first-setup" From ac5d2213d312137ba666c0638cdc4104e9ae07a0 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 10 Nov 2022 14:06:48 +0000 Subject: [PATCH 4/4] feat: Better interrupt handling --- scripts/develop.sh | 49 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/scripts/develop.sh b/scripts/develop.sh index e8d071d3a0f20..4e453c4cc156e 100755 --- a/scripts/develop.sh +++ b/scripts/develop.sh @@ -51,22 +51,53 @@ make -j "build/coder_${GOOS}_${GOARCH}" # Use the coder dev shim so we don't overwrite the user's existing Coder config. CODER_DEV_SHIM="${PROJECT_ROOT}/scripts/coder-dev.sh" +pids=() +exit_cleanup() { + set +e + # Set empty interrupt handler so cleanup isn't interrupted. + trap '' INT + # Send interrupt to the entire process group to start shutdown procedures. + kill -INT -$$ + # Remove exit trap to avoid infinite loop. + trap - EXIT + + # Just in case, send interrupts to our children. + kill -INT "${pids[@]}" >/dev/null 2>&1 + # Use the hammer if things take too long. + { sleep 5 && kill -TERM -$$ >/dev/null 2>&1; } & + + # Wait for all children to exit (this can be aborted by hammer). + wait_cmds + exit 1 +} +start_cmd() { + echo "== CMD: $*" >&2 + "$@" || fatal "CMD: $*" & + pids+=("$!") +} +wait_cmds() { + wait "${pids[@]}" >/dev/null 2>&1 +} +fatal() { + echo "== FAIL: $*" >&2 + exit_cleanup +} + # This is a way to run multiple processes in parallel, and have Ctrl-C work correctly # to kill both at the same time. For more details, see: # https://stackoverflow.com/questions/3004811/how-do-you-run-multiple-programs-in-parallel-from-a-bash-script ( # If something goes wrong, just bail and tear everything down # rather than leaving things in an inconsistent state. - trap 'kill -TERM -$$' ERR + trap 'exit_cleanup' INT EXIT + trap 'fatal "Script encountered an error"' ERR + cdroot - "${CODER_DEV_SHIM}" server --address 0.0.0.0:3000 || kill -INT -$$ & + start_cmd "${CODER_DEV_SHIM}" server --address 0.0.0.0:3000 echo '== Waiting for Coder to become ready' curl --silent --fail --connect-timeout 1 --max-time 1 --retry 60 --retry-delay 1 --retry-max-time 60 --retry-all-errors 'http://localhost:3000/healthz' || - { - echo '== ERROR: Coder did not become ready in time' - kill -INT -$$ - } + fatal 'Coder did not become ready in time' # Check if credentials are already set up to avoid setting up again. "${CODER_DEV_SHIM}" list >/dev/null 2>&1 && touch "${PROJECT_ROOT}/.coderv2/developsh-did-first-setup" @@ -107,11 +138,11 @@ CODER_DEV_SHIM="${PROJECT_ROOT}/scripts/coder-dev.sh" fi # Start the frontend once we have a template up and running - CODER_HOST=http://127.0.0.1:3000 yarn --cwd=./site dev --host | { + CODER_HOST=http://127.0.0.1:3000 start_cmd yarn --cwd=./site dev --host | { while read -r line; do echo "[SITE] $(date -Iseconds): $line" done - } || kill -INT -$$ & + } interfaces=(localhost) if which ip >/dev/null 2>&1; then @@ -140,5 +171,5 @@ CODER_DEV_SHIM="${PROJECT_ROOT}/scripts/coder-dev.sh" log # Wait for both frontend and backend to exit. - wait + wait_cmds )