171 lines
5.4 KiB
Bash
Executable File
171 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
INSTALL_ROOT="${ERP_INSTALL_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd -P)}"
|
|
CONFIG_FILE="${ERP_CONFIG_FILE:-$INSTALL_ROOT/config/erp.env}"
|
|
|
|
say() { printf '[ERP] %s\n' "$*"; }
|
|
fail() { printf '[ERP] ERROR: %s\n' "$*" >&2; exit 1; }
|
|
|
|
load_configuration() {
|
|
[[ -r "$CONFIG_FILE" ]] || fail "configuration not readable: $CONFIG_FILE"
|
|
set -a
|
|
# The installer writes this file with POSIX shell-safe single-quoted values.
|
|
# shellcheck disable=SC1090
|
|
source "$CONFIG_FILE"
|
|
set +a
|
|
|
|
RUN_DIR="${ERP_RUN_DIR:-$INSTALL_ROOT/run}"
|
|
JAR_PATH="${ERP_JAR_PATH:-$INSTALL_ROOT/current/app/kaidi-erp.jar}"
|
|
INSTALLER_JAR="${ERP_INSTALLER_JAR:-$INSTALL_ROOT/installer/kaidi-erp-installer.jar}"
|
|
PENDING_FILE="${ERP_INSTALL_PENDING_FILE:-$INSTALL_ROOT/state/install.pending}"
|
|
INSTALL_LOCK_FILE="${ERP_INSTALL_LOCK_FILE:-$INSTALL_ROOT/state/install.lock}"
|
|
INSTALL_LOG_FILE="${ERP_INSTALL_LOG_FILE:-$(dirname "$PENDING_FILE")/install-formal.log}"
|
|
HEALTH_URL="${ERP_HEALTH_URL:-http://127.0.0.1:${SERVER_PORT:-8091}/api/oa/health}"
|
|
HEALTH_TIMEOUT_SECONDS="${ERP_INSTALL_HEALTH_TIMEOUT_SECONDS:-240}"
|
|
HEALTH_POLL_SECONDS="${ERP_UPDATE_HEALTH_POLL_SECONDS:-2}"
|
|
}
|
|
|
|
resolve_java() {
|
|
JAVA_BIN="${ERP_JAVA_BIN:-}"
|
|
if [[ -z "$JAVA_BIN" ]]; then
|
|
if [[ -n "${JAVA_HOME:-}" && -x "$JAVA_HOME/bin/java" ]]; then
|
|
JAVA_BIN="$JAVA_HOME/bin/java"
|
|
else
|
|
JAVA_BIN="$(command -v java || true)"
|
|
fi
|
|
fi
|
|
[[ -n "$JAVA_BIN" && -x "$JAVA_BIN" ]] || fail 'Java 17+ is not installed'
|
|
local java_major
|
|
java_major="$("$JAVA_BIN" -version 2>&1 | awk -F'[".]' '/version/ {print $2; exit}')"
|
|
[[ "$java_major" =~ ^[0-9]+$ && "$java_major" -ge 17 ]] || fail 'Java 17+ is required'
|
|
}
|
|
|
|
split_java_options() {
|
|
IFS=$' \t' read -r -a JAVA_OPTS <<< "${ERP_JAVA_OPTS:--Xms512m -Xmx2g}"
|
|
IFS=$' \t' read -r -a INSTALLER_JAVA_OPTS <<< "${ERP_INSTALLER_JAVA_OPTS:--Xms128m -Xmx512m}"
|
|
}
|
|
|
|
write_pid() {
|
|
mkdir -p "$RUN_DIR"
|
|
printf '%s\n' "$1" > "$RUN_DIR/app.pid"
|
|
}
|
|
|
|
clear_pid() {
|
|
local expected="$1"
|
|
if [[ -r "$RUN_DIR/app.pid" && "$(<"$RUN_DIR/app.pid")" == "$expected" ]]; then
|
|
rm -f "$RUN_DIR/app.pid"
|
|
fi
|
|
}
|
|
|
|
run_formal_application_direct() {
|
|
[[ -r "$JAR_PATH" ]] || fail "application jar not readable: $JAR_PATH"
|
|
write_pid "$$"
|
|
exec "$JAVA_BIN" "${JAVA_OPTS[@]}" \
|
|
-jar "$JAR_PATH" \
|
|
--spring.profiles.active=postgres \
|
|
--server.port="${SERVER_PORT:-8091}"
|
|
}
|
|
|
|
run_web_installer() {
|
|
[[ -r "$INSTALLER_JAR" ]] || fail "installer jar not readable: $INSTALLER_JAR"
|
|
say "Starting first-run installer on port ${SERVER_PORT:-8091}"
|
|
printf '%s\n' "$$" > "$RUN_DIR/installer.pid"
|
|
set +e
|
|
"$JAVA_BIN" "${INSTALLER_JAVA_OPTS[@]}" \
|
|
-jar "$INSTALLER_JAR" \
|
|
--server.port="${SERVER_PORT:-8091}"
|
|
local status=$?
|
|
set -e
|
|
rm -f "$RUN_DIR/installer.pid"
|
|
[[ "$status" == "0" ]] || fail "web installer exited with status $status"
|
|
[[ -f "$PENDING_FILE" ]] || fail 'web installer exited before installation was completed'
|
|
}
|
|
|
|
finalize_installation() {
|
|
[[ -f "$PENDING_FILE" ]] || fail "pending installation marker is missing: $PENDING_FILE"
|
|
[[ ! -e "$INSTALL_LOCK_FILE" ]] || fail "installation lock already exists: $INSTALL_LOCK_FILE"
|
|
mkdir -p "$(dirname "$INSTALL_LOCK_FILE")"
|
|
mv "$PENDING_FILE" "$INSTALL_LOCK_FILE"
|
|
chmod 600 "$INSTALL_LOCK_FILE"
|
|
rm -rf "$INSTALL_ROOT/installer"
|
|
say "Installation lock written; the web installer has been removed"
|
|
}
|
|
|
|
run_pending_formal_application() {
|
|
[[ -r "$JAR_PATH" ]] || fail "application jar not readable: $JAR_PATH"
|
|
[[ "$HEALTH_TIMEOUT_SECONDS" =~ ^[1-9][0-9]*$ ]] || fail 'invalid installation health timeout'
|
|
[[ "$HEALTH_POLL_SECONDS" =~ ^[1-9][0-9]*$ ]] || fail 'invalid health poll interval'
|
|
|
|
say 'Starting the formal PostgreSQL application'
|
|
mkdir -p "$(dirname "$INSTALL_LOG_FILE")"
|
|
: > "$INSTALL_LOG_FILE"
|
|
chmod 600 "$INSTALL_LOG_FILE"
|
|
"$JAVA_BIN" "${JAVA_OPTS[@]}" \
|
|
-jar "$JAR_PATH" \
|
|
--spring.profiles.active=postgres \
|
|
--server.port="${SERVER_PORT:-8091}" \
|
|
> >(tee -a "$INSTALL_LOG_FILE") 2>&1 &
|
|
APP_PID=$!
|
|
write_pid "$APP_PID"
|
|
|
|
forward_signal() {
|
|
kill -TERM "$APP_PID" 2>/dev/null || true
|
|
}
|
|
trap forward_signal TERM INT
|
|
|
|
local deadline=$((SECONDS + HEALTH_TIMEOUT_SECONDS))
|
|
while (( SECONDS < deadline )); do
|
|
if ! kill -0 "$APP_PID" 2>/dev/null; then
|
|
set +e
|
|
wait "$APP_PID"
|
|
local status=$?
|
|
set -e
|
|
clear_pid "$APP_PID"
|
|
say "Formal application diagnostics: $INSTALL_LOG_FILE"
|
|
fail "formal application exited before becoming healthy (status $status)"
|
|
fi
|
|
if curl -fsS --connect-timeout 2 --max-time 5 "$HEALTH_URL" >/dev/null 2>&1; then
|
|
finalize_installation
|
|
set +e
|
|
wait "$APP_PID"
|
|
local status=$?
|
|
set -e
|
|
clear_pid "$APP_PID"
|
|
return "$status"
|
|
fi
|
|
sleep "$HEALTH_POLL_SECONDS"
|
|
done
|
|
|
|
kill -TERM "$APP_PID" 2>/dev/null || true
|
|
set +e
|
|
wait "$APP_PID"
|
|
set -e
|
|
clear_pid "$APP_PID"
|
|
say "Formal application diagnostics: $INSTALL_LOG_FILE"
|
|
fail "formal application did not become healthy within ${HEALTH_TIMEOUT_SECONDS} seconds"
|
|
}
|
|
|
|
main() {
|
|
load_configuration
|
|
resolve_java
|
|
split_java_options
|
|
mkdir -p "$RUN_DIR"
|
|
|
|
if [[ -f "$INSTALL_LOCK_FILE" ]]; then
|
|
run_formal_application_direct
|
|
fi
|
|
|
|
if [[ ! -f "$PENDING_FILE" ]]; then
|
|
run_web_installer
|
|
load_configuration
|
|
resolve_java
|
|
split_java_options
|
|
fi
|
|
|
|
run_pending_formal_application
|
|
}
|
|
|
|
main "$@"
|