fix(storage-agent): write nothing but the music files to the mounted storage
ci / api / api (push) Successful in 50s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Failing after 10s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Failing after 31m43s
ci / db / db (push) Failing after 19s
ci / api / api (push) Successful in 50s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Failing after 10s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Failing after 31m43s
ci / db / db (push) Failing after 19s
- Imported tracks are created directly under their final name with O_EXCL (never overwriting; " (2)" on conflict), fsync'ed and checked against SHA-256 — no hidden .pipu-tmp file next to them any more. - On any failure the agent removes its own partial file and the empty directories it created for it. - The write check uses access(W_OK) and the read-only mount flag instead of creating and deleting .pipu-write-test in the storage root. - Tests assert the storage tree holds only audio files after successful and failed writes and after the write check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6ad49fe0e3
commit
85fceaa686
6 files changed
+116
-56
No files matched your search
@@ -35,8 +35,7 @@
|
||||
`fsync`, сверка SHA-256, атомарный `rename`. Перезапись существующих файлов и удаление запрещены на уровне кода агента.
|
||||
- Права на NFS-сервере: экспорт должен разрешать запись для UID/GID агента (`PIPU_FILE_UID` / `PIPU_FILE_GID`,
|
||||
задаются в `.env` под владельца музыки на файловом сервере); новые файлы — `0644`, каталоги — `0755`.
|
||||
- `POST /admin/sources/{id}/test` для такого источника дополнительно проверяет запись: создаёт и удаляет
|
||||
`.pipu-write-test` в корне.
|
||||
- `POST /admin/sources/{id}/test` для такого источника дополнительно проверяет право записи — без создания файлов.
|
||||
- У источника задаётся `write_template` — шаблон пути для новых файлов, с автоподбором по существующей структуре
|
||||
и проверкой обратимости через регэкспы источника (подробно — [uploads.md](uploads.md#7-раскладка-в-хранилище-как-принято-на-сервере)).
|
||||
|
||||
@@ -44,8 +43,11 @@
|
||||
- Агент: `POST /internal/files` `{source_id, local_path?, rel_path, staging_path, sha256}` → `{rel_path, size, renamed}`;
|
||||
`POST /internal/files/test` — проверка записи. NFS с `accepts_uploads` монтируется rw в `/library-rw/<id>` (каталог
|
||||
внутри контейнера агента), а в `/library/<id>` — bind этой точки с `remount,ro`. Local-источники пишутся через
|
||||
`/library-host-rw` (тот же `LIBRARY_HOST`, на запись — только у агента). Итоговое имя создаётся жёсткой ссылкой
|
||||
на временный файл (`link` не перезаписывает, в отличие от `rename`); занято — ` (2)`, ` (3)`…
|
||||
`/library-host-rw` (тот же `LIBRARY_HOST`, на запись — только у агента). На музыкальный диск не пишется ничего,
|
||||
кроме самих треков: файл создаётся сразу под итоговым именем (`O_EXCL` — существующий не перезаписывается;
|
||||
занято — ` (2)`, ` (3)`…), `fsync`, сверка SHA-256; при ошибке агент удаляет свой недописанный файл и созданные
|
||||
для него пустые каталоги. Проверка записи — `access(W_OK)` и флаг read-only файловой системы, без пробного файла.
|
||||
Остальные сервисы видят музыку только на чтение (`read_only` в compose).
|
||||
Владелец новых файлов и каталогов — `PIPU_FILE_UID` / `PIPU_FILE_GID` (`-1` — не менять).
|
||||
- Шаблон: `meta.ParseTemplate` / `Render` (очистка имён, пределы длины), `meta.SuggestTemplate` (регэксп → шаблон через
|
||||
`regexp/syntax`: именованные группы → поля, `(?:(?P<disc>\d)-)?` → `{disc:1-}`, необязательная группа → `[ ]`,
|
||||
|
||||
Reference in new issue
Block a user