e97f260113
`glchat update` на стенде с внешним прокси всегда сообщал «приложение не поднялось»: readyz проверялся на 127.0.0.1, а приложение слушает адрес в WireGuard (GLCHAT_APP_BIND). Тот же дефект был в restore.sh и в `glchat status` (health показывался как unreachable). Добавлен общий помощник app_check_url.
107 lines
4.3 KiB
Bash
Executable File
107 lines
4.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# glchat: обновление стека (AGENT.md 9.3, 10.11).
|
|
set -euo pipefail
|
|
|
|
GLCHAT_ETC_DIR="${GLCHAT_ETC_DIR:-/opt/glchat}"
|
|
ENV_FILE="${GLCHAT_ETC_DIR}/.env"
|
|
COMPOSE_FILE="${GLCHAT_ETC_DIR}/compose.yaml"
|
|
REPO_DIR_DEFAULT="${GLCHAT_REPO_DIR:-/opt/glchat-src}"
|
|
|
|
# app_check_url печатает адрес /readyz с учётом привязки приложения: во внешнем
|
|
# режиме оно слушает WireGuard-адрес, и проверка localhost всегда падала бы.
|
|
app_check_url() {
|
|
local port="$1" host="${2:-}"
|
|
case "$host" in
|
|
0.0.0.0 | "" | "::") host="127.0.0.1" ;;
|
|
esac
|
|
printf 'http://%s:%s/readyz' "$host" "$port"
|
|
}
|
|
|
|
log() { printf '[update] %s\n' "$*"; }
|
|
die() {
|
|
printf '[update] ошибка: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
TARGET_VERSION=""
|
|
CHANNEL=""
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--version) TARGET_VERSION="${2:?}"; shift 2 ;;
|
|
--channel) CHANNEL="${2:?}"; shift 2 ;;
|
|
*) die "неизвестный аргумент: $1" ;;
|
|
esac
|
|
done
|
|
|
|
[ -f "$ENV_FILE" ] || die "не найден ${ENV_FILE}"
|
|
[ -f "$COMPOSE_FILE" ] || die "не найден ${COMPOSE_FILE}"
|
|
|
|
# shellcheck disable=SC1090
|
|
set -a && . "$ENV_FILE" && set +a
|
|
|
|
CURRENT="${APP_VERSION:-unknown}"
|
|
TARGET="${TARGET_VERSION:-$CURRENT}"
|
|
[ -n "$CHANNEL" ] && TARGET_CHANNEL="$CHANNEL" || TARGET_CHANNEL="${CHANNEL_NAME:-stable}"
|
|
|
|
log "текущая версия: ${CURRENT} → целевая: ${TARGET} (канал ${TARGET_CHANNEL})"
|
|
|
|
if [ "$CURRENT" = "$TARGET" ] && [ -z "${GLCHAT_FORCE_UPDATE:-}" ]; then
|
|
log "версия не изменилась; для принудительного обновления задайте GLCHAT_FORCE_UPDATE=1"
|
|
fi
|
|
|
|
log "бэкап перед обновлением (обязательно)"
|
|
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/backup.sh" || die "бэкап не удался; обновление остановлено"
|
|
|
|
compose_args=(-f "$COMPOSE_FILE")
|
|
[ "${PROXY_MODE:-embedded}" = "embedded" ] && compose_args+=(--profile embedded-proxy)
|
|
|
|
if [ "$APP_IMAGE" = "glchat:local" ] || [ -z "${APP_IMAGE:-}" ]; then
|
|
REPO_DIR="${GLCHAT_REPO_DIR:-$REPO_DIR_DEFAULT}"
|
|
if [ -d "${REPO_DIR}/.git" ]; then
|
|
log "обновляем исходники в ${REPO_DIR}"
|
|
git -C "$REPO_DIR" fetch --tags --depth 1 origin
|
|
if [ -n "$TARGET_VERSION" ]; then
|
|
git -C "$REPO_DIR" checkout "$TARGET_VERSION"
|
|
else
|
|
git -C "$REPO_DIR" pull --ff-only
|
|
fi
|
|
log "пересобираем образ"
|
|
docker build -t "${APP_IMAGE:-glchat:local}" \
|
|
--build-arg "VERSION=${TARGET}" \
|
|
--build-arg "COMMIT=$(git -C "$REPO_DIR" rev-parse --short HEAD)" \
|
|
--build-arg "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
"$REPO_DIR" || die "сборка не удалась"
|
|
else
|
|
die "каталог исходников ${REPO_DIR} не найден; выполните git clone или задайте GLCHAT_REPO_DIR"
|
|
fi
|
|
else
|
|
log "скачиваем образ ${APP_IMAGE}"
|
|
docker pull "$APP_IMAGE" || die "не удалось скачать образ"
|
|
fi
|
|
|
|
log "применяем новую версию"
|
|
(cd "$GLCHAT_ETC_DIR" && docker compose "${compose_args[@]}" up -d --remove-orphans) || die "не удалось поднять стек"
|
|
|
|
READY_URL="$(app_check_url "${APP_PORT:-8080}" "${GLCHAT_APP_BIND:-}")"
|
|
|
|
log "ожидаем готовности ${READY_URL} (миграции выполняются на старте приложения)"
|
|
for _ in $(seq 1 45); do
|
|
if curl -fsS "$READY_URL" >/dev/null 2>&1; then
|
|
log "приложение готово"
|
|
break
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
if ! curl -fsS "$READY_URL" >/dev/null 2>&1; then
|
|
die "приложение не поднялось; откат: glchat restore <бэкап>, затем docker compose up -d"
|
|
fi
|
|
|
|
if command -v sed >/dev/null 2>&1; then
|
|
sed -i "s/^APP_VERSION=.*/APP_VERSION=${TARGET}/" "$ENV_FILE"
|
|
sed -i "s/^CHANNEL_NAME=.*/CHANNEL_NAME=${TARGET_CHANNEL}/" "$ENV_FILE" 2>/dev/null || printf 'CHANNEL_NAME=%s\n' "$TARGET_CHANNEL" >>"$ENV_FILE"
|
|
fi
|
|
|
|
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/smoke.sh" || log "smoke-тест с замечаниями"
|
|
log "обновление завершено: ${TARGET}"
|