292 lines
9.6 KiB
Markdown
292 lines
9.6 KiB
Markdown
# План интеграции AstraDeploy и бота (FSM + callback API)
|
||
|
||
## Цели
|
||
|
||
Сделать наблюдаемую, устойчивую и воспроизводимую установку через бота с поэтапными статусами.
|
||
|
||
Скрипт уже умеет отдавать:
|
||
- `started`
|
||
- `step`
|
||
- `success`
|
||
- `failed`
|
||
|
||
Нужно оборачивать это в `FSM`-движок на бэкенде бота.
|
||
|
||
## 1. Точка входа callback
|
||
|
||
### Endpoint
|
||
- `POST /astra-deploy/report`
|
||
- Заголовок: `Authorization: Bearer <report-token>`
|
||
- Content-Type: `application/json`
|
||
|
||
### Тело (из скрипта)
|
||
```json
|
||
{
|
||
"status": "step",
|
||
"core": "paper",
|
||
"dir": "/opt/minecraft/paper",
|
||
"port": 25565,
|
||
"protocol": "tcp",
|
||
"service": "tmux-systemd",
|
||
"message": "Installing base packages",
|
||
"step": "preflight_packages",
|
||
"step_index": 14,
|
||
"step_total": 80,
|
||
"step_percent": 17
|
||
}
|
||
```
|
||
|
||
### Рекомендуемый расширенный payload (бот-раннер может добавить)
|
||
```json
|
||
{
|
||
"request_id": "uuid",
|
||
"job_id": "job_123",
|
||
"user_id": "123",
|
||
"locale": "ru"
|
||
}
|
||
```
|
||
|
||
### Ответ
|
||
- `200/204` с `{ "ok": true }` или пустым телом.
|
||
- Идемпотентность по `(request_id, status, step, step_index, step_total, ts_sec)` или аналогичной паре.
|
||
|
||
## 2. Запуск задачи из бота
|
||
|
||
Ключевые параметры запускаемого процесса:
|
||
- `--core ...`
|
||
- `--dir ...`
|
||
- `--port ...`
|
||
- `--service systemd|tmux-systemd|screen|none`
|
||
- `--user ...`
|
||
- `--firewall yes|no`
|
||
- `--yes`
|
||
- `--accept-license yes` (обязательно в автоматическом)
|
||
- `--accept-eula yes` для Java-ядер
|
||
- `--report-url ...`
|
||
- `--report-token ...`
|
||
- `--locale ru|en` (или `LANGUAGE`/`LANG`)
|
||
- `--dry-run`, `--update`, `--force-clean`, `--backup-existing`, `--allow-existing`
|
||
- `--build`, `--mc-version` для `nethergamesmc`
|
||
|
||
## 3. FSM состояния
|
||
|
||
### Состояния
|
||
- `QUEUED`
|
||
- `RUNNING`
|
||
- `VALIDATION`
|
||
- `PREPARE_ENV`
|
||
- `CORE_INSTALL`
|
||
- `POST_INSTALL`
|
||
- `WAITING_INPUT`
|
||
- `ROLLBACK`
|
||
- `DONE`
|
||
- `FAILED`
|
||
- `DRY_RUN`
|
||
- `STALLED` (таймаут между шагами)
|
||
|
||
### Переходы
|
||
- `started` -> `RUNNING`
|
||
- `step(parse_complete|prepare_defaults|preflight_*)` -> `VALIDATION`
|
||
- `step(preflight_packages|preflight_java|preflight_user|preflight_directory)` -> `PREPARE_ENV`
|
||
- `step(install_core|deploy_core|update_core|core_*)` -> `CORE_INSTALL`
|
||
- `step(core_post|core_service|service_*|finalize)` -> `POST_INSTALL`
|
||
- `status=success` -> `DONE`
|
||
- `status=failed` -> `FAILED`
|
||
- `--dry-run` (локально определено) -> `DRY_RUN`
|
||
- долгий таймаут без новых step -> `STALLED`
|
||
- interactive без автоматических флагов и требующие ответа -> `WAITING_INPUT`
|
||
|
||
### Идёмпотентная обработка
|
||
- Игнорировать дубликаты последнего шага в том же `request_id`.
|
||
- Обновлять состояние только если новый `step_index` выше предыдущего или статус изменился на более поздний.
|
||
|
||
## 4. Полная карта `step`
|
||
|
||
### Общая фаза и предзапуск
|
||
- `parse_complete`
|
||
- `prepare_defaults`
|
||
- `preflight_start`
|
||
- `install_start`
|
||
- `finalize`
|
||
- `core_runtime`
|
||
- `core_install`
|
||
- `core_update`
|
||
|
||
### Предпроверки
|
||
- `preflight_begin`
|
||
- `preflight_validate_root`
|
||
- `preflight_detect`
|
||
- `preflight_detect_os`
|
||
- `preflight_validate_support`
|
||
- `preflight_update_mode_check`
|
||
- `preflight_validate_plan`
|
||
- `preflight_validate_licenses`
|
||
- `preflight_validate_port`
|
||
- `preflight_directory`
|
||
- `preflight_packages`
|
||
- `preflight_java`
|
||
- `preflight_user`
|
||
|
||
### Установка/обновление ядер
|
||
- `core_resolve_channel`
|
||
- `core_resolve_download`
|
||
- `core_fetch`
|
||
- `core_render`
|
||
- `core_configure`
|
||
- `core_post`
|
||
- `core_service`
|
||
- `core_chown`
|
||
- `core_backup`
|
||
- `core_update_done`
|
||
- `core_phpbuild_resolve`
|
||
- `core_phpbuild_fetch`
|
||
- `core_composer`
|
||
- `core_repo_clone`
|
||
- `core_install`
|
||
- `install_core`
|
||
- `deploy_core`
|
||
- `update_core`
|
||
|
||
### Системные шаги
|
||
- `packages_start`
|
||
- `packages_dry_run`
|
||
- `packages_index`
|
||
- `download_start`
|
||
- `download_completed`
|
||
- `download_swap`
|
||
- `firewall_start`
|
||
- `firewall_done`
|
||
- `firewall_manual`
|
||
- `java_install`
|
||
- `render_start_script`
|
||
- `chmod_start_script`
|
||
- `service_stop`
|
||
- `service_create`
|
||
- `service_reload_enable`
|
||
- `service_start`
|
||
- `user_create`
|
||
- `user_exists`
|
||
- `prepare_dir`
|
||
- `permission_fix`
|
||
|
||
## 5. Маппинг на UX-сообщения (ru/en)
|
||
|
||
### RU
|
||
- `preflight_*` → «Подготовка окружения и проверок»
|
||
- `preflight_packages` / `packages_*` → «Установка базовых пакетов»
|
||
- `core_*` → «Установка и настройка ядра»
|
||
- `service_*`, `core_service` → «Настройка автозапуска»
|
||
- `core_chown` / `prepare_dir` / `permission_fix` → «Настройка доступа»
|
||
- `success` → «Установка завершена»
|
||
- `failed` → «Ошибка установки»
|
||
|
||
### EN
|
||
- `preflight_*` → `Environment preflight`
|
||
- `core_*` → `Core installation`
|
||
- `service_*` → `Service setup`
|
||
- `failed` → `Deployment failed`
|
||
|
||
## 6. Edge-cases по сценариям запуска
|
||
|
||
- **Interactive (без `--yes`)**
|
||
- может остановиться на подтверждении лицензии/ЕULA/директории
|
||
- статус `WAITING_INPUT`
|
||
- **`--easy`**
|
||
- обычный процесс, добавляется план-сводка до preflight
|
||
- **`--update`**
|
||
- `step_total` уменьшается на 6, проверяется существующая непустая директория
|
||
- **`--dry-run`**
|
||
- физически без изменений, callback может отсутствовать (как реализовано сейчас)
|
||
- **`--force-clean`**
|
||
- удаление содержимого директории перед установкой
|
||
- **`--backup-existing`**
|
||
- резервная копия `*.backup-<timestamp>`
|
||
- **`--allow-existing`**
|
||
- пропуск проверки непустой директории
|
||
- **Неправильный `core` / OS**
|
||
- жёсткий fail с объяснением
|
||
- **Порт занят**
|
||
- fail с деталями `tcp/udp` и предложением сменить порт
|
||
- **Сбой callback API**
|
||
- для скрипта не фатальный; бот не должен переводить задачу в `FAILED` из-за 5xx webhook-а
|
||
|
||
## 7. Rollback и пост-факту
|
||
|
||
На фатальной ошибке скрипт делает:
|
||
- лог ошибки
|
||
- попытку удаления созданного сервиса (если был создан)
|
||
- сообщение с путём лога (`/var/log/astra-deploy/...`)
|
||
- завершение с кодом ошибки
|
||
|
||
Для бота:
|
||
- статусы -> `ROLLBACK` (внутренний подстейт)
|
||
- показать пользователю:
|
||
- возможная причина
|
||
- путь лога
|
||
- безопасный список ручных действий
|
||
|
||
## 8. Минимальная модель хранения
|
||
|
||
### `jobs`
|
||
- `id`
|
||
- `user_id`
|
||
- `core`, `dir`, `port`, `service`, `locale`
|
||
- `fsm_state`
|
||
- `status`
|
||
- `percent`
|
||
- `step`, `step_index`, `step_total`, `message`
|
||
- `request_id`, `report_token_id`, `process_pid`
|
||
- `created_at`, `updated_at`
|
||
|
||
### `job_events`
|
||
- `job_id`
|
||
- `status`, `step`, `step_index`, `step_total`, `step_percent`
|
||
- `message`
|
||
- `raw_payload` (json)
|
||
- `created_at`
|
||
|
||
## 9. Шаблоны уведомлений
|
||
|
||
### Telegram (RU)
|
||
1) Запуск: `🚀 Установка AstraDeploy запущена`
|
||
2) Шаг: `⚙️ {percent}% | {state} | {step}`
|
||
3) Успех: `✅ Установка завершена`
|
||
4) Ошибка: `❌ Установка завершена с ошибкой`
|
||
|
||
### Telegram (EN)
|
||
1) `🚀 AstraDeploy started`
|
||
2) `⚙️ {percent}% | {state} | {step}`
|
||
3) `✅ Installation completed`
|
||
4) `❌ Installation failed`
|
||
|
||
Кнопки:
|
||
- `Получить статус`
|
||
- `Логи`
|
||
- `Запустить проверку`
|
||
- `Повторить (dry-run)`
|
||
|
||
## 10. Безопасность
|
||
|
||
- Токены webhook не логировать.
|
||
- Проверять `Authorization` строго.
|
||
- Проверка whitelist по разрешённым `step`.
|
||
- Rate limit на report endpoint.
|
||
- Защищённое хранение токенов (vault/secret/env).
|
||
|
||
## 11. Проверочный набор для интеграции
|
||
|
||
- `paper` non-interactive, валидные флаги
|
||
- `paper` без `--accept-eula` и с `--yes` -> `failed`
|
||
- `nethergamesmc --dry-run` -> без изменений, шаги в локальном логе
|
||
- занятый порт -> `failed`
|
||
- `--update` на пустой директории -> `failed`
|
||
- `--force-clean` на непустой директории -> success после очистки
|
||
- callback 5xx -> установка продолжается, без ложного FAILED в UI
|
||
|
||
## 12. Что отдаёт разработчику бота на старте
|
||
|
||
- список поддерживаемых `core`: `pmmp,paper,purpur,velocity,powernukkitx,nethergamesmc`
|
||
- поддерживаемые режимы сервиса: `systemd`, `tmux-systemd`, `screen`, `none`
|
||
- список ключевых шагов из этого плана выше
|
||
- статусные правила и fallback-поведение для отсутствующего callback
|