# OTA: что обновление может менять в системе Изначально OTA задумывалась как замена только приложения (бинарник, веб, коллектор). На практике `bt-update` выполняется **от root** и уже меняет системные файлы: хелперы, sudoers, юниты systemd, конфиги systemd. Здесь описано, что именно он делает, в каком порядке и как добавить новую системную правку. ## Как запускается 1. Веб (пользователь `buttontask`) принимает пакет и вызывает `sudo -n /opt/buttontask/scripts/bt-update stage `. Это разрешено правилом в `/etc/sudoers.d/buttontask`. 2. `bt-update` перезапускает сам себя через `systemd-run` в отдельном временном юните `buttontask-update-`. Поэтому он переживает перезапуск `buttontask-web` посреди обновления. 3. Прогресс пишется в `run/update-status.json`, подробный лог в `run/update.log`. ## Порядок `stage` | Шаг | Что делается | Куда пишет | |---|---|---| | 1. распаковка | пакет → `versions/`, проверка `manifest.json` | `/opt/buttontask/versions/` | | 2. `sync_helpers` | все `webconfig/scripts/bt-*` → root-owned хелперы; sudoers ставится только если прошёл `visudo -c` | `/opt/buttontask/scripts/`, `/etc/sudoers.d/buttontask` | | 3. коллектор | `buttontask-collector.service`, enable/disable по `collectorEnabled` | `/etc/systemd/system/` | | 4. bluetooth | drop-in `Restart=always` для `bluetooth.service` | `/etc/systemd/system/bluetooth.service.d/override.conf` | | 5. `sync_system` | `buttontask.service`, `buttontask-displaywatch.service`, аппаратный вотчдог; `daemon-reload` или `daemon-reexec`, enable/restart displaywatch | `/etc/systemd/system/`, `/etc/systemd/system.conf.d/` | | 6. переключение | `current` → новая версия, перезапуск сервисов | | | 7. health-check | `/healthz`, свежий `run/qt.alive`, `buttontask` active (30 с) | | | 8. откат | при провале `current` → предыдущая версия, перезапуск | | Подкоманды для ручного запуска: ```sh sudo /opt/buttontask/scripts/bt-update sync-helpers # шаг 2 из текущей версии sudo /opt/buttontask/scripts/bt-update sync-system # шаг 5 из текущей версии ``` ## Важные ограничения ### 1. OTA выполняет **старый** `bt-update` Обновление запускает `bt-update`, который уже установлен на устройстве, а не тот, что лежит в пакете. Новый `bt-update` приезжает на шаге 2 и работает только **со следующей** OTA. Значит, системную правку, добавленную в `bt-update`, первая OTA не применит. Как это обойти (сделано для вотчдога): веб при каждом старте вызывает `sudo bt-update sync-system` (`sync_system_units()` в `webconfig/system_info.py`). На шаге 6 веб перезапускается уже из новой версии, вызывает новый `bt-update` (его установил шаг 2), и правка применяется в ту же OTA. Поэтому `sync-system` должен быть **идемпотентным**: без изменений он ничего не делает (`install_if_changed` + `cmp`). ### 2. Системные правки **не откатываются** Шаги 2–5 выполняются до health-check, и откат возвращает только симлинк `current`. Юниты, sudoers и конфиги остаются от новой версии. Отсюда правило: **любая системная правка должна работать и со старыми версиями приложения.** Пример: `buttontask.service` не задаёт `WatchdogSec=`, таймаут включает сам бинарник через `WATCHDOG_USEC`. Иначе старые версии без пингов убивались бы каждые 30 секунд. ### 3. Изменённый юнит не применяется к уже запущенному процессу `daemon-reload` обновляет юнит, но переменные окружения (например, `NOTIFY_SOCKET`) процесс получает только при старте. Если юнит поменялся после перезапуска на шаге 6 (это случай из пункта 1), новые настройки заработают со следующего рестарта сервиса или перезагрузки. ### 4. Чего OTA не умеет - **apt/deb-пакеты.** Для них нужен полный deploy-бандл (`winDeployScripts/`, `device-install.sh`). - **Произвольные одноразовые скрипты-миграции.** Отдельного механизма нет: каждая правка вписывается в `bt-update` руками (см. ниже). - **Перезагрузку** после установки. Если она нужна, это ручной шаг. ## Как добавить новую системную правку 1. Положите файл в пакет, в `webconfig/…` (всё из `webconfig/` попадает в OTA через `make-package.sh`). 2. В `bt-update` в `sync_system` добавьте `install_if_changed ` и нужный `reload`/`reexec`/`enable`. Не добавляйте новый шаг прямо в `cmd_stage`: тогда правка не применится при первой OTA (пункт 1). 3. Проверьте, что правка совместима со старыми версиями приложения (пункт 2). 4. Повторите то же в `winDeployScripts/device-install.sh` для чистой установки. Если добавили новый хелпер `bt-*`, впишите его в списки в `device-install.sh` и `make-adb-bundle.ps1`. 5. Новые типы файлов (`*.conf` и т.п.) пропишите в `.gitattributes` с `eol=lf`. ## Безопасность Пакет OTA фактически исполняется от root: хелперы, sudoers и юниты из него ставятся без подписи. От подмены защищают только пароль веб-конфигуратора и (необязательная) сверка sha256 при загрузке. Доступ к вкладке «Обновление» равен root-доступу к устройству.