Files
admin/.wiki/concepts/snolla-admin-appdata-acl-500-after-scp-migration.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

5.8 KiB
Raw Blame History

title: MoreThenCms admin (RUVDS) — App_Data RX-only после scp-миграции → HTTP 500 на любой записи (delete/upload) status: fixed 2026-07-03 (Modify выдан на весь App_Data) tags: [cms, snolla, morethencms, iis, ruvds, acl, permissions, migration, assets, 500] related: galleries-storage-class-local-not-s3, ../entities/ruvds-iis-host, ../sources/iis-migration-to-ruvds-2026-05-23 updated: 2026-07-03

App_Data RX-only → 500 на записи из админки

Симптом

POST /admin/assets/<ownerId>/delete?path=/&filename=<file>HTTP 500. В IIS-логе (C:\inetpub\logs\LogFiles\W3SVC1\, время в UTC; сервер MSK=UTC+3) — sc-status 500 sc-substatus 0 sc-win32-status 0 = чистое managed-исключение, не IIS-уровень. В Windows Application Event Log пусто, файловых логов CMS нет → ASP.NET глотает исключение default-handler'ом. GET того же URL → 404 (delete только [HttpPost]).

Root cause — ACL, не код и не MinIO

App pool snolla = ApplicationPoolIdentity → процесс бежит как IIS AppPool\snolla. После scp-миграции 2026-05-23 bootstrap выдал этому аккаунту на дереве контента только (RX) (Read&Execute), без Modify:

C:\sites\snolla\App_Data   IIS APPPOOL\snolla:(OI)(CI)(RX)     ← только чтение
      ...\labtools-price.pdf IIS APPPOOL\snolla:(I)(RX)

Провайдер assets в <fileStorageClients> = MoreThenCms.FileStorage.Local.AssetsStorage (локальный диск, App_Data\assets\<ownerId:N>\<storageFilename>; basePath="") — см. galleries-storage-class-local-not-s3. Код-путь удаления: AssetsController.DeleteAssetsService.DeleteAsset (MoreThenCms/Assets/Services/AssetsService.cs:84): FileExists (RX-чтение ок → true) → DeleteFile = File.Delete под identity с RX → UnauthorizedAccessException → необработанное → 500. DB-delete (строкой ниже) даже не достигается. RX не содержит право DELETE, и на родителе нет DC (delete-child) → удалять нечем. BUILTIN\Users:(AD)(WD) не спасает — виртуальный аккаунт пула в IIS_IUSRS, не в Users; и AD/WD — создание, не удаление.

Дифдиагностика (чем исключены NRE-версии): в БД mssql.kzntsv.site подтверждены обе строки — Folders (root-папка owner'а, Path='/', Discriminator=AssetsFolder) и Files (StorageClient='assets', StorageFilename=<file>), поэтому GetFolderByPath(...).Id и asset.Folder не-null, выполнение доходит именно до File.Delete. Единственная падающая операция — физическое удаление.

Класс проблемы шире delete: RX-only убивает ВСЕ Local-записи из админки — upload ассетов, contentCache/uploadCache/imageCache, галереи, watermarks. Всё это классы Local в App_Data.

Fix (применён 2026-07-03)

# на RUVDS IIS (80.64.31.36), от Administrator
icacls "C:\sites\snolla\App_Data" /grant "IIS AppPool\snolla:(OI)(CI)(M)" /T /C

(M)=Modify (включает DELETE+WRITE), (OI)(CI)=наследование на файлы+подпапки, /T=протянуть на существующие. Результат: 44293 файла, 0 ошибок. Проверка: на целевом файле теперь IIS APPPOOL\snolla:(I)(M). Рестарт пула не нужен — ACL применяется на лету. Живой delete-тест намеренно НЕ гонялся (удалил бы реальный ассет); доказательство = ACL на точном таргете + протрассированный код-путь.

Split-brain: админка ≠ боевой сайт

Админка MoreThenCms живёт на RUVDS IIS и читает/пишет локальный App_Data. Боевой snolla-app (labtools.ru и др. на ../entities/vds-kzntsv) отдаёт ассеты/галереи из MinIO (minio.kzntsv.site = books-vds, bucket assets/<ownerId>/<file>), см. galleries-storage-class-local-not-s3. Классы мигрированы в S3 (галереи 12.06, assets 13.06), но админка на S3 не переключена → любая правка ассета через админку меняет только локалку IIS и НЕ отражается на боевом сайте (и наоборот). Пока админка не repointed на S3 — правки зеркалить руками в оба места.

Пример (2026-07-03): замена labtools-price.pdf (ownerId d375c419…) — новый файл залит и в MinIO (mc cp --attr Content-Type=application/pdf … snm/assets/d375c419…/labtools-price.pdf, ETag→6426ddd0…) и на локальный диск IIS (scp, MD5 сверен). Оба слоя = байт-в-байт с исходником.

TODO (настоящее закрытие split-brain)

Переключить админский <fileStorageClients>-класс assetsgalleries и пр.) на S3-провайдер, указывающий на minio.kzntsv.site — тогда админка и боевой app работают с одним хранилищем, ручное зеркалирование и ACL на App_Data перестают быть нужны. Это код/конфиг-таска на стороне MoreThenCms.