#!/usr/bin/env sh set -eu # Установка HY2XS состоит из двух строго разделённых фаз. # # PHASE 0 — READ ONLY (этот файл, целиком) # проверка прав, целостности пакета и чистоты хоста. # Ни один persistent path не изменяется. # # PHASE 1 — MUTATION (оркестратор, `hy2xs-orchestrator install`) # раскладка самого оркестратора, runtime-пакета и вся установка. # # Инвариант: у мутации ровно ОДИН владелец. # # Раньше PHASE 1 начиналась здесь: install.sh сам создавал /usr/local/lib/hy2xs, # ставил туда бинарник, вешал symlink и копировал runtime-пакет, и только потом # запускал оркестратор. Между этими двумя действиями оркестратор выполнял # собственный preflight. Если он отказывал — сменился DNS, занялся порт, # истёк таймаут резолвера, — у оркестратора ни один ownership-флаг не был # взведён, отказ классифицировался как `fatal_pre_apply`, и пользователь читал # «на сервере ничего не изменено». Хост при этом уже нёс каталог оркестратора, # symlink и runtime-пакет, а следующий запуск упирался в них как в маркеры # чужой установки. # # Отследить владение мутацией нельзя, пока мутируют двое. Поэтому здесь не # осталось ни одной изменяющей команды: shell только проверяет и передаёт # управление через exec. Сборка проверяет это структурно (tools/build/lib/verify.sh). PACKAGE_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" ORCHESTRATOR="$PACKAGE_DIR/orchestrator/hy2xs-orchestrator" 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 "$@" 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 --- # # Всё, что ниже, выполняет оркестратор: он ставит себя в /usr/local/lib/hy2xs, # раскладывает runtime-пакет и продолжает установку — уже под собственным # учётом владения и с собственным rollback. log "package directory: $PACKAGE_DIR" log "handing the mutating phase over to the orchestrator" exec "$ORCHESTRATOR" install --package-dir "$PACKAGE_DIR" "$@"