firewall guard: барьер покоя fail-closed и явный контракт транзиентного таймера
Барьер, обязанный ДОКАЗАТЬ отсутствие асинхронного исполнителя, в трёх местах принимал за доказательство отсутствие наблюдения. - отказ `systemctl` больше не выдаётся за отсутствие guard: вместо `return []` введён единый наблюдатель inspectRollbackGuard с исходами quiescent/pending/ unknown и отдельным типом отказа GuardStateUnknownError; - покой перечисляется белым списком (inactive, failed): maintenance, refreshing и любое незнакомое состояние systemd блокируют операцию; - у транзиентного таймера явно заданы AccuracySec=1s (умолчание 1min превращало обещанные 45 секунд в 45-105) и RemainAfterElapse=no; барьер дополнительно опознаёт SubState=elapsed у *.timer как покой; - команда взведения строится чистой buildArmGuardArgv и выполняется новым runMutatingArgv без shell, поэтому её контракт проверяется значением, а не грепом по исходнику; - status перестал листить guard-юниты своей копией кода: без --plain, с `|| true` и с трактовкой failed как «вооружён» отчёт вечно противоречил барьеру. Добавлены rollback_guard_state и firewall_state=guard_unknown; - purge-v0.sh пропускал failed-юниты из-за маркера в первой колонке. Барьер покрыт поведенческими тестами через подставляемый SystemdUnitProbe: прежние проверки грепом по тексту функции пережили инверсию смысла - строка `return [];` была на месте, а решение стало неверным. Документация (README, docs/07, 11, 12, 13, 14, CHANGELOG) приведена к реальному окну 45-46 секунд и к новому тексту отказа. Отдельно исправлен комментарий PNPM_AUDIT_LEVEL в versions.env: гейт давно проверяет весь lock-граф.
This commit is contained in:
@@ -201,7 +201,7 @@ operation lock … exists but is not a valid HY2XS lock record
|
||||
|
||||
```text
|
||||
previous HY2XS operation is no longer running, but its firewall rollback guard
|
||||
is still armed: hy2xs-fw-rollback-<op-id>.timer (active)
|
||||
is still armed: hy2xs-fw-rollback-<op-id>.timer (active/waiting)
|
||||
```
|
||||
|
||||
Предыдущая операция умерла аварийно **после** применения firewall. Её процесса
|
||||
@@ -211,18 +211,50 @@ systemd, и он переживает свой процесс. Если нача
|
||||
операции.
|
||||
|
||||
Ничего делать не нужно, кроме как подождать: окно guard — 45 секунд с момента
|
||||
применения firewall.
|
||||
применения firewall плюс точность таймера (`AccuracySec=1s`), то есть не больше
|
||||
46 секунд.
|
||||
|
||||
```bash
|
||||
# сколько ещё ждать и что именно висит
|
||||
systemctl list-units --all 'hy2xs-fw-rollback-*'
|
||||
systemctl list-units --all --plain 'hy2xs-fw-rollback-*'
|
||||
hy2xs-orchestrator status --package-dir /usr/local/lib/hy2xs/package
|
||||
```
|
||||
|
||||
Когда guard сработает, юнит перестанет быть `active`, и операция пройдёт.
|
||||
Состояние `failed` у него покою не мешает: оно означает, что откат отработал
|
||||
не полностью, и это как раз повод запустить `repair`, а не ждать дальше —
|
||||
подробности в `journalctl -u 'hy2xs-fw-rollback-*'`.
|
||||
`--plain` здесь не для красоты: у юнита в состоянии `failed` systemctl печатает
|
||||
первой колонкой маркер `●`, и без флага его легко не заметить в списке.
|
||||
|
||||
Когда guard сработает, отработавший таймер выгрузится (`RemainAfterElapse=no`),
|
||||
и операция пройдёт. Состояние `failed` у сервиса покою не мешает: оно означает,
|
||||
что откат отработал не полностью, и это как раз повод запустить `repair`, а не
|
||||
ждать дальше — подробности в `journalctl -u 'hy2xs-fw-rollback-*'`. Такой
|
||||
`failed`-юнит остаётся загруженным до `systemctl reset-failed`, но операцию не
|
||||
блокирует.
|
||||
|
||||
### Операция отказывает: состояние guard'а не удалось выяснить
|
||||
|
||||
```text
|
||||
unable to verify firewall rollback guard state; systemd query failed,
|
||||
refusing to start a lifecycle operation: systemctl list-units failed: …
|
||||
```
|
||||
|
||||
Это **не** «guard вооружён», и ждать здесь нечего. Барьер обязан доказать, что у
|
||||
предыдущей операции не осталось исполнителей, способных изменить firewall;
|
||||
`systemctl` не ответил, доказательства нет, и операция отказывает до первой
|
||||
мутации.
|
||||
|
||||
Отсутствие ответа не равно отсутствию guard'а: systemd мог быть жив, а взведённый
|
||||
таймер — существовать. Разрешить операцию в этой ситуации означало бы допустить
|
||||
срабатывание старого таймера поверх новой операции.
|
||||
|
||||
```bash
|
||||
systemctl status
|
||||
systemctl list-units --all --plain 'hy2xs-fw-rollback-*'
|
||||
journalctl -u 'hy2xs-fw-rollback-*' --no-pager
|
||||
```
|
||||
|
||||
Разбирайтесь с systemd/D-Bus и повторяйте операцию. Отдельно ускорять ничего не
|
||||
нужно: `systemd-run` требуется в preflight, поэтому без работающего systemd
|
||||
операция всё равно не прошла бы — барьер лишь сообщает об этом раньше и точнее.
|
||||
|
||||
### Установка отказала с `firewall_guard_fired`
|
||||
|
||||
@@ -237,8 +269,8 @@ phase: firewall_guard_fired
|
||||
даже если smoke успел сойтись, — иначе сервер считался бы настроенным с чужими
|
||||
правилами, что особенно дорого при смене порта Hysteria, SSH или ACME.
|
||||
|
||||
Окно guard — 45 секунд, и оно не обязано покрывать smoke. Причину ищите в том,
|
||||
почему проход в него не уложился:
|
||||
Окно guard — 45 секунд (плюс точность таймера, `AccuracySec=1s`), и оно не
|
||||
обязано покрывать smoke. Причину ищите в том, почему проход в него не уложился:
|
||||
|
||||
```bash
|
||||
journalctl -u 'hy2xs-fw-rollback-*' --no-pager
|
||||
|
||||
Reference in New Issue
Block a user