feat(admin): manage server updates and local configuration
ci / api / api (push) Successful in 52s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m9s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m35s
release / release (версия и заметки) (push) Successful in 5s
release / android (APK в релиз) (push) Successful in 4m6s
ci / db / db (push) Successful in 1m15s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m19s
ci / ts / ts (packages + web) (push) Successful in 2m34s
release / desktop (Linux и Windows в релиз) (push) Successful in 14m27s
release / prune (старые файлы и прогоны) (push) Successful in 6s

This commit is contained in:
mrleo1nid committed 2026-10-22 23:01:36 +03:00
1 parent e33abc948c
commit a29a8b18ad
49 files changed
+3604 -353

No files matched your search

+1
View File
@@ -24,6 +24,7 @@ Pipu Music — self-hosted музыкальный сервис (веб + Android
| [i18n.md](i18n.md) | Локализация (ru / en, расширяемость) |
| [install-guide.md](install-guide.md) | **Пошагово:** установка сервера на домен с HTTPS, подключение веба и Android |
| [admin-guide.md](admin-guide.md) | **Администратору:** пользователи, хранилища, очередь, волна, обновления, диагностика |
| [server-management.md](server-management.md) | Управление обновлениями и config.local из админки, установка агента |
| [deployment.md](deployment.md) | Справочник по развёртыванию: сервисы, каталоги, переменные |
## Стек в одном абзаце
+5
View File
@@ -133,3 +133,8 @@ APK, Linux (`.deb`) и Windows (NSIS) прикладываются к релиз
| Сервис перезапускается по кругу | `docker compose logs <сервис>`; часто — закончилось место на диске |
Остальное — [install-guide.md](install-guide.md#12-если-что-то-не-работает).
## Управление обновлениями и конфигурацией
Разделы **Обновления** и **Конфигурация** используют агент на хосте. Установка для существующего сервера, права, приоритет `.env` над `config.local` и диагностика описаны в [server-management.md](server-management.md).
+3
View File
@@ -97,3 +97,6 @@
делает **единственный** параллельный refresh (single-flight) и повторяет запросы.
- Роутинг-гарды: `must_change_credentials` → `/setup/admin`; `must_change_password` → `/setup/password`;
админские разделы — по `role`.
Управление обновлениями сервера — право `manages_updates`: у admin всегда, другим его выдаёт и отзывает только admin. Оно даёт доступ к `/admin/updates`, управлению источниками и запуску обновления, но не к конфигурации сервера. `/admin/config` доступен только admin. Подробности: [server-management.md](server-management.md).
+127
View File
@@ -0,0 +1,127 @@
# Управление сервером из веб-интерфейса
В меню админки доступны **Обновления** (`/admin/updates`) и **Конфигурация**
(`/admin/config`). Клиентские APK и desktop-сборки по-прежнему раздаются через
существующий механизм `appupdate`; источники обновления сервера от него независимы.
## Установка на существующий сервер
После получения версии с управлением сервером выполните на Linux-хосте:
```bash
cd /opt/pipu-music/deploy
sudo bash ./install-management.sh
./update.sh main # либо тег версии, содержащей эту возможность
```
Новая установка через `sudo ./install.sh` устанавливает агент автоматически.
Нужны systemd, Python **3.10+**, Git, Bash, `flock` (util-linux) и Docker Compose
**2.24+**. Compose должен поддерживать несколько `--env-file` и тег `!reset`
из существующего TLS-overlay. Агент выполняется от root, чтобы запускать Compose
и обращаться к данным развёртывания; API продолжает работать без root и без Docker socket.
Скрипт создаёт `pipu-management.service`, копирует агент вне Git-checkout в
`/usr/local/lib/pipu/server-agent.py`, создаёт `deploy/config.local` и общий каталог
`${PIPU_DATA}/management` с владельцем UID 65532. Последний монтируется только в API.
Приватные настройки источников, состояние, аудит и журналы лежат в
`/var/lib/pipu-management`, доступном только root. Нужен доступ этого пользователя
к origin; SSH-ключи и known_hosts для приватных репозиториев настройте на хосте.
Пароли и токены в URL источников не принимаются.
После успешного обновления агент автоматически заменяет свою установленную копию
из нового checkout и перезапускается, сохранив итоговый статус. Для ручной установки
нового кода можно повторно запустить `install-management.sh`.
Во время выполняющейся операции не перезапускайте его: systemd остановит дочерние
процессы. После прерывания/перезагрузки задача помечается ошибкой, а не успехом.
## Права
Администратор всегда может управлять обновлениями. В меню действий пользователя
на странице **Пользователи** он может выдать и забрать право **Управление
обновлениями** (`manages_updates`). Право действует независимо от роли и проверяется
на сервере при каждом запросе. Оно позволяет изменять источники, видеть журнал
и запускать обновление. Пользователь с этим правом получает ссылку на обновления,
но не получает доступ к пользователям, конфигурации или остальным действиям админа.
Выдавайте это право доверенным операторам: обновление запускает код выбранного
совместимого репозитория на хосте. Только администраторы могут просматривать,
сохранять и применять конфигурацию. Выдача/отзыв права записываются в `audit_log`;
операции агента с UUID инициатора — в его приватный `audit.jsonl` без значений секретов.
## Обновления
При первом обращении автоматически добавляется текущий `git remote origin`.
Можно создавать, редактировать и удалять источники; хотя бы один должен остаться.
Поддерживаются совместимые Git-репозитории Pipu через HTTP(S) и SSH.
* **Последний релиз** — значение по умолчанию: максимальный стабильный тег SemVer
`vMAJOR.MINOR.PATCH` (также допускается без `v`), без `-rc.N`.
* **Выбрать версию** — конкретный релизный тег, включая release candidate.
* **main** — текущий commit ветки main.
Обновления устанавливаются только по нажатию кнопки и после подтверждения.
Перед запуском агент повторно читает refs и фиксирует SHA; update.sh проверяет,
что полученный commit совпадает. Выбранный источник не перезаписывает origin
и не смешивает его теги с тегами другого репозитория. Git checkout с локальными
изменениями отклоняется. Защита update.sh от downgrade сохраняется: откат
выполняется вручную с `PIPU_ALLOW_DOWNGRADE=1` после проверки совместимости БД.
Выполнение, ограниченный хвост журнала и итоговый статус доступны на странице.
Можно закрыть браузер или переждать перезапуск API: работа продолжается на хосте.
Полные логи остаются приватными; для интерфейса известные секреты маскируются.
Одновременно агент допускает только одну операцию обновления/применения.
Резервная копия и откат схемы БД автоматически не выполняются.
## Конфигурация
Реестр поддерживаемых параметров находится в `deploy/config.schema.json`:
API, общие параметры сервисов, рекомендатель и развёртывание. Добавляя параметр
в конфигурацию сервиса, обновите реестр; для рекомендателя/агента хранилища также
проверьте передачу через Compose. Пути томов, сгенерированный DATABASE_URL и
некоторые служебные параметры показаны для просмотра и меняются на хосте.
Страница не является произвольным редактором nginx/Caddy/YAML-файлов.
Приоритет при запуске через скрипты:
1. Явные переменные окружения Compose и значения из `deploy/.env`.
2. `deploy/config.local`.
3. Встроенные значения по умолчанию.
Для интерполяции Compose скрипты передают `--env-file config.local --env-file .env`.
У API порядок `env_file: [config.local, .env]`; рекомендатель и storage-agent получают
только необходимые им переменные через `environment`. При ручном запуске Compose
сохраняйте эти флаги, иначе параметры интерполяции из config.local не подхватятся.
Страница показывает ожидаемое значение после применения, а не утверждает, что
работающий процесс уже перечитал сохранённый файл. Окружение shell запуска Compose
тоже может перекрывать интерполяцию; для агента используется окружение systemd.
В интерфейсе видны локальное значение, значение из `.env` и источник приоритета.
Если ключ уже есть в `.env`, изменение его в config.local сохраняется, но не
перекрывает `.env` — интерфейс прямо сообщает об этом. Чтобы управлять таким ключом
через страницу, удалите его строку из `.env` на хосте. Секреты не возвращаются в API
открытым текстом: поле без изменений сохраняет прежний секрет, ввод заменяет,
**Сбросить локальное** удаляет только значение из config.local.
Сохранение атомарно, с правами 0600 и проверкой ревизии: устаревшая форма не затрёт
правки другого администратора. Перед сохранением проверяются типы и Compose;
при ошибке прежний файл восстанавливается. Произвольные ключи, переводы строк
и изменение служебных параметров отклоняются. Сохраняемые значения трактуются
буквально: подстановки shell не выполняются.
Кнопка **Применить и перезапустить** отдельно подтверждает пересоздание контейнеров.
Агент запускает `apply-config.sh`, ждёт `/readyz` и сохраняет результат. Если сервисы
не стали готовы, состояние — ошибка; исправьте config.local или восстановите его
на хосте. Автоматического отката конфигурации после неудачного применения нет.
Диагностика:
```bash
sudo systemctl status pipu-management.service
sudo journalctl -u pipu-management.service -n 100
cd /opt/pipu-music/deploy
docker compose --env-file config.local --env-file .env logs api
```
Проверки разработки: `python3 -m unittest discover -s deploy -p 'test_*.py'`,
`go test ./internal/auth ./internal/management` из `services/api`, а также
`pnpm --filter @pipu/web test:e2e e2e/server-management.spec.ts`.