Files
HY2XS_flamy/package/install.sh
T
founder 2b4a2cb2d5 fix(install): двухфазная установка, clean-host контракт и проверка поколения
Установщик мог повредить работающий сервер до того, как откажется его
трогать: install.sh переписывал /usr/local/lib/hy2xs, раскладывал
runtime-пакет и перезаписывал install-state.json, и только потом
запускал clean-host preflight. При ошибочном запуске поверх старой
установки rollback дополнительно делал stop и disable для работающих
hysteria-server и hy2xs-admin.

Установка разделена на две фазы с жёсткой границей:

  PHASE 0 - read only: права, checksums пакета, clean-host preflight
            из распакованного архива (новая команда preflight-install)
  PHASE 1 - mutation: раскладка оркестратора и сама установка

Граница держится не соглашением, а read-only guard: под ним writeText,
writeTextAtomic и мутирующие раннеры lib/process кидают ошибку.
Внутри install() preflight выполняется раньше первой записи состояния.

Остальное в этом же инварианте:

- clean-host контракт расширен с двух маркеров до четырнадцати, пути
  установки и данных берутся из конфигурации, а не захардкожены;
- отсутствие HY2XS_CONFIG_SCHEMA_VERSION трактуется как legacy, а не
  как текущая схема: до v1 этого поля не существовало. Тест,
  закреплявший прежнее поведение, инвертирован;
- install-state несёт идентификацию поколения (product, release_line,
  config_schema_version); reconfigure и repair проверяют её до всего
  остального, потому что installed: true мог остаться и от 0.x;
- repair требует явного --allow-partial-state;
- классификация отказа опирается на ownership-флаги, а не на текст
  ошибки: раньше сообщение со словом nftables приводило к откату
  чужого firewall. stop/disable выполняется только для юнитов,
  развёрнутых текущей операцией, а fatal_pre_apply не делает
  системного отката и не собирает diagnostics-бандл.
2026-08-27 12:14:47 +05:00

109 lines
3.9 KiB
Bash
Executable File

#!/usr/bin/env sh
set -eu
# Установка HY2XS состоит из двух строго разделённых фаз.
#
# PHASE 0 — READ ONLY
# проверка прав, целостности пакета и чистоты хоста.
# Ни один persistent path не изменяется, включая /usr/local/lib/hy2xs.
#
# PHASE 1 — MUTATION
# раскладка оркестратора и runtime-пакета, затем сама установка.
#
# Инвариант: до успешного завершения PHASE 0 установщик не имеет права
# изменить на сервере ничего. HY2XS v1 не устанавливается поверх 0.x и не
# мигрирует состояние, поэтому ошибочный запуск поверх работающего сервера
# обязан быть безвредным.
PACKAGE_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
ORCHESTRATOR="$PACKAGE_DIR/orchestrator/hy2xs-orchestrator"
ORCHESTRATOR_INSTALL_PATH="/usr/local/lib/hy2xs/hy2xs-orchestrator"
ORCHESTRATOR_SYMLINK="/usr/local/bin/hy2xs-orchestrator"
RUNTIME_PACKAGE_DIR="/usr/local/lib/hy2xs/package"
log() {
printf '[hy2xs-install] %s\n' "$*"
}
fail() {
printf '[hy2xs-install] ERROR: %s\n' "$*" >&2
exit 1
}
# ---------------------------------------------------------------- PHASE 0 ---
log "PHASE 0: read-only checks (no persistent path is modified)"
if [ "$(id -u)" != "0" ]; then
fail "HY2XS install must run as root."
fi
if [ ! -x "$ORCHESTRATOR" ]; then
fail "Missing executable orchestrator artifact: $ORCHESTRATOR"
fi
if [ ! -f "$PACKAGE_DIR/metadata/checksums.txt" ]; then
fail "Missing package checksums: $PACKAGE_DIR/metadata/checksums.txt"
fi
log "verifying package checksums"
(
cd "$PACKAGE_DIR"
sha256sum -c metadata/checksums.txt
)
# PHASE 0 принимает только источник конфигурации: флаги, влияющие на мутацию
# (--skip-*), к read-only проверке отношения не имеют.
PREFLIGHT_CONFIG=""
scan_config_argument() {
while [ "$#" -gt 0 ]; do
case "$1" in
--config)
[ "$#" -ge 2 ] || fail "Missing value for --config"
PREFLIGHT_CONFIG="$2"
shift 2
;;
*)
shift
;;
esac
done
}
scan_config_argument "$@"
# Bootstrap preflight запускается из РАСПАКОВАННОГО пакета: установленного
# оркестратора на этом этапе ещё не существует и появиться не должен.
log "running clean-host preflight from the unpacked package"
if [ -n "$PREFLIGHT_CONFIG" ]; then
"$ORCHESTRATOR" preflight-install --package-dir "$PACKAGE_DIR" --config "$PREFLIGHT_CONFIG" \
|| fail "clean-host preflight failed; the server was left untouched"
else
"$ORCHESTRATOR" preflight-install --package-dir "$PACKAGE_DIR" \
|| fail "clean-host preflight failed; the server was left untouched"
fi
log "PHASE 0 passed"
# ---------------------------------------------------------------- PHASE 1 ---
log "PHASE 1: applying changes"
install -d -m 0755 /usr/local/lib/hy2xs
install -m 0755 "$ORCHESTRATOR" "$ORCHESTRATOR_INSTALL_PATH"
ln -sf "$ORCHESTRATOR_INSTALL_PATH" "$ORCHESTRATOR_SYMLINK"
log "installing runtime package assets to: $RUNTIME_PACKAGE_DIR"
rm -rf "$RUNTIME_PACKAGE_DIR"
install -d -m 0755 "$RUNTIME_PACKAGE_DIR"
cp -a "$PACKAGE_DIR/config" "$RUNTIME_PACKAGE_DIR/"
cp -a "$PACKAGE_DIR/docs" "$RUNTIME_PACKAGE_DIR/"
cp -a "$PACKAGE_DIR/systemd" "$RUNTIME_PACKAGE_DIR/"
cp -a "$PACKAGE_DIR/templates" "$RUNTIME_PACKAGE_DIR/"
cp -a "$PACKAGE_DIR/metadata" "$RUNTIME_PACKAGE_DIR/"
cp -a "$PACKAGE_DIR/ui" "$RUNTIME_PACKAGE_DIR/"
cp -a "$PACKAGE_DIR/install.sh" "$RUNTIME_PACKAGE_DIR/"
log "package directory: $PACKAGE_DIR"
log "starting install-only orchestrator"
exec "$ORCHESTRATOR_INSTALL_PATH" install --package-dir "$RUNTIME_PACKAGE_DIR" "$@"