687e059a86
FRESH 清除 nexus-state 旧锁;PENDING=1 时 entrypoint 不恢复旧 env;验收脚本已安装期望 404。 Co-authored-by: Cursor <cursoragent@cursor.com>
176 lines
5.0 KiB
Bash
176 lines
5.0 KiB
Bash
#!/bin/sh
|
|
# Nexus Docker entrypoint — wait for deps, sync .env with persistent volume, exec uvicorn.
|
|
set -eu
|
|
|
|
PERSIST_DIR="${NEXUS_PERSIST_DIR:-/var/lib/nexus}"
|
|
PERSIST_ENV="${PERSIST_DIR}/.env"
|
|
|
|
wait_tcp() {
|
|
host="$1"
|
|
port="$2"
|
|
echo "entrypoint: waiting for ${host}:${port}..."
|
|
until python3 -c "
|
|
import socket
|
|
s = socket.socket()
|
|
s.settimeout(2)
|
|
s.connect(('${host}', ${port}))
|
|
s.close()
|
|
" 2>/dev/null; do
|
|
sleep 2
|
|
done
|
|
}
|
|
|
|
wait_tcp_optional() {
|
|
host="$1"
|
|
port="$2"
|
|
tries="${3:-15}"
|
|
label="${4:-service}"
|
|
echo "entrypoint: waiting for ${label} ${host}:${port} (max ${tries} tries)..."
|
|
n=0
|
|
while [ "$n" -lt "$tries" ]; do
|
|
if python3 -c "
|
|
import socket
|
|
s = socket.socket()
|
|
s.settimeout(2)
|
|
s.connect(('${host}', ${port}))
|
|
s.close()
|
|
" 2>/dev/null; then
|
|
echo "entrypoint: ${label} ready at ${host}:${port}"
|
|
return 0
|
|
fi
|
|
n=$((n + 1))
|
|
sleep 2
|
|
done
|
|
echo "entrypoint: warn — ${label} not reachable at ${host}:${port}; install on host or set URL in .env"
|
|
return 0
|
|
}
|
|
|
|
restore_persisted_install_lock() {
|
|
if [ "${NEXUS_INSTALL_WIZARD_PENDING:-0}" = "1" ]; then
|
|
return 0
|
|
fi
|
|
PERSIST_LOCK="${PERSIST_DIR}/.install_locked"
|
|
if [ -f "${PERSIST_LOCK}" ] && [ ! -f /app/.install_locked ]; then
|
|
cp "${PERSIST_LOCK}" /app/.install_locked
|
|
chmod 600 /app/.install_locked
|
|
echo "entrypoint: restored .install_locked from ${PERSIST_LOCK}"
|
|
fi
|
|
}
|
|
|
|
archive_install_wizard_if_locked() {
|
|
if [ "${NEXUS_INSTALL_WIZARD_PENDING:-0}" = "1" ]; then
|
|
rm -f /app/.install_locked "${PERSIST_DIR}/.install_locked" 2>/dev/null || true
|
|
if [ -f /app/web/app/install.html.bak ] && [ ! -f /app/web/app/install.html ]; then
|
|
mv /app/web/app/install.html.bak /app/web/app/install.html
|
|
echo "entrypoint: restored install.html from .bak (wizard pending)"
|
|
fi
|
|
return 0
|
|
fi
|
|
if [ ! -f /app/.install_locked ] && [ ! -f "${PERSIST_DIR}/.install_locked" ]; then
|
|
return 0
|
|
fi
|
|
if [ -f /app/web/app/install.html.bak ]; then
|
|
if [ -f /app/web/app/install.html ]; then
|
|
rm -f /app/web/app/install.html
|
|
echo "entrypoint: removed install.html (wizard archived as install.html.bak)"
|
|
fi
|
|
return 0
|
|
fi
|
|
if [ -f /app/web/app/install.html ]; then
|
|
mv /app/web/app/install.html /app/web/app/install.html.bak
|
|
echo "entrypoint: archived install.html → install.html.bak"
|
|
fi
|
|
}
|
|
|
|
restore_persisted_env() {
|
|
if [ "${NEXUS_INSTALL_WIZARD_PENDING:-0}" = "1" ]; then
|
|
return 0
|
|
fi
|
|
if [ ! -f "${PERSIST_ENV}" ]; then
|
|
return 0
|
|
fi
|
|
if ! grep -q '^NEXUS_DATABASE_URL=' "${PERSIST_ENV}" 2>/dev/null; then
|
|
echo "entrypoint: warn — ${PERSIST_ENV} missing NEXUS_DATABASE_URL; skip restore (complete install wizard)"
|
|
return 0
|
|
fi
|
|
cp "${PERSIST_ENV}" /app/.env
|
|
chmod 600 /app/.env
|
|
echo "entrypoint: restored .env from ${PERSIST_ENV}"
|
|
}
|
|
|
|
# Compose may inject placeholder NEXUS_REDIS_URL (no password). Wizard .env wins.
|
|
export_app_env() {
|
|
if [ ! -f /app/.env ]; then
|
|
return 0
|
|
fi
|
|
set -a
|
|
# shellcheck disable=SC1091
|
|
. /app/.env
|
|
set +a
|
|
echo "entrypoint: exported NEXUS_* from /app/.env (overrides Compose placeholders)"
|
|
}
|
|
|
|
write_env_from_environment() {
|
|
if [ -f /app/.env ]; then
|
|
return 0
|
|
fi
|
|
if [ "${NEXUS_DOCKER_WRITE_ENV:-}" != "1" ]; then
|
|
return 0
|
|
fi
|
|
if [ -z "${NEXUS_SECRET_KEY:-}" ]; then
|
|
return 0
|
|
fi
|
|
if [ "${NEXUS_INSTALL_WIZARD_PENDING:-}" = "1" ]; then
|
|
echo "entrypoint: install wizard pending — skip writing /app/.env"
|
|
return 0
|
|
fi
|
|
if [ -z "${NEXUS_DATABASE_URL:-}" ]; then
|
|
echo "entrypoint: skip writing /app/.env — NEXUS_DATABASE_URL not set (use /app/install.html)"
|
|
return 0
|
|
fi
|
|
mkdir -p "${PERSIST_DIR}"
|
|
{
|
|
echo "# Generated by docker/entrypoint.sh — do not commit"
|
|
env | grep '^NEXUS_' | sort
|
|
} > /app/.env
|
|
chmod 600 /app/.env
|
|
cp /app/.env "${PERSIST_ENV}"
|
|
echo "entrypoint: wrote .env from container environment"
|
|
}
|
|
|
|
persist_state_on_exit() {
|
|
if [ -f /app/.env ]; then
|
|
mkdir -p "${PERSIST_DIR}"
|
|
cp /app/.env "${PERSIST_ENV}"
|
|
chmod 600 "${PERSIST_ENV}" 2>/dev/null || true
|
|
fi
|
|
if [ -f /app/.install_locked ]; then
|
|
mkdir -p "${PERSIST_DIR}"
|
|
cp /app/.install_locked "${PERSIST_DIR}/.install_locked"
|
|
chmod 600 "${PERSIST_DIR}/.install_locked" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
trap persist_state_on_exit EXIT INT TERM
|
|
|
|
# MySQL / Redis 均由用户自行安装在宿主机;安装向导阶段不阻塞启动
|
|
if [ "${NEXUS_INSTALL_WIZARD_PENDING:-0}" != "1" ] && [ "${NEXUS_SKIP_MYSQL_WAIT:-0}" != "1" ]; then
|
|
MYSQL_HOST="${NEXUS_1PANEL_DB_HOST:-${MYSQL_HOST:-host.docker.internal}}"
|
|
MYSQL_PORT="${MYSQL_PORT:-3306}"
|
|
wait_tcp_optional "${MYSQL_HOST}" "${MYSQL_PORT}" 30 "MySQL"
|
|
fi
|
|
|
|
if [ "${NEXUS_INSTALL_WIZARD_PENDING:-0}" != "1" ] && [ "${NEXUS_SKIP_REDIS_WAIT:-0}" != "1" ]; then
|
|
REDIS_HOST="${NEXUS_1PANEL_REDIS_HOST:-${REDIS_HOST:-host.docker.internal}}"
|
|
REDIS_PORT="${REDIS_PORT:-6379}"
|
|
wait_tcp_optional "${REDIS_HOST}" "${REDIS_PORT}" 15 "Redis"
|
|
fi
|
|
|
|
restore_persisted_install_lock
|
|
archive_install_wizard_if_locked
|
|
restore_persisted_env
|
|
write_env_from_environment
|
|
export_app_env
|
|
|
|
exec "$@"
|