Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -935,10 +935,21 @@ start_user_gateway() {

info "registering local gateway as ${TARGET_USER}..."
register_local_gateway
wait_for_local_gateway_listener
wait_for_local_gateway_listener user_gateway_service_failed
wait_for_local_gateway_status
}

# Succeeds when the gateway user service has failed or is waiting to restart
# after a failure. A unit that is starting or running does not match, even if
# it failed before it was restarted.
user_gateway_service_failed() {
_unit_state="$(as_target_user systemctl --user show openshell-gateway -p ActiveState -p SubState 2>/dev/null)" || return 1
case "$_unit_state" in
*ActiveState=failed* | *SubState=auto-restart*) return 0 ;;
esac
return 1
}

dump_local_gateway_diagnostics() {
_lines="${OPENSHELL_INSTALL_LOG_LINES:-80}"
case "$_lines" in
Expand Down Expand Up @@ -1015,10 +1026,14 @@ dump_user_service_gateway_diagnostics() {
fi
}

# An optional command name stops the wait early when it succeeds, so a service
# that already failed does not run out the full timeout.
wait_for_local_gateway_listener() {
_failed_check="${1:-}"
_timeout="${OPENSHELL_INSTALL_GATEWAY_TIMEOUT:-30}"
_elapsed=0
_last_output=""
_service_failed=0
_probe_url="$(local_gateway_endpoint)/"
_mtls_dir="${TARGET_HOME}/.config/openshell/gateways/openshell/mtls"

Expand All @@ -1030,12 +1045,19 @@ wait_for_local_gateway_listener() {
info "local gateway listener is reachable"
return 0
fi
if [ -n "$_failed_check" ] && "$_failed_check"; then
_service_failed=1
break
fi
sleep 1
_elapsed=$((_elapsed + 1))
done

[ -z "$_last_output" ] || printf '%s\n' "$_last_output" >&2
dump_local_gateway_diagnostics
if [ "$_service_failed" -eq 1 ]; then
error "the openshell-gateway service failed to start; fix the cause shown above, then run: systemctl --user restart openshell-gateway"
fi
error "local gateway listener did not become reachable at ${_probe_url} within ${_timeout}s"
}

Expand Down
91 changes: 91 additions & 0 deletions tasks/scripts/test-install-sh.sh
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,97 @@ if [[ -z $(find "$snap_user_tls" -maxdepth 0 -perm 700) ]]; then
exit 1
fi

assert_user_gateway_service_failed() {
local name=$1
local unit_state=$2
local expected=$3
local actual=0

(
as_target_user() { printf '%s\n' "$unit_state"; }
user_gateway_service_failed
) >/dev/null || actual=$?
if [ "$actual" != "$expected" ]; then
echo "FAIL: ${name}: expected status ${expected}, got ${actual}" >&2
exit 1
fi
}

assert_user_gateway_service_failed "failed unit" $'ActiveState=failed\nSubState=failed' 0
assert_user_gateway_service_failed "unit restarting after a failure" $'ActiveState=activating\nSubState=auto-restart' 0
assert_user_gateway_service_failed "unit starting after a failure" $'ActiveState=activating\nSubState=start' 1
assert_user_gateway_service_failed "running unit" $'ActiveState=active\nSubState=running' 1
if (
as_target_user() { return 1; }
user_gateway_service_failed
); then
echo "FAIL: unreachable user systemd must not count as a failed unit" >&2
exit 1
fi

# Runs the listener wait against an unreachable gateway and prints the number
# of one second waits. The wait is expected to fail.
run_listener_wait() {
local unit_state=$1
local sleeps_file="${tmpdir}/listener-sleeps"
shift

: >"$sleeps_file"
(
as_target_user() {
case "$1" in
systemctl) printf '%s\n' "$unit_state" ;;
*) return 7 ;;
esac
}
sleep() { printf '.' >>"$sleeps_file"; }
info() { :; }
dump_local_gateway_diagnostics() { echo "gateway diagnostics" >&2; }
TARGET_HOME="${tmpdir}/listener-home"
PLATFORM=linux
OPENSHELL_INSTALL_GATEWAY_TIMEOUT=5 wait_for_local_gateway_listener "$@"
) >"$out" 2>"$err" && return 1
wc -c <"$sleeps_file" | tr -d ' '
}

listener_mtls_dir="${tmpdir}/listener-home/.config/openshell/gateways/openshell/mtls"
mkdir -p "$listener_mtls_dir"
: >"${listener_mtls_dir}/ca.crt"
: >"${listener_mtls_dir}/tls.crt"
: >"${listener_mtls_dir}/tls.key"

restarting_unit=$'ActiveState=activating\nSubState=auto-restart'
running_unit=$'ActiveState=active\nSubState=running'

if [ "$(run_listener_wait "$restarting_unit" user_gateway_service_failed)" != "0" ]; then
echo "FAIL: a failed gateway service must stop the listener wait immediately" >&2
exit 1
fi
if [ "$(tail -n 1 "$err")" != "openshell: error: the openshell-gateway service failed to start; fix the cause shown above, then run: systemctl --user restart openshell-gateway" ]; then
echo "FAIL: a failed gateway service must end with the service error" >&2
cat "$err" >&2
exit 1
fi
if ! grep -Fq "gateway diagnostics" "$err"; then
echo "FAIL: a failed gateway service must dump diagnostics" >&2
exit 1
fi

if [ "$(run_listener_wait "$running_unit" user_gateway_service_failed)" != "5" ]; then
echo "FAIL: a running gateway service must not stop the listener wait" >&2
exit 1
fi
if ! grep -Fq "did not become reachable" "$err"; then
echo "FAIL: a running gateway service must end with the listener timeout" >&2
cat "$err" >&2
exit 1
fi

if [ "$(run_listener_wait "$restarting_unit")" != "5" ]; then
echo "FAIL: the listener wait must ignore the service state without a check" >&2
exit 1
fi

if [ "$(PLATFORM=darwin local_gateway_endpoint)" != "https://localhost:17670" ]; then
echo "FAIL: macOS local gateway endpoint must use a TLS-compatible loopback hostname" >&2
exit 1
Expand Down
Loading