Files
admin/.tasks/morethencms-s3-filestorage-provider.md
vitya 2e5adcf11e deploy(cms-s3): S3 FileStorage provider LIVE on RUVDS — admin↔MinIO split-brain closed
Разбор 500 на /admin/assets/<owner>/delete → корень ACL (app pool RX-only на
App_Data после scp-миграции) → полная развязка хранилища CMS:

- S3 FileStorage провайдер (MoreThenCms.FileStorage.S3) построен (координация с
  интерн-сессией) и раскатан LIVE на прод RUVDS: 6 контентных классов web.config
  → S3/MinIO, кэши остались Local. Смок 7 тенантов 200/301, 0×500, S3-read byte-parity.
  Upload-гоча: UseChunkEncoding=false (MinIO ⊥ AWSSDK aws-chunked).
- Весь локальный контент RUVDS → MinIO (galleries 5.3G, themes 2.7G, maxMind);
  imageCache-блоат (2.1G) выпилен из бакета themes.
- stostayer.old определён как stale-копия (не мигрировать).

Новый concept: snolla-admin-appdata-acl-500-after-scp-migration.
Трекеры: morethencms-s3-filestorage-provider (LIVE), reconcile-local-assets-to-minio (done).
Rollback: web.config.bak-pre-s3-2026-07-03 на хосте.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 13:47:21 +03:00

7.4 KiB
Raw Permalink Blame History

[morethencms-s3-filestorage-provider] — S3-провайдер FileStorage для MoreThenCms (MinIO)

Status: 🟢 LIVE на прод RUVDS (2026-07-03). Split-brain закрыт: боевой catch-all C:\sites\snolla теперь читает/пишет ассеты/темы/галереи из MinIO. Локальный IIS (windows-recovery-host) — отложен до ухода сайтов с RUVDS (решение user).

Прод-cutover RUVDS (2026-07-03)

  • Backup: web.config.bak-pre-s3-2026-07-03 + IIS-снапшот pre-s3-cutover-2026-07-03. Rollback = restore + recycle (Local вернётся, MinIO не трогается).
  • 3 DLL (S3+AWSSDK.*) → C:\sites\snolla\bin. web.config <fileStorageClients>: 6 контентных классов (assets/galleries/images/scripts/stylesheets/watermarks) → S3, креды в конфиге (ACL SYSTEM+Admins); кэши (imageCache/uploadCache/contentCache/_imageCache-Azure) оставлены Local. Правка — точечный regex, UTF-8/BOM сохранён, XML валиден (10 записей).
  • Pre-flight: RUVDS→minio.kzntsv.site:443 = TCP+HTTPS 200. Egress ок.
  • Smoke GREEN: 7 тенантов 200/301 (0× 500); S3-read вживую — theme CSS 16ba5cb8…/css/lato.css → 200/9239b/text/css, byte-parity с MinIO. Write-механика — self-test цикл (ранее).
  • imageCache-прун бакета themes (2.1 ГБ мусора) — фоном bfb8wy94n. Валидация (standalone-проба, IIS/elevation не нужны): Read/key/byte-parity + full self-test put→exists→download(MD5==)→delete→exists=false после upload-фикса. Upload-фикс: UseChunkEncoding=false в PutObjectRequest (MinIO отвергает AWSSDK 3.7 aws-chunked STREAMING-AWS4-HMAC-SHA256-PAYLOAD; DisablePayloadSigning НЕ помогает). 17/17 юнитов + интеграция. _selftest/-мусора нет.

Метод валидации (важно — IIS/elevation НЕ нужны)

Провайдер чистый (AWSSDK + базовый FileStorageClient, без SnollaHost/Autofac) → грузится standalone в PowerShell: загрузить 3 DLL из deploy/ + зависимости из C:\sites\stostayer.old\bin (резолвер с guard от рекурсии), инстанцировать AssetsStorage через $type::new($cfgDict), гонять против real MinIO. Проба: scratchpad s3-provider-probe.ps1 + s3-upload-diag.ps1. stostayer.old НЕ трогается (только его DLL читаются в чужой процесс). Self-test пишет в throwaway assets/_selftest/ (чистится). Owner-split: код — прогер (проект MoreThenCms); координация + deploy + приёмка — admin (я).

