Files
Phoenix/scripts/restart_phoenix_services.sh

323 lines
9.3 KiB
Bash

#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
PHOENIX_ROOT="${PHOENIX_ROOT_OVERRIDE:-}"
if [ -z "$PHOENIX_ROOT" ]; then
PHOENIX_ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
else
PHOENIX_ROOT="$(cd "$PHOENIX_ROOT" && pwd -P)"
fi
PHOENIX_PARENT="$(cd "$PHOENIX_ROOT/.." && pwd -P)"
PHOENIX_NAME="$(basename "$PHOENIX_ROOT")"
STAGE_DIR="$PHOENIX_PARENT/${PHOENIX_NAME}.update"
BACKUP_DIR="$PHOENIX_PARENT/${PHOENIX_NAME}.backup"
FAILED_DIR="$PHOENIX_PARENT/${PHOENIX_NAME}.failed"
LOG_FILE="$PHOENIX_PARENT/${PHOENIX_NAME}.update.log"
exec >>"$LOG_FILE" 2>&1
echo "=== $(date): restart_phoenix_services.sh START ==="
is_volumio_install() {
[ "${PHOENIX_INSTALL_PROFILE:-}" = "volumio" ] || [ "$PHOENIX_ROOT" = "/home/volumio/Phoenix" ]
}
restart_if_present() {
local unit="$1"
if ! command -v systemctl >/dev/null 2>&1; then
return 0
fi
if run_systemctl list-unit-files "$unit" >/dev/null 2>&1 || run_systemctl status "$unit" >/dev/null 2>&1; then
run_systemctl restart "$unit" >/dev/null 2>&1 || true
fi
}
stop_if_present() {
local unit="$1"
if ! command -v systemctl >/dev/null 2>&1; then
return 0
fi
if run_systemctl list-unit-files "$unit" >/dev/null 2>&1 || run_systemctl status "$unit" >/dev/null 2>&1; then
run_systemctl stop "$unit" >/dev/null 2>&1 || true
fi
}
run_systemctl() {
if [ "$(id -u)" -eq 0 ]; then
systemctl "$@"
return $?
fi
if ! command -v sudo >/dev/null 2>&1; then
echo "sudo not found; cannot control system services as non-root" >&2
return 1
fi
sudo -n systemctl "$@"
}
run_systemd_run() {
local unit_name="phoenix-online-update-$(date +%s)"
if [ "$(id -u)" -eq 0 ]; then
systemd-run --unit="$unit_name" --collect --property=Type=oneshot \
/usr/bin/env PHOENIX_UPDATE_DETACHED=1 /bin/bash "$0"
return $?
fi
if ! command -v sudo >/dev/null 2>&1; then
echo "sudo not found; cannot detach update restart as non-root" >&2
return 1
fi
sudo -n systemd-run --unit="$unit_name" --collect --property=Type=oneshot \
/usr/bin/env PHOENIX_UPDATE_DETACHED=1 /bin/bash "$0"
}
start_volumio_update_service() {
local unit="phoenix-update-volumio.service"
if [ "$(id -u)" -eq 0 ]; then
/usr/bin/systemctl --no-block start "$unit"
return $?
fi
if ! command -v sudo >/dev/null 2>&1; then
echo "sudo not found; cannot start $unit as non-root" >&2
return 1
fi
sudo -n /usr/bin/systemctl --no-block start "$unit"
}
health_ok() {
if ! command -v curl >/dev/null 2>&1; then
return 0
fi
curl -fsS http://127.0.0.1:8789/health >/dev/null 2>&1
}
needs_phoenix_build() {
local phoenix_dir="${1:-$PHOENIX_ROOT}"
local phoenix_bin="$phoenix_dir/target/release/phoenix"
if [ ! -x "$phoenix_bin" ] || [ ! -s "$phoenix_bin" ]; then
return 0
fi
if [ -f "$phoenix_dir/Cargo.toml" ] && [ "$phoenix_dir/Cargo.toml" -nt "$phoenix_bin" ]; then
return 0
fi
if [ -f "$phoenix_dir/Cargo.lock" ] && [ "$phoenix_dir/Cargo.lock" -nt "$phoenix_bin" ]; then
return 0
fi
if [ -d "$phoenix_dir/src" ] && find "$phoenix_dir/src" -type f -name '*.rs' -newer "$phoenix_bin" -print -quit | grep -q .; then
return 0
fi
return 1
}
clear_browser_asset_caches() {
local cache_roots=(
"/data/chrome-analyzer/Default/Cache"
"/data/chrome-analyzer/Default/Code Cache"
"/data/chrome-analyzer/Default/GPUCache"
"/data/chrome-dualtabs/Default/Cache"
"/data/chrome-dualtabs/Default/Code Cache"
"/data/chrome-dualtabs/Default/GPUCache"
)
local path
for path in "${cache_roots[@]}"; do
if [ -e "$path" ]; then
rm -rf "$path" || true
fi
done
}
wait_for_health() {
local attempts="${1:-30}"
local delay="${2:-1}"
local i
for i in $(seq 1 "$attempts"); do
if health_ok; then
return 0
fi
sleep "$delay"
done
return 1
}
wait_for_candidate_health() {
local phoenix_dir="${1:-$PHOENIX_ROOT}"
local attempts="${2:-45}"
local delay="${3:-1}"
local start_try
local max_start_tries="${PHOENIX_UPDATE_START_TRIES:-3}"
if needs_phoenix_build "$phoenix_dir"; then
attempts="${PHOENIX_UPDATE_BUILD_HEALTH_ATTEMPTS:-420}"
echo "Phoenix tree requires local rebuild; extending health wait to ${attempts}s"
else
echo "Phoenix tree already has runnable binary; health wait ${attempts}s"
fi
for start_try in $(seq 1 "$max_start_tries"); do
echo "starting Phoenix services health attempt ${start_try}/${max_start_tries}"
start_all_services
if wait_for_health "$attempts" "$delay"; then
echo "Phoenix health OK on attempt ${start_try}/${max_start_tries}"
return 0
fi
echo "Phoenix health failed on attempt ${start_try}/${max_start_tries}"
stop_all_services
done
return 1
}
build_volumio_candidate() {
local phoenix_dir="${1:-$STAGE_DIR}"
local cargo_bin=""
local cargo_dir=""
local candidate
if ! needs_phoenix_build "$phoenix_dir"; then
echo "Volumio candidate already contains a runnable Phoenix binary"
return 0
fi
for candidate in /root/.cargo/bin/cargo /home/volumio/.cargo/bin/cargo /usr/local/bin/cargo /usr/bin/cargo; do
if [ -x "$candidate" ]; then
cargo_bin="$candidate"
break
fi
done
if [ -z "$cargo_bin" ]; then
echo "cargo not found; cannot build staged Volumio update" >&2
return 1
fi
cargo_dir="$(dirname "$cargo_bin")"
echo "building staged Volumio update before stopping the running kiosk"
if ! (
cd "$phoenix_dir"
PATH="$cargo_dir:/root/.cargo/bin:/home/volumio/.cargo/bin:/usr/local/bin:/usr/bin:/bin" \
CARGO_TERM_COLOR=never "$cargo_bin" build --release --locked
); then
if [ -d "$phoenix_dir/target" ]; then
chown -R volumio:volumio "$phoenix_dir/target" || true
fi
echo "staged Volumio build failed; running installation was left untouched" >&2
return 1
fi
chown -R volumio:volumio "$phoenix_dir/target"
if [ ! -x "$phoenix_dir/target/release/phoenix" ] || [ ! -s "$phoenix_dir/target/release/phoenix" ]; then
echo "staged Volumio build did not produce a runnable Phoenix binary" >&2
return 1
fi
echo "staged Volumio build completed"
}
start_all_services() {
if is_volumio_install; then
restart_if_present analyzer-web-volumio.service
clear_browser_asset_caches
restart_if_present analyzer-kiosk-volumio.service
return
fi
restart_if_present phoenix.service
restart_if_present analyzer-web.service
restart_if_present analyzer-web-volumio.service
clear_browser_asset_caches
restart_if_present analyzer-kiosk.service
restart_if_present analyzer-kiosk-volumio.service
}
stop_all_services() {
if is_volumio_install; then
stop_if_present analyzer-kiosk-volumio.service
stop_if_present analyzer-web-volumio.service
return
fi
stop_if_present analyzer-kiosk.service
stop_if_present analyzer-kiosk-volumio.service
stop_if_present analyzer-web.service
stop_if_present analyzer-web-volumio.service
stop_if_present phoenix.service
}
rollback_to_backup() {
stop_all_services
rm -rf "$FAILED_DIR"
if [ -d "$PHOENIX_ROOT" ]; then
mv "$PHOENIX_ROOT" "$FAILED_DIR"
fi
if [ ! -d "$BACKUP_DIR" ]; then
echo "backup missing; cannot roll back to $BACKUP_DIR" >&2
return 1
fi
mv "$BACKUP_DIR" "$PHOENIX_ROOT"
if ! wait_for_candidate_health "$PHOENIX_ROOT" "${PHOENIX_ROLLBACK_HEALTH_ATTEMPTS:-120}" 1; then
echo "backup rollback restored files but Phoenix health did not recover" >&2
return 1
fi
echo "rollback to backup succeeded"
}
if [ "${PHOENIX_UPDATE_DETACHED:-0}" != "1" ]; then
if is_volumio_install; then
echo "handing Volumio update to phoenix-update-volumio.service"
if start_volumio_update_service; then
echo "Volumio update service accepted"
exit 0
fi
echo "failed to start phoenix-update-volumio.service" >&2
echo "run scripts/install_volumio_services.sh once as root" >&2
exit 1
fi
if ! command -v systemd-run >/dev/null 2>&1; then
echo "systemd-run not found; cannot safely detach updater" >&2
exit 1
fi
echo "detaching updater into transient systemd unit"
if run_systemd_run; then
echo "detached updater started"
exit 0
fi
echo "failed to start detached updater" >&2
exit 1
fi
if [ ! -d "$STAGE_DIR" ]; then
echo "staged update missing: $STAGE_DIR" >&2
exit 1
fi
if [ ! -f "$STAGE_DIR/Cargo.toml" ] || [ ! -d "$STAGE_DIR/src" ] || [ ! -d "$STAGE_DIR/www" ] || [ ! -d "$STAGE_DIR/scripts" ]; then
echo "staged update invalid: $STAGE_DIR" >&2
exit 1
fi
if is_volumio_install; then
build_volumio_candidate "$STAGE_DIR"
fi
stop_all_services
rm -rf "$BACKUP_DIR"
if [ -d "$PHOENIX_ROOT" ]; then
mv "$PHOENIX_ROOT" "$BACKUP_DIR"
fi
mv "$STAGE_DIR" "$PHOENIX_ROOT"
health_attempts=45
health_delay=1
if ! wait_for_candidate_health "$PHOENIX_ROOT" "$health_attempts" "$health_delay"; then
if ! rollback_to_backup; then
echo "new Phoenix version failed health check and rollback failed" >&2
exit 1
fi
echo "new Phoenix version failed health check; rolled back to backup" >&2
exit 1
fi
if is_volumio_install && [ "$(id -u)" -eq 0 ] && [ -f "$PHOENIX_ROOT/scripts/restart_phoenix_services.sh" ]; then
install -o root -g root -m 0755 \
"$PHOENIX_ROOT/scripts/restart_phoenix_services.sh" \
/usr/local/libexec/phoenix/restart_phoenix_services.sh
echo "Volumio privileged update helper refreshed"
fi
echo "=== $(date): restart_phoenix_services.sh OK ==="