From 774af2b1d5a22844d25adb617907216279ba5c1f Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 21 Aug 2026 08:25:44 -0400 Subject: [PATCH 1/7] Wait for The Combine to come up before shutting it down wait-for-combine only ever read one deployment's READY count. Collapsing the kubectl table with an unquoted expansion put every row on one line, so grep matched the whole line for each name and the greedy sed captured the last N/1 in it -- the alphabetically last deployment, maintenance. Replace the parsing with kubectl wait, and check the database first, since everything else depends on it and it is the slowest to come up on a first install. Then wait for the database to record a completed semantic domain import. The installer stops k3s next, which SIGKILLs pods because the k3s unit is patched to KillMode=mixed, and an interrupted import is redone on the next start; so without this the shutdown could silently cost the user another import. Co-Authored-By: Claude Opus 5 (1M context) --- deploy/scripts/install-combine.sh | 44 +++++++++++++++++++------------ 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/deploy/scripts/install-combine.sh b/deploy/scripts/install-combine.sh index 2480d6a92b..afa7f82356 100755 --- a/deploy/scripts/install-combine.sh +++ b/deploy/scripts/install-combine.sh @@ -154,25 +154,34 @@ install-the-combine () { deactivate } -# Wait until all The Combine deployments are "Running" +# Wait until all The Combine deployments are available. There is no timeout; +# the caller tells the user how to interrupt. wait-for-combine () { - # Wait for all The Combine deployments to be up - while true ; do - combine_status=`kubectl -n thecombine get deployments` - # Assert The Combine is up; if any components are not up, set it to false - combine_up=true - for deployment in frontend backend database maintenance ; do - deployment_status=$(echo ${combine_status} | grep "${deployment}" | sed "s/^.*\([0-9]\)\/1.*/\1/") - if [ "$deployment_status" == "0" ] ; then - combine_up=false - break - fi - done - if [ ${combine_up} != true ] ; then + set-k3s-env + # The database is checked first because everything else depends on it and it + # is the slowest to come up on a first install. + for deployment in database backend frontend maintenance ; do + echo "Waiting for deployment/${deployment}." + until kubectl -n thecombine get deployment/${deployment} > /dev/null 2>&1 ; do sleep 5 - else - break - fi + done + until kubectl -n thecombine wait --for=condition=Available \ + --timeout=1m deployment/${deployment} > /dev/null 2>&1 ; do + echo " still waiting for deployment/${deployment}." + done + done +} + +# Wait until the database has recorded a completed semantic domain import. The +# import runs from the database's postStart hook and takes several minutes on a +# first install. It is redone on the next start if it is interrupted, so waiting +# here keeps the shutdown below from silently costing the user another import. +wait-for-semantic-domains () { + echo "Waiting for the semantic domain import." + import_done="quit(db.getSiblingDB('CombineDatabase').SemanticDomainImportStatus.countDocuments({ _id: 'semantic-domains', completed: true }) === 1 ? 0 : 1)" + until kubectl -n thecombine exec deployment/database -- \ + mongosh --quiet --host 127.0.0.1 --eval "${import_done}" > /dev/null 2>&1 ; do + sleep 10 done } @@ -374,6 +383,7 @@ while [ "$STATE" != "Done" ] ; do echo "This may take some time depending on your Internet connection." echo "Press Ctrl-C to interrupt." wait-for-combine + wait-for-semantic-domains echo "The Combine was successfully setup!" next-state "Shutdown-combine" ;; From de0f4bc27e7522f2abbd5a7488d61362f7b72c4a Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 21 Aug 2026 08:25:44 -0400 Subject: [PATCH 2/7] Let single-step stop the installer after Wait-for-combine Every other step that records a follow-on state checks SINGLE_STEP before continuing, but Wait-for-combine fell straight through into Shutdown-combine, so single-step could not be used to inspect a running cluster before the installer stopped it. Setting STATE directly rather than calling next-state leaves the recorded state in place, so the next run resumes at Shutdown-combine. Co-Authored-By: Claude Opus 5 (1M context) --- deploy/scripts/install-combine.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deploy/scripts/install-combine.sh b/deploy/scripts/install-combine.sh index afa7f82356..30b00c9ab1 100755 --- a/deploy/scripts/install-combine.sh +++ b/deploy/scripts/install-combine.sh @@ -386,6 +386,9 @@ while [ "$STATE" != "Done" ] ; do wait-for-semantic-domains echo "The Combine was successfully setup!" next-state "Shutdown-combine" + if [ "$SINGLE_STEP" == "1" ] ; then + STATE=Done + fi ;; Shutdown-combine) # If not being installed as a server, From 1965d92fb1736963e7d5725b25ad68f8be949d27 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 21 Aug 2026 08:25:44 -0400 Subject: [PATCH 3/7] Pace and bound the installer's waits for The Combine "kubectl wait" returns at once, rather than blocking for its timeout, when the API server is unreachable or the deployment is gone, so its retry loop had nothing but an echo in it and could spin, pegging a core and flooding the terminal. Pace the retries. Neither wait had an upper bound either, so a deployment that was never going to come up produced no error, ever. Give each stage a deadline, default one hour and overridable with WAIT_TIMEOUT_SECONDS, and print the pods in the namespace before exiting so there is somewhere to start looking. Rerunning the installer resumes the wait. Check the semantic domain import every 30 seconds rather than every 10; each check starts a mongosh inside the database container, competing with the import it is waiting on. Co-Authored-By: Claude Opus 5 (1M context) --- deploy/scripts/install-combine.sh | 34 ++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/deploy/scripts/install-combine.sh b/deploy/scripts/install-combine.sh index 30b00c9ab1..c585f74734 100755 --- a/deploy/scripts/install-combine.sh +++ b/deploy/scripts/install-combine.sh @@ -13,6 +13,9 @@ set -eo pipefail # - single-step - run the next "step" in the installation process and stop. # - start-at - start at the step named and run to completion. # +# The WAIT_TIMEOUT_SECONDS environment variable overrides how long each stage of +# the "Wait-for-combine" step waits before giving up. +# ######################################################################################### # Warning and Error reporting functions @@ -154,20 +157,37 @@ install-the-combine () { deactivate } -# Wait until all The Combine deployments are available. There is no timeout; -# the caller tells the user how to interrupt. +# Exit if the deadline for the current wait has passed, printing the state of +# the pods so that the user has somewhere to start looking. +check-wait-deadline () { + if (( SECONDS < WAIT_DEADLINE )) ; then + return 0 + fi + echo "Current state of the pods in the 'thecombine' namespace:" >&2 + kubectl -n thecombine get pods --request-timeout=10s >&2 || true + ERROR_HINT="Rerun the installer to resume waiting; nothing needs to be undone." + error "Timed out after ${WAIT_TIMEOUT_SECONDS}s waiting for $1." +} + +# Wait until all The Combine deployments are available. wait-for-combine () { set-k3s-env + WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) # The database is checked first because everything else depends on it and it # is the slowest to come up on a first install. for deployment in database backend frontend maintenance ; do echo "Waiting for deployment/${deployment}." until kubectl -n thecombine get deployment/${deployment} > /dev/null 2>&1 ; do + check-wait-deadline "deployment/${deployment}" sleep 5 done + # "kubectl wait" returns at once, rather than blocking for its timeout, when + # the API is unreachable or the deployment is gone, so pace the retries. until kubectl -n thecombine wait --for=condition=Available \ --timeout=1m deployment/${deployment} > /dev/null 2>&1 ; do + check-wait-deadline "deployment/${deployment}" echo " still waiting for deployment/${deployment}." + sleep 5 done done } @@ -178,10 +198,14 @@ wait-for-combine () { # here keeps the shutdown below from silently costing the user another import. wait-for-semantic-domains () { echo "Waiting for the semantic domain import." + WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) import_done="quit(db.getSiblingDB('CombineDatabase').SemanticDomainImportStatus.countDocuments({ _id: 'semantic-domains', completed: true }) === 1 ? 0 : 1)" + # Each check starts a mongosh inside the database container, competing with the + # import it is waiting on, so check infrequently. until kubectl -n thecombine exec deployment/database -- \ mongosh --quiet --host 127.0.0.1 --eval "${import_done}" > /dev/null 2>&1 ; do - sleep 10 + check-wait-deadline "the semantic domain import" + sleep 30 done } @@ -248,6 +272,10 @@ ERROR_HINT="" # Only a timeout given as an option is checked for a valid format, so ignore any # value that happens to be set in the environment. HELM_TIMEOUT="" +# Maximum time to wait for each stage of The Combine to come up. A first +# install pulls several images and imports the semantic domains, so a generous +# default is better than one that gives up on a slow machine or connection. +WAIT_TIMEOUT_SECONDS=${WAIT_TIMEOUT_SECONDS:-3600} # See if we need to continue from a previous install STATE_FILE=${CONFIG_DIR}/install-state From de8eb895a23d02f64a22e962e91b89591e7302b3 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 21 Aug 2026 08:26:02 -0400 Subject: [PATCH 4/7] Report the installer's waits and their remedies accurately One deadline covers the wait for all four deployments, so "Timed out after 3600s waiting for deployment/maintenance" claimed a wait that had mostly elapsed on the database. Say what the wait was still waiting for instead, and describe the timeout in the header comment as the budget for the deployments and then for the import, rather than one per deployment. The semantic domain import runs from the database pod's postStart hook, so rerunning the installer does not start an import that never ran; give that wait a hint that names the manual import instead of the default advice. Co-Authored-By: Claude Opus 5 (1M context) --- deploy/scripts/install-combine.sh | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/deploy/scripts/install-combine.sh b/deploy/scripts/install-combine.sh index c585f74734..437486da84 100755 --- a/deploy/scripts/install-combine.sh +++ b/deploy/scripts/install-combine.sh @@ -13,8 +13,9 @@ set -eo pipefail # - single-step - run the next "step" in the installation process and stop. # - start-at - start at the step named and run to completion. # -# The WAIT_TIMEOUT_SECONDS environment variable overrides how long each stage of -# the "Wait-for-combine" step waits before giving up. +# The WAIT_TIMEOUT_SECONDS environment variable overrides how long the +# "Wait-for-combine" step waits for the deployments to become available, and then +# again for the semantic domain import, before giving up. # ######################################################################################### @@ -158,18 +159,22 @@ install-the-combine () { } # Exit if the deadline for the current wait has passed, printing the state of -# the pods so that the user has somewhere to start looking. +# the pods so that the user has somewhere to start looking. $1 names what is +# still being waited for and $2 optionally replaces the default error hint. check-wait-deadline () { if (( SECONDS < WAIT_DEADLINE )) ; then return 0 fi echo "Current state of the pods in the 'thecombine' namespace:" >&2 kubectl -n thecombine get pods --request-timeout=10s >&2 || true - ERROR_HINT="Rerun the installer to resume waiting; nothing needs to be undone." - error "Timed out after ${WAIT_TIMEOUT_SECONDS}s waiting for $1." + ERROR_HINT="${2:-Rerun the installer to resume waiting; nothing needs to be undone.}" + # The deadline covers the whole wait, so report what it was still waiting for + # rather than implying that $1 alone had the full timeout. + error "Timed out after ${WAIT_TIMEOUT_SECONDS}s; still waiting for $1." } -# Wait until all The Combine deployments are available. +# Wait until all The Combine deployments are available. One deadline covers all +# of them, so a database that takes most of it leaves the rest less time. wait-for-combine () { set-k3s-env WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) @@ -200,11 +205,14 @@ wait-for-semantic-domains () { echo "Waiting for the semantic domain import." WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) import_done="quit(db.getSiblingDB('CombineDatabase').SemanticDomainImportStatus.countDocuments({ _id: 'semantic-domains', completed: true }) === 1 ? 0 : 1)" + # Rerunning the installer does not restart the database pod, so it does not + # start an import that never ran; point at the manual import instead. + import_hint="Import the semantic domains manually with: kubectl -n thecombine exec deployment/database -- /opt/thecombine/update-semantic-domains.sh" # Each check starts a mongosh inside the database container, competing with the # import it is waiting on, so check infrequently. until kubectl -n thecombine exec deployment/database -- \ mongosh --quiet --host 127.0.0.1 --eval "${import_done}" > /dev/null 2>&1 ; do - check-wait-deadline "the semantic domain import" + check-wait-deadline "the semantic domain import" "${import_hint}" sleep 30 done } From 5aa4aa7582f75450e47afd6e49fdadacd5691e2b Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 21 Aug 2026 08:26:02 -0400 Subject: [PATCH 5/7] Correct what the installer's comments claim about its waits The database is not available until its postStart hook has imported the semantic domains, so the import elapses inside the wait for the deployments, not inside the wait that follows it. That second wait is a guard for a database pod that an install left running, which therefore never ran the hook. Comments now use one space after a period rather than two, and some blocks are rewrapped to the width of the file around them. Co-Authored-By: Claude Opus 5 (1M context) --- deploy/scripts/install-combine.sh | 43 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/deploy/scripts/install-combine.sh b/deploy/scripts/install-combine.sh index 437486da84..b1e8587283 100755 --- a/deploy/scripts/install-combine.sh +++ b/deploy/scripts/install-combine.sh @@ -13,9 +13,9 @@ set -eo pipefail # - single-step - run the next "step" in the installation process and stop. # - start-at - start at the step named and run to completion. # -# The WAIT_TIMEOUT_SECONDS environment variable overrides how long the -# "Wait-for-combine" step waits for the deployments to become available, and then -# again for the semantic domain import, before giving up. +# The WAIT_TIMEOUT_SECONDS environment variable overrides how long the "Wait-for-combine" +# step waits for the deployments to become available. The check that follows, which +# normally passes at once, is given the same budget again. # ######################################################################################### @@ -32,9 +32,9 @@ error () { exit 1 } -# Set the environment variables that are required by The Combine. -# In addition, the values are stored in a file so that they do not -# need to be re-entered on subsequent installations. +# Set the environment variables that are required by The Combine. In addition, +# the values are stored in a file so that they do not need to be re-entered on +# subsequent installations. set-combine-env () { if [ ! -f "${CONFIG_DIR}/env" ] ; then # Generate JWT Secret Key @@ -101,9 +101,8 @@ install-kubernetes () { ansible-playbook playbook_desktop_setup.yml -K ${EXTRA_VARS} $(((DEBUG == 1)) && echo "-vv") } -# Set the KUBECONFIG environment variable so that the cluster can -# be reached by the installation scripts. It also starts the k3s -# service if it is not already running. +# Set the KUBECONFIG env var so the cluster can be reached by the installation +# scripts. It also starts the k3s service if it is not already running. set-k3s-env () { ##### # Setup kubectl configuration file @@ -159,7 +158,7 @@ install-the-combine () { } # Exit if the deadline for the current wait has passed, printing the state of -# the pods so that the user has somewhere to start looking. $1 names what is +# the pods so that the user has somewhere to start looking. $1 names what is # still being waited for and $2 optionally replaces the default error hint. check-wait-deadline () { if (( SECONDS < WAIT_DEADLINE )) ; then @@ -173,8 +172,9 @@ check-wait-deadline () { error "Timed out after ${WAIT_TIMEOUT_SECONDS}s; still waiting for $1." } -# Wait until all The Combine deployments are available. One deadline covers all -# of them, so a database that takes most of it leaves the rest less time. +# Wait until all The Combine deployments are available. One deadline covers all +# of them, so the database, which is not available until its postStart hook has +# imported the semantic domains, leaves the rest of them less time. wait-for-combine () { set-k3s-env WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) @@ -197,10 +197,15 @@ wait-for-combine () { done } -# Wait until the database has recorded a completed semantic domain import. The -# import runs from the database's postStart hook and takes several minutes on a -# first install. It is redone on the next start if it is interrupted, so waiting -# here keeps the shutdown below from silently costing the user another import. +# Check that the database has recorded a completed semantic domain import, which +# is redone on the next pod start if it was interrupted, so that the shutdown +# below does not silently cost the user another import. +# +# The import runs from the database's postStart hook, and the kubelet does not +# report a container ready until its hook returns, so wait-for-combine has +# already waited the import out and this normally passes on its first check. It +# is here for what that wait cannot see: a database pod that an install left +# running, and so never ran the hook, with no import recorded. wait-for-semantic-domains () { echo "Waiting for the semantic domain import." WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) @@ -277,10 +282,10 @@ SINGLE_STEP=0 IS_SERVER=0 DEBUG=0 ERROR_HINT="" -# Only a timeout given as an option is checked for a valid format, so ignore any -# value that happens to be set in the environment. +# Only a timeout given as an option is checked for a valid format, so ignore +# any value that happens to be set in the environment. HELM_TIMEOUT="" -# Maximum time to wait for each stage of The Combine to come up. A first +# Maximum time to wait for each stage of The Combine to come up. A first # install pulls several images and imports the semantic domains, so a generous # default is better than one that gives up on a slow machine or connection. WAIT_TIMEOUT_SECONDS=${WAIT_TIMEOUT_SECONDS:-3600} From 3ed0b9e6ec501e2d26614cc30de18cef4b475fd9 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 21 Aug 2026 08:26:18 -0400 Subject: [PATCH 6/7] Bound the semantic domain check and validate its timeout wait-for-semantic-domains had the same hour-long budget as the wait for the deployments, but readiness is gated on the same record, so it either passes on its first check or is in the case where no pod will ever write the record. That spent an hour polling before printing the manual-import hint that is the actual remedy; give it a short budget of its own. check-wait-deadline now reports the budget of the wait that set it, so the two cannot drift. WAIT_TIMEOUT_SECONDS went into arithmetic unchecked, where bash reads a non-number as 0 and a leading zero as octal: "abc" became a deadline that had already passed, "007" became seven seconds, and "3600s" aborted with a bare arithmetic error. Require a whole number greater than zero, as the timeout option already does. Co-Authored-By: Claude Opus 5 (1M context) --- deploy/scripts/install-combine.sh | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/deploy/scripts/install-combine.sh b/deploy/scripts/install-combine.sh index b1e8587283..c8469b324b 100755 --- a/deploy/scripts/install-combine.sh +++ b/deploy/scripts/install-combine.sh @@ -14,8 +14,8 @@ set -eo pipefail # - start-at - start at the step named and run to completion. # # The WAIT_TIMEOUT_SECONDS environment variable overrides how long the "Wait-for-combine" -# step waits for the deployments to become available. The check that follows, which -# normally passes at once, is given the same budget again. +# step waits for the deployments to become available. The check that follows it has a +# short budget of its own, since it normally passes at once. # ######################################################################################### @@ -157,6 +157,12 @@ install-the-combine () { deactivate } +# Start a wait of $1 seconds, keeping the budget for check-wait-deadline to report. +start-wait () { + WAIT_BUDGET=$1 + WAIT_DEADLINE=$(( SECONDS + WAIT_BUDGET )) +} + # Exit if the deadline for the current wait has passed, printing the state of # the pods so that the user has somewhere to start looking. $1 names what is # still being waited for and $2 optionally replaces the default error hint. @@ -169,7 +175,7 @@ check-wait-deadline () { ERROR_HINT="${2:-Rerun the installer to resume waiting; nothing needs to be undone.}" # The deadline covers the whole wait, so report what it was still waiting for # rather than implying that $1 alone had the full timeout. - error "Timed out after ${WAIT_TIMEOUT_SECONDS}s; still waiting for $1." + error "Timed out after ${WAIT_BUDGET}s; still waiting for $1." } # Wait until all The Combine deployments are available. One deadline covers all @@ -177,7 +183,7 @@ check-wait-deadline () { # imported the semantic domains, leaves the rest of them less time. wait-for-combine () { set-k3s-env - WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) + start-wait "${WAIT_TIMEOUT_SECONDS}" # The database is checked first because everything else depends on it and it # is the slowest to come up on a first install. for deployment in database backend frontend maintenance ; do @@ -205,10 +211,11 @@ wait-for-combine () { # report a container ready until its hook returns, so wait-for-combine has # already waited the import out and this normally passes on its first check. It # is here for what that wait cannot see: a database pod that an install left -# running, and so never ran the hook, with no import recorded. +# running, and so never ran the hook, with no import recorded. Nothing will write +# the record then, so the wait is short and ends in the hint below. wait-for-semantic-domains () { echo "Waiting for the semantic domain import." - WAIT_DEADLINE=$(( SECONDS + WAIT_TIMEOUT_SECONDS )) + start-wait "${IMPORT_CHECK_TIMEOUT_SECONDS}" import_done="quit(db.getSiblingDB('CombineDatabase').SemanticDomainImportStatus.countDocuments({ _id: 'semantic-domains', completed: true }) === 1 ? 0 : 1)" # Rerunning the installer does not restart the database pod, so it does not # start an import that never ran; point at the manual import instead. @@ -285,10 +292,15 @@ ERROR_HINT="" # Only a timeout given as an option is checked for a valid format, so ignore # any value that happens to be set in the environment. HELM_TIMEOUT="" -# Maximum time to wait for each stage of The Combine to come up. A first -# install pulls several images and imports the semantic domains, so a generous -# default is better than one that gives up on a slow machine or connection. +# Maximum time to wait for each stage of The Combine to come up. A first install +# pulls several images and imports the semantic domains, so be generous. WAIT_TIMEOUT_SECONDS=${WAIT_TIMEOUT_SECONDS:-3600} +# Prevent silently bad values: non-number (reads as 0); leading zero (octal). +if [[ ! ${WAIT_TIMEOUT_SECONDS} =~ ^[1-9][0-9]*$ ]] ; then + error "Invalid WAIT_TIMEOUT_SECONDS, '${WAIT_TIMEOUT_SECONDS}'; it must be a whole number greater than zero." +fi +# The deployments wait already covers the import, so this only covers one slow call. +IMPORT_CHECK_TIMEOUT_SECONDS=120 # See if we need to continue from a previous install STATE_FILE=${CONFIG_DIR}/install-state From 617aeffa1e2c0b1e5b7b0e679baa86b2a52c0169 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 21 Aug 2026 08:26:18 -0400 Subject: [PATCH 7/7] Keep the wait timeout check out of the uninstall path WAIT_TIMEOUT_SECONDS was checked at the top of the script, so a bad value left in the environment stopped an uninstall, which never waits for anything. Check it with the other install-only setup, where the state is known, as the version number already is. Co-Authored-By: Claude Opus 5 (1M context) --- deploy/scripts/install-combine.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/scripts/install-combine.sh b/deploy/scripts/install-combine.sh index c8469b324b..6200c2e490 100755 --- a/deploy/scripts/install-combine.sh +++ b/deploy/scripts/install-combine.sh @@ -295,10 +295,6 @@ HELM_TIMEOUT="" # Maximum time to wait for each stage of The Combine to come up. A first install # pulls several images and imports the semantic domains, so be generous. WAIT_TIMEOUT_SECONDS=${WAIT_TIMEOUT_SECONDS:-3600} -# Prevent silently bad values: non-number (reads as 0); leading zero (octal). -if [[ ! ${WAIT_TIMEOUT_SECONDS} =~ ^[1-9][0-9]*$ ]] ; then - error "Invalid WAIT_TIMEOUT_SECONDS, '${WAIT_TIMEOUT_SECONDS}'; it must be a whole number greater than zero." -fi # The deployments wait already covers the import, so this only covers one slow call. IMPORT_CHECK_TIMEOUT_SECONDS=120 @@ -371,6 +367,10 @@ fi SETUP_OPTS="" if [ "${STATE}" != "Uninstall-combine" ] ; then + # Prevent silently bad values: non-number (reads as 0); leading zero (octal). + if [[ ! ${WAIT_TIMEOUT_SECONDS} =~ ^[1-9][0-9]*$ ]] ; then + error "Invalid WAIT_TIMEOUT_SECONDS, '${WAIT_TIMEOUT_SECONDS}'; it must be a whole number greater than zero." + fi # Every helm command runs after the restart that the Pre-reqs step usually # requires, so record a timeout and reuse it until the install finishes. if [ -z "${HELM_TIMEOUT}" ] ; then