Ключ-конвенция (ground-truthed 2026-07-03, финал)

Провайдер = калька с Local (не Azure — Azure в бою не гонялся), ключи по snolla-фронту packages/core/lib/services/storage.js (key = ownerId.toLowerCase()+'/'+storageFilename).

  • assets: bucket assets, ключ <ownerId:N>/<file> — ownerId без дефисов (админка отдаёт ToString("N"), объекты в MinIO без дефисов). НЕ вставлять дефисы.
  • themes (css/images/js/watermarks): единый bucket themes, ключ <themeId:N>/{css,images,js,watermarks}/<file>. scripts=js (не /scripts!). watermarks НЕ отдельный бакет — они в App_Data\themes\<themeId>\watermarks\ (Local WatermarksStorage), 11 файлов вкл. tandemmebel.ru.
  • galleries: bucket galleries, ключ <siteId:N>/<file> плоско (без /images).
  • Azure separator-баг (prefix+fileUri без /) прогер поймал → Trim('/')+"/"+fileUri.
  • Configuration net461→net462 (OpeItcLoc03/MoreThenCms.Configuration 3e79ff2) — build-only, на прод НЕ едет (шипим только 3 DLL).
  • Приёмка на локальном IIS: key-parity + byte-parity sweep (ключ совпал с существующими + MD5==).

Зачем

Админка MoreThenCms пишет ассеты на локальный диск IIS (App_Data, провайдер FileStorage.Local), а боевой фронт snolla читает из MinIO → split-brain (правка в админке не видна на сайте). Плюс отдельный симптом — 500 на delete из-за RX-only ACL (пофикшен 2026-07-03 выдачей Modify, но это лечит только delete, не устраняет раздвоение). Настоящее закрытие — посадить админку на тот же MinIO через S3-провайдер, которого в кодовой базе нет (есть только Local и Azure).

Решения (приняты)

  • Новая сборка MoreThenCms.FileStorage.S3 — калька с MoreThenCms.FileStorage.Azure, backend AWSSDK.S3 против MinIO (ForcePathStyle=true).
  • Объём: все контентные классы (Assets/Galleries/Images/Scripts/Stylesheets/Watermarks). Кэши (image/upload/content) остаются Local.
  • Один MinIO на всех: minio.kzntsv.site (books-vds, 89.253.255.133), path-style. Bucket = имя класса, ключ = <prefix>/<file> без ведущего слэша (parity с уже мигрированными объектами).
  • Deploy target админки: локальный IIS на windows-recovery-host (репрпоуз PC; серверная роль была декоммишнута, сам PC жив). DNS-аудит 2026-07-03: инфра-хосты *.kzntsv.site резолвятся в реальные IP, перехвата 127.0.0.1 НЕТ — костыль в конфиг не нужен.

Where I stopped

ТЗ (полное, под новичка, с таблицей префиксов и выделенной граблей «ведущий слэш в ключе S3») лежит в ~/projects/MoreThenCms/.claude-inbox/2026-07-03T06-40-09Z-admin.md.

Next action

Дождаться MoreThenCms.FileStorage.S3.dll от прогера → развернуть на локальный IIS (windows-recovery-host) → сквозняк: upload из админки → объект в MinIO с корректным ключом+Content-Type → фронт через imgproxy отдаёт 200 → byte-parity (ETag/MD5). Затем deploy на боевой + переключить <fileStorageClients> секцию, секреты прокинуть из окружения (не хардкод).

Пайплайн

ТЗ → сборка (прогер) → deploy-local → сквозняк-приёмка → deploy-remote → close split-brain.

Контекст

  • .wiki/concepts/snolla-admin-appdata-acl-500-after-scp-migration.md (500 + split-brain + fix)
  • .wiki/concepts/galleries-storage-class-local-not-s3.md (Local-класс, миграция в S3, префиксы)
  • Абстракция: MoreThenCms/FileStorage/FileStorageClient.cs + Azure/AzureCloudStorage.cs (образец)

Branch: n/a (admin ops + external code)