164 lines
15 KiB
Markdown
164 lines
15 KiB
Markdown
# Управление сервером из веб-интерфейса
|
||
|
||
В меню админки доступны **Обновления** (`/admin/updates`) и **Конфигурация**
|
||
(`/admin/config`). Клиентские APK и desktop-сборки по-прежнему раздаются через
|
||
существующий механизм `appupdate`; источники обновления сервера от него независимы.
|
||
|
||
## Установка на существующий сервер
|
||
|
||
Обычное обновление на Linux-хосте автоматически настраивает агент после
|
||
переключения на выбранную версию и до пересоздания контейнеров:
|
||
|
||
```bash
|
||
cd /opt/pipu-music/deploy
|
||
./update.sh main # либо тег версии, содержащей эту возможность
|
||
```
|
||
|
||
Если прав не хватает, установщик запросит sudo только для настройки системного
|
||
сервиса. Повторный запуск проверяет установку и запускает остановленный агент;
|
||
исправный агент с тем же кодом и unit-файлом не перезапускается. Ошибка установки
|
||
останавливает обновление до пересоздания контейнеров. При обновлении из админки
|
||
собственный агент остаётся запущенным и заменяет свою копию после успеха.
|
||
|
||
В версии **v1.9.0** вызов установщика из `update.sh` был пропущен. Если сервер уже
|
||
обновлён до неё, агент можно включить сразу без новой сборки:
|
||
|
||
```bash
|
||
cd /opt/pipu-music/deploy && sudo bash ./install-management.sh
|
||
```
|
||
|
||
Чтобы получить исправленный updater на checkout ветки main, один раз выполните
|
||
`git pull --ff-only` перед `./update.sh main`: старая временная копия updater,
|
||
запущенная до checkout, ещё не содержит нового шага настройки.
|
||
|
||
Новая установка через `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.
|
||
|
||
Кнопка установки появляется только если выбранный commit отличается от работающего
|
||
и переход не является откатом. Для `main` сравнивается SHA, для релиза — SHA тега.
|
||
Одинаковая версия, более новая установленная сборка, ошибка проверки и неопределённый
|
||
commit не предлагают установку. «Проверить обновления» обходит кэш refs.
|
||
Работающий API передаёт свою встроенную revision; для прежних сборок агент разрешает
|
||
hash из git-describe или локальный релизный тег. HEAD checkout и PIPU_VERSION в .env
|
||
не считаются доказательством установленного commit, поскольку сборка могла не удаться.
|
||
|
||
Обновления устанавливаются только по нажатию кнопки и после подтверждения.
|
||
Перед запуском агент повторно читает 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.
|
||
|
||
Маскирование охватывает `.env`, config.local, итоговое значение и значение по
|
||
умолчанию. URL со встроенными учётными данными, query-параметрами или фрагментом
|
||
целиком считается секретом. Поля замены изначально пусты; переключатель видимости
|
||
показывает только новый ввод. После сохранения поле снова очищается.
|
||
|
||
Сохранение атомарно, с правами 0600 и проверкой ревизии: устаревшая форма не затрёт
|
||
правки другого администратора. Перед сохранением проверяются типы и Compose;
|
||
при ошибке прежний файл восстанавливается. Произвольные ключи, переводы строк
|
||
и изменение служебных параметров отклоняются. Сохраняемые значения трактуются
|
||
буквально: подстановки shell не выполняются.
|
||
|
||
Панель сохранения появляется только при отличиях от исходных локальных значений.
|
||
После возврата прежних значений она исчезает. Сохранённые изменения, влияющие на
|
||
итоговую конфигурацию, показывают отдельное действие применения. Пустой config.local,
|
||
комментарии, явное значение по умолчанию или значение, перекрытое .env, сами по себе
|
||
не требуют перезапуска.
|
||
|
||
Кнопка **Применить и перезапустить** отдельно подтверждает пересоздание контейнеров.
|
||
Агент запускает `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`.
|