Compare commits

...

2 Commits

Author SHA1 Message Date
lendry
34c1d8446a fix sso healtcheck and remove any span frontend 2026-06-24 15:44:24 +03:00
lendry
ecd95c5698 fix sso healtcheck 2026-06-24 15:28:03 +03:00
8 changed files with 171 additions and 20 deletions

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@ dist
!.env.example
docker-compose.override.yml
.idp-install.json
.idp-infra.secrets
nginx/certs/*
!nginx/certs/.gitkeep
nginx/conf.d/*.conf

View File

@@ -358,7 +358,6 @@ export default function LoginPage() {
) : null}
<ProjectTagline className="mt-9 text-center text-sm font-semibold" />
<p className="mt-2 text-center text-sm font-bold">Узнать больше</p>
</section>
</main>
);

View File

@@ -69,10 +69,6 @@ export default function RegisterPage() {
{isSubmitting ? 'Отправляем...' : 'Получить код'}
</Button>
</form>
<div className="mt-5 flex items-start gap-3 rounded-[22px] bg-[#2a2c36] p-4 text-sm">
<ShieldCheck className="mt-0.5 h-5 w-5 text-[#8ec5ff]" />
<p>Первый зарегистрированный пользователь автоматически станет суперадминистратором.</p>
</div>
<Button asChild variant="ghost" className="mt-5 w-full text-white hover:bg-[#2a2c36]">
<Link href="/auth/login">У меня уже есть ID</Link>
</Button>

View File

@@ -48,9 +48,7 @@ export function Sidebar({ active }: { active: string }) {
<LogOut className="h-3.5 w-3.5" />
Выйти
</button>
<p>Русский</p>
<p>Справка</p>
<p>© 2026 Lendry</p>
<p>© 2026</p>
</div>
</aside>
);

View File

@@ -41,6 +41,9 @@ RUN npm --workspace @lendry/sso-core run prisma:generate \
&& npm --workspace @lendry/sso-core run proto:generate \
&& npm --workspace @lendry/sso-core run build
COPY apps/sso-core/docker-entrypoint.sh /app/apps/sso-core/docker-entrypoint.sh
RUN chmod +x /app/apps/sso-core/docker-entrypoint.sh
EXPOSE 3001 50051
CMD ["sh", "-c", "npm --workspace @lendry/sso-core run prisma:push && node apps/sso-core/dist/main.js"]
CMD ["/app/apps/sso-core/docker-entrypoint.sh"]

View File

@@ -0,0 +1,23 @@
#!/bin/sh
set -e
echo "[sso-core] Применение схемы БД (Prisma)..."
attempt=0
max_attempts=30
while [ "$attempt" -lt "$max_attempts" ]; do
attempt=$((attempt + 1))
if npm --workspace @lendry/sso-core run prisma:push; then
echo "[sso-core] Схема БД синхронизирована"
break
fi
if [ "$attempt" -ge "$max_attempts" ]; then
echo "[sso-core] ОШИБКА: не удалось подключиться к PostgreSQL после ${max_attempts} попыток." >&2
echo "[sso-core] Проверьте POSTGRES_* в .env и пароль существующего volume postgres_data." >&2
exit 1
fi
echo "[sso-core] PostgreSQL недоступен или неверный пароль, повтор ${attempt}/${max_attempts}..."
sleep 3
done
exec node apps/sso-core/dist/main.js

View File

@@ -110,10 +110,11 @@ services:
ldap-auth:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://localhost:3001/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3001/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 10s
timeout: 5s
retries: 10
timeout: 10s
retries: 12
start_period: 120s
api-gateway:
pull_policy: build
@@ -143,10 +144,11 @@ services:
minio:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://localhost:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 10s
timeout: 5s
retries: 10
timeout: 10s
retries: 12
start_period: 60s
media-ws:
pull_policy: build

View File

@@ -22,6 +22,7 @@ LOCAL_CONF_DIR="${ROOT_DIR}/nginx/conf.d"
LOCAL_CERTS_DIR="${ROOT_DIR}/nginx/certs"
COMPOSE_OVERRIDE="${ROOT_DIR}/docker-compose.override.yml"
STATE_FILE="${ROOT_DIR}/.idp-install.json"
INFRA_SECRETS_FILE="${ROOT_DIR}/.idp-infra.secrets"
NON_INTERACTIVE=0
FORCE_ENV="${FORCE_ENV:-0}"
@@ -62,6 +63,7 @@ ${BOLD}Lendry ID v${SCRIPT_VERSION}${NC} — установка и управл
./install.sh --renew-ssl Обновить сертификаты Let's Encrypt
./install.sh --restart Перезапуск контейнеров
./install.sh --status Статус сервисов
./install.sh --reset-db Сброс PostgreSQL (новый пароль из .env, данные удалятся)
./install.sh --remove-nginx Удалить конфиги Nginx IdP
${BOLD}Режим локальной сети (без интернета / AD-домены .local .lpr):${NC}
@@ -85,7 +87,7 @@ ${BOLD}Прочие опции:${NC}
-h, --help Справка
${BOLD}Переменные окружения:${NC}
FORCE_ENV=1 Пересоздать .env (секреты будут новые)
FORCE_ENV=1 Новые JWT-секреты (пароли БД/MinIO/RabbitMQ сохраняются если volume уже есть)
OFFLINE=1 То же, что --offline
${BOLD}Примеры:${NC}
@@ -117,7 +119,7 @@ parse_args() {
--renew-ssl) ACTION="renew-ssl"; shift ;;
--restart) ACTION="restart"; shift ;;
--status) ACTION="status"; shift ;;
--remove-nginx) ACTION="remove-nginx"; shift ;;
--reset-db) ACTION="reset-db"; shift ;;
--local) INSTALL_LOCAL=1; shift ;;
--intranet) INSTALL_INTRANET=1; shift ;;
--offline) OFFLINE=1; shift ;;
@@ -637,17 +639,139 @@ write_env_secrets_if_missing() {
cp .env.example .env 2>/dev/null || touch .env
fi
if [[ "$FORCE_ENV" == "1" ]] || [[ "$(env_get POSTGRES_PASSWORD change-me-postgres)" == "change-me-postgres" ]]; then
load_infra_secrets_into_env
if docker_volume_exists postgres_data; then
if [[ -n "$(env_get POSTGRES_PASSWORD "")" ]]; then
warn "Volume PostgreSQL уже существует — POSTGRES_PASSWORD в .env не меняем"
else
fail "Volume PostgreSQL существует, но POSTGRES_PASSWORD не найден. Восстановите .env или выполните: ./install.sh --reset-db"
fi
pg_pass="$(env_get POSTGRES_PASSWORD "$pg_pass")"
fi
if docker_volume_exists rabbitmq_data; then
warn "Volume RabbitMQ уже существует — RABBITMQ_DEFAULT_PASS не меняем"
rmq_pass="$(env_get RABBITMQ_DEFAULT_PASS "$rmq_pass")"
fi
if docker_volume_exists minio_data; then
warn "Volume MinIO уже существует — MINIO_ROOT_PASSWORD не меняем"
minio_pass="$(env_get MINIO_ROOT_PASSWORD "$minio_pass")"
fi
local need_secrets=0
if [[ "$FORCE_ENV" == "1" ]]; then
need_secrets=1
elif [[ "$(env_get POSTGRES_PASSWORD change-me-postgres)" == "change-me-postgres" ]]; then
need_secrets=1
elif [[ "$(env_get JWT_ACCESS_SECRET change-me-access-secret)" == "change-me-access-secret" ]]; then
need_secrets=1
fi
if [[ "$need_secrets" -eq 1 ]]; then
env_set POSTGRES_PASSWORD "$pg_pass"
env_set RABBITMQ_DEFAULT_PASS "$rmq_pass"
env_set MINIO_ROOT_PASSWORD "$minio_pass"
env_set JWT_ACCESS_SECRET "$jwt_access"
env_set JWT_REFRESH_SECRET "$jwt_refresh"
env_set DATA_ENCRYPTION_KEY "$data_key"
ok "Секреты сгенерированы"
save_infra_secrets
ok "Секреты сгенерированы / синхронизированы"
fi
}
compose_project_name() {
load_env
echo "${COMPOSE_PROJECT_NAME:-lendry-id}"
}
docker_volume_name() {
echo "$(compose_project_name)_$1"
}
docker_volume_exists() {
docker volume inspect "$(docker_volume_name "$1")" >/dev/null 2>&1
}
save_infra_secrets() {
load_env
cat >"$INFRA_SECRETS_FILE" <<EOF
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-}
RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS:-}
MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-}
EOF
chmod 600 "$INFRA_SECRETS_FILE" 2>/dev/null || true
}
load_infra_secrets_into_env() {
[[ -f "$INFRA_SECRETS_FILE" ]] || return 0
# shellcheck disable=SC1091
set -a && source "$INFRA_SECRETS_FILE" && set +a
[[ -n "${POSTGRES_PASSWORD:-}" ]] && env_set POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
[[ -n "${RABBITMQ_DEFAULT_PASS:-}" ]] && env_set RABBITMQ_DEFAULT_PASS "$RABBITMQ_DEFAULT_PASS"
[[ -n "${MINIO_ROOT_PASSWORD:-}" ]] && env_set MINIO_ROOT_PASSWORD "$MINIO_ROOT_PASSWORD"
}
verify_postgres_auth() {
load_env
load_infra_secrets_into_env
[[ -f .env ]] || return 0
docker_cmd compose ps postgres 2>/dev/null | grep -q postgres || return 0
local user pass db
user="$(env_get POSTGRES_USER lendry)"
pass="$(env_get POSTGRES_PASSWORD "")"
db="$(env_get POSTGRES_DB lendry_id)"
[[ -n "$pass" ]] || return 0
if docker_cmd compose exec -T -e PGPASSWORD="$pass" postgres \
psql -U "$user" -d "$db" -c 'SELECT 1' >/dev/null 2>&1; then
ok "PostgreSQL: пароль из .env подходит"
save_infra_secrets
return 0
fi
echo ""
fail "PostgreSQL: пароль в .env не совпадает с данными в volume (ошибка P1000).
Это происходит после FORCE_ENV=1 или смены POSTGRES_PASSWORD при существующей БД.
Решения:
1) Сбросить БД (удалит всех пользователей и данные):
./install.sh --reset-db --yes && ./install.sh --restart
2) Вернуть старый POSTGRES_PASSWORD в .env (если сохранили)
3) Если есть файл ${INFRA_SECRETS_FILE} — скопируйте пароль оттуда в .env"
}
action_reset_db() {
load_env
local vol
vol="$(docker_volume_name postgres_data)"
if [[ "$NON_INTERACTIVE" -ne 1 ]]; then
echo ""
warn "Будет удалён volume ${vol} — все пользователи, сессии и настройки в PostgreSQL пропадут."
read -r -p "Продолжить? [y/N]: " confirm
[[ "$confirm" =~ ^[Yy]$ ]] || fail "Отменено"
fi
log "Остановка сервисов..."
docker_cmd compose --env-file .env --profile proxy down 2>/dev/null || docker_cmd compose --env-file .env down 2>/dev/null || true
log "Удаление ${vol}..."
if docker volume inspect "$vol" >/dev/null 2>&1; then
docker volume rm "$vol" || fail "Не удалось удалить ${vol}"
else
warn "Volume ${vol} не найден — возможно, уже удалён"
fi
ok "PostgreSQL volume удалён. PostgreSQL создастся заново с паролем из .env."
save_infra_secrets
}
persist_domain_env() {
write_env_secrets_if_missing
@@ -1319,6 +1443,7 @@ deploy_stack() {
write_compose_override
load_env
verify_postgres_auth
local compose_cmd=(compose --env-file .env)
if [[ -n "$(env_get DOMAIN_API "")" && "$(env_get INSTALL_MODE local)" != "local" ]]; then
@@ -1328,6 +1453,7 @@ deploy_stack() {
log "Сборка и запуск контейнеров (1020 минут при первом запуске)..."
docker_cmd "${compose_cmd[@]}" up -d --build
wait_for_service "sso-core" 120
wait_for_service "api-gateway" 90
wait_for_service "frontend" 60
wait_for_service "docs" 60
@@ -1494,11 +1620,12 @@ show_menu() {
echo " 4) Перезапуск / пересборка контейнеров"
echo " 5) Статус сервисов"
echo " 6) Удалить конфиги Nginx IdP"
echo " 7) Сброс PostgreSQL (если ошибка P1000 / пароль БД)"
echo " 0) Выход"
echo ""
local choice
read -r -p "Выберите пункт [0-6]: " choice
read -r -p "Выберите пункт [0-7]: " choice
case "$choice" in
1) NON_INTERACTIVE=0; action_full_install ;;
@@ -1507,6 +1634,7 @@ show_menu() {
4) action_restart ;;
5) show_status ;;
6) remove_nginx_configs; ok "Готово" ;;
7) action_reset_db; action_restart ;;
0) exit 0 ;;
*) warn "Неверный пункт" ;;
esac
@@ -1527,6 +1655,7 @@ main() {
renew-ssl) action_renew_ssl ;;
restart) action_restart ;;
status) show_status ;;
reset-db) action_reset_db ;;
remove-nginx) remove_nginx_configs ;;
"")
if [[ -f .env ]] && [[ "$NON_INTERACTIVE" -ne 1 ]]; then