Files
ayurishchevandClaude Opus 5.5 5f7bd6588a Состояния «Upgrade FW» и осознанный откат прошивки RouterBOARD
Пункт 18 ревью 2026-09-28 21:32 (docs/changes/027): после отката ROS
плата остаётся на более новой прошивке, а приложение сравнивало версии
на неравенство и показывало откат как обновление.
- devices.fw_state: unknown/update/downgrade/current; has_fw_update и
  фильтры не считают откат обновлением; метка «в ROS: X».
- upgrade_firmware не понижает прошивку; общая запись — _flash_firmware.
- Задача fw_downgrade: проверка → обязательный бэкап → запись →
  перезагрузка; API POST /devices/{id}/firmware/downgrade и
  /batch/fw_downgrade (target_version обязателен).
- UI: «Откатить прошивку…» (строка и группа), общее окно отката с kind.

Тесты: 39 из 39. Стенд: временное недоступное устройство — 422/202,
задачи failed на проверке, бэкапов нет. Реальная запись прошивки при
откате и ручная проверка UI не выполнялись.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 00:04:51 +03:00

37 lines
4.5 KiB
Markdown

# Итог: состояния «Upgrade FW» и осознанный откат прошивки RouterBOARD (изменение 027)
План: [`plan.md`](plan.md). Закрывает п. 18 ревью [2026-09-28 21:32](../../reviews/2026-09-28-2132-codebase-review.md): после отката ROS
прошивка платы больше не выдаётся за «обновление», штатное обновление FW её не понижает, откат прошивки — отдельное осознанное действие.
## Что сделано
| Файл | Изменение |
|---|---|
| `app/services/devices.py` | `fw_state(st)`: `unknown` / `update` / `downgrade` / `current` (по `version_newer`); `has_fw_update` = `fw_state == "update"` — фильтры `updates=fw\|any\|none` не считают откат обновлением |
| `app/ros/operations.py` | запись и ожидание `FW_DONE_MSG` вынесены в `_flash_firmware`; `upgrade_firmware` при плате новее встроенной в ROS не пишет и возвращает «обновление не требуется»; `check_fw_downgrade`, `downgrade_firmware` — по образцу `check_downgrade`/`downgrade_ros` |
| `app/services/ops.py`, `jobs.py` | задача `fw_downgrade` (`run_fw_downgrade`): проверка → обязательный бэкап → повторная проверка и запись |
| `app/api/v1.py` | `POST /devices/{id}/firmware/downgrade`, `POST /batch/fw_downgrade` (обязательный `target_version`; до `/batch/{action}`) |
| `app/ui/routes.py`, `_dialog_downgrade.html` | одно окно отката на оба вида: словарь `DOWNGRADE_KINDS` (`ros`/`fw`), параметр `kind` (по умолчанию `ros` — прежние адреса), неизвестный `kind` → 400 |
| `_devices.html`, `dashboard.html`, `_jobs.html` | метка «в ROS: X», пункты «Откатить прошивку…» (строка, только в состоянии `downgrade`) и «Откатить прошивку до версии ROS…» (группа), подпись «Откат FW» |
| `tests/test_devices.py`, `tests/test_operations.py` | состояния `fw_state`; отказ `upgrade_firmware` понижать; порядок `backup → upgrade → reboot`, несовпадение версии — без бэкапа и записи; 422 без `target_version` |
| `README.md`, отчёт ревью | таблица состояний «Upgrade FW», раздел об откате, API, 39 тестов, строка 027; п. 18 — ✅ 027 |
## Найдено и исправлено в ходе цикла
Дефектов на ревью диффа не найдено, возвратов исполнителю не было.
## Проверки
- `pytest`: 39 из 39 (новых 3).
- Стенд (8001, пересоздан): в контейнере новый код (`def fw_state`, `fw_downgrade`, `kind=fw` в шаблонах).
- Временное недоступное устройство `192.0.2.1`: без `target_version` — 422 на обоих эндпоинтах; с версией — 202; обе задачи `fw_downgrade` —
`failed` на проверке (ConnectTimeout), бэкапов нет. Устройство удалено (204).
- Реальные устройства: у всех RouterBOARD `fw_current = fw_upgrade` — «актуально»; CHR — «—».
## Не проверено
- **Реальная запись прошивки при откате** не выполнялась. Не подтверждено, что RouterOS при записи более старой прошивки пишет в журнал тот же
`FW_DONE_MSG`. Если текст другой — задача через 180 с завершится ошибкой без перезагрузки (прошивка, вероятно, записана и применится
при следующей перезагрузке).
- Ручная проверка UI пользователем на момент коммита не подтверждена.
## Эксплуатация
- Если на устройстве включён `/system/routerboard/settings auto-upgrade=yes`, RouterOS сама записывает встроенную прошивку при загрузке —
состояние «в ROS: X» после отката ROS может не возникнуть.