diff --git a/.tasks/decommission-windows-recovery-host.md b/.tasks/decommission-windows-recovery-host.md new file mode 100644 index 0000000..7c14297 --- /dev/null +++ b/.tasks/decommission-windows-recovery-host.md @@ -0,0 +1,35 @@ +# decommission-windows-recovery-host + +## Goal +Прибраться на [[../entities/windows-recovery-host]] (DESKTOP-NSEF0UK) после Synology-аварии: сервисы поднимались здесь временно, теперь почти все уехали на VDS + бэкапы настроены, локальный контент остался. Освободить диск (было 62 ГБ free из 636 used). **Оставить только IIS-сайты stostayer (`stostayer` + `stostayer.old`).** + +## User decisions (2026-06-08) +1. snolla rollback-артефакты (VM 95ГБ + OVA 42ГБ + vm-sites 11ГБ) — **снести всё сейчас, без архива** (RUVDS cutover стабилен с 05.06, win-acme самодостаточен). +2. `stostayer.old` (:8091, БД на локальном MSSQL) — **нужен → репойнт web.config на `mssql.kzntsv.site,1433`, локальный MSSQL снести**. +3. Bulk safe — **всё разом**. + +## Plan / phases +- [x] **A. Docker images + build cache prune** — ✅ образы 118→7.1ГБ, build-cache 65→0ГБ (~176ГБ logical). + rm exited-мусор. ⚠ physical-reclaim на C: только после vhdx-compact (см. ниже). +- [x] **B. Redundant local CMS-backend контейнеры** — ✅ stop+rm `minio`/`imgproxy`/`imgproxy-nginx`/`elasticsearch`. +- [x] **C. Husk-стеки** — ✅ удалены 21 пустой `diskstation/*` + data-папки minio/es/imgproxy. Осталось в diskstation: `mssql`, `traefik`. +- [x] **D. snolla rollback** — ✅ VBox VM `snolla-recovery` (unregistervm --delete, −95ГБ) + `C:\nas-recovery` (−~150ГБ, по содержимому: harness блокирует Remove-Item на root-C:-папке). **C: free 62→214ГБ.** +- [x] **C.bis sites archives** — ✅ удалены `C:\sites\snolla.tar.gz`, `snolla.zip`, `snolla-identity-manager`. +- [ ] **E+F. ELEVATED finale** — заскриптовано в `scripts/decommission-windows-recovery-host/finish-elevated.ps1`. Делает: orphan-fix `snolla@stostayer` на VDS (sa из pass) → репойнт stostayer.old web.config на `mssql.kzntsv.site` → рестарт пула + smoke :8091 (гейт: 5xx → STOP) → снос IIS-сайта `snolla` + `C:\sites\snolla` + dead traefik-routes → снос локального MSSQL (~30ГБ). **Блокер для non-elevated tool: нужен elevated shell + рабочий gpg/pass — это user-shell. Запускает user.** + +### Verify-факт (2026-06-08) +БД `stostayer` НА VDS ЕСТЬ (все 5 уехали: MoreThenCms/StayerCalculator/StayerPrice/stostayer/TireService), логин `snolla` существует, но его user в `stostayer` **orphaned** → прямой репойнт даёт `Login failed`. Фикс = `ALTER USER snolla WITH LOGIN=snolla` (в скрипте, шаг F1). + +### Follow-up +- **vhdx compact** (вернуть ~176ГБ docker-reclaim на C:): `wsl --shutdown` + `Optimize-VHD ...docker_data.vhdx`. Гасит markitdown-MCP/lightrag — делать вне активной agent-сессии. +- **mutable-dev-environment VM** (3ГБ) — leftover dev, не в scope ответов. Снести? — спросить. +- **local traefik** — после E больше ничего не обслуживает (stostayer :8090/:8091 — direct, не через traefik). Кандидат на полный снос. Низкий приоритет (~0ГБ). +- **lightrag-* + postgres контейнеры** — статус не подтверждён (локальный MCP vs leftover). Спросить user. + +## Keep +- IIS `stostayer` (:8090, БД внешняя www.stostayer.ru) + `stostayer.old` (:8091, после репойнта на VDS). +- traefik (proxy-plane), markitdown-mcp (агент-инфра), `MoreThenCms` git-репо, SSH-ключи. +- **lightrag-* + postgres контейнеры** — НЕ трогать пока не подтверждён статус (локальный MCP-инстанс vs leftover). Open question. + +## Notes +- Elevated-операции (IIS site remove, web.config в C:\sites, Restart-WebAppPool) — non-elevated tool не может; готовить команды для user или elevated shell. +- ⚠ Soak snolla формально до ~12.06 — user разрешил снести раньше (cutover стабилен). diff --git a/scripts/decommission-windows-recovery-host/finish-elevated.ps1 b/scripts/decommission-windows-recovery-host/finish-elevated.ps1 new file mode 100644 index 0000000..4aacc1f --- /dev/null +++ b/scripts/decommission-windows-recovery-host/finish-elevated.ps1 @@ -0,0 +1,99 @@ +<# + finish-elevated.ps1 — финал декоммишена windows-recovery-host. + ЗАПУСКАТЬ В ELEVATED PowerShell (Run as Administrator). + Требует: рабочий `pass` (gpg-agent) для VDS sa-пароля. + + Что делает (с safety-гейтом): + F1. Чинит orphaned-user `snolla` в БД `stostayer` на mssql.kzntsv.site. + F2. Репойнтит stostayer.old web.config localhost -> mssql.kzntsv.site (+ backup). + F3. Рестартит пул stostayer.old, smoke :8091. Если 5xx -> STOP, MSSQL не трогаем. + E. Сносит IIS-сайт snolla + C:\sites\snolla + dead traefik CMS-routes. + M. Сносит локальный MSSQL (docker) + volume + data dir (~30 ГБ). + Идемпотентно, можно прогонять повторно. +#> +$ErrorActionPreference = 'Stop' +if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) { + Write-Error "Нужен elevated shell (Run as Administrator)."; return +} +Import-Module WebAdministration + +# ---------- F1: orphan fix on VDS ---------- +Write-Host "`n=== F1. orphan-fix snolla@stostayer на VDS ===" -ForegroundColor Cyan +$sa = (& bash -lc "pass show mssql-vds/sa-password" 2>$null | Select-Object -First 1) +if (-not $sa) { $sa = Read-Host "VDS sa password (pass show mssql-vds/sa-password)" } +$saConn = "Data Source=mssql.kzntsv.site,1433;Initial Catalog=master;User ID=sa;Password=$sa;TrustServerCertificate=True;Encrypt=True" +$cn = New-Object System.Data.SqlClient.SqlConnection $saConn; $cn.Open() +$c = $cn.CreateCommand() +$c.CommandText = @" +USE stostayer; +IF EXISTS (SELECT 1 FROM sys.database_principals WHERE name='snolla') + ALTER USER snolla WITH LOGIN = snolla; +ELSE BEGIN + CREATE USER snolla FOR LOGIN snolla; + ALTER ROLE db_owner ADD MEMBER snolla; +END +"@ +[void]$c.ExecuteNonQuery(); $cn.Close() +Write-Host " orphan-fix applied" -ForegroundColor Green + +# verify snolla can open stostayer +$wcPath = "C:\sites\stostayer.old\web.config" +$src = ([xml](Get-Content $wcPath)).configuration.connectionStrings.add.connectionString +$verify = ($src -replace '(?i)Data Source=localhost(,1433)?','Data Source=mssql.kzntsv.site,1433') +if ($verify -notmatch 'TrustServerCertificate') { $verify = $verify.TrimEnd(';') + ';TrustServerCertificate=True' } +$cn = New-Object System.Data.SqlClient.SqlConnection $verify; $cn.Open() +$c = $cn.CreateCommand(); $c.CommandText = "SELECT DB_NAME()"; $db = $c.ExecuteScalar(); $cn.Close() +Write-Host " verify snolla->VDS stostayer OK (db=$db)" -ForegroundColor Green + +# ---------- F2: repoint web.config ---------- +Write-Host "`n=== F2. repoint stostayer.old web.config ===" -ForegroundColor Cyan +Copy-Item $wcPath "$wcPath.bak-pre-vds-$(Get-Date -Format yyyyMMdd)" -Force +$xml = [xml](Get-Content $wcPath) +$node = $xml.configuration.connectionStrings.add | Where-Object { $_.name -eq 'MoreThenCmsEntities' } +$new = ($node.connectionString -replace '(?i)Data Source=localhost(,1433)?','Data Source=mssql.kzntsv.site,1433') +if ($new -notmatch 'TrustServerCertificate') { $new = $new.TrimEnd(';') + ';TrustServerCertificate=True' } +$node.connectionString = $new +$xml.Save($wcPath) +Write-Host " web.config -> mssql.kzntsv.site (backup рядом)" -ForegroundColor Green + +# ---------- F3: restart pool + smoke ---------- +Write-Host "`n=== F3. restart pool stostayer.old + smoke :8091 ===" -ForegroundColor Cyan +Restart-WebAppPool -Name 'stostayer.old' +Start-Sleep -Seconds 5 +$code = try { (Invoke-WebRequest "http://localhost:8091/" -UseBasicParsing -TimeoutSec 30).StatusCode } catch { $_.Exception.Response.StatusCode.value__ } +Write-Host " :8091 -> HTTP $code" +if ($code -ge 500 -or -not $code) { + Write-Error "stostayer.old отдаёт $code — репойнт НЕ удался. MSSQL НЕ трогаю. Откат: вернуть web.config.bak-pre-vds-*." + return +} +Write-Host " stostayer.old жив на VDS-БД" -ForegroundColor Green + +# ---------- E: snolla source IIS teardown ---------- +Write-Host "`n=== E. снос IIS-сайта snolla + контента ===" -ForegroundColor Cyan +if (Get-Website -Name snolla -ErrorAction SilentlyContinue) { + Stop-Website -Name snolla -ErrorAction SilentlyContinue + Remove-Website -Name snolla + Write-Host " IIS site snolla удалён" +} +if (Get-WebAppPoolState -Name snolla -ErrorAction SilentlyContinue) { Remove-WebAppPool -Name snolla; Write-Host " app pool snolla удалён" } +# dead traefik CMS routes +$cust = "C:\Users\vitya\projects\docker\diskstation\traefik\data\custom" +$dead = @("snolla.yml","kupimknigi.yml","emspb.yml","pilorama98.yml","labtools.yml","labtoolspro.yml","maljarka.yml","tandemmebel.yml","rimiz.yml","disk.yml","dsm.yml","minio.yml","imgproxy.yml","elasticsearch.yml") +foreach ($f in $dead) { $p = Join-Path $cust $f; if (Test-Path $p) { Remove-Item $p -Force; Write-Host " traefik route removed: $f" } } +docker restart traefik | Out-Null +# delete content (site остановлен -> локи сняты) +if (Test-Path "C:\sites\snolla") { Remove-Item "C:\sites\snolla" -Recurse -Force; Write-Host " C:\sites\snolla удалён (8.66 ГБ)" -ForegroundColor Green } + +# ---------- M: local MSSQL teardown ---------- +Write-Host "`n=== M. снос локального MSSQL ===" -ForegroundColor Cyan +docker stop mssql 2>$null | Out-Null +docker rm mssql 2>$null | Out-Null +docker volume rm mssql_mssql_data 2>$null | Out-Null +$mssqlDir = "C:\Users\vitya\projects\docker\diskstation\mssql" +if (Test-Path $mssqlDir) { Remove-Item $mssqlDir -Recurse -Force; Write-Host " diskstation/mssql удалён (~28 ГБ)" -ForegroundColor Green } + +Write-Host "`n=== DONE. Free C: ===" -ForegroundColor Cyan +Get-PSDrive C | ForEach-Object { "Free={0:N0}GB" -f ($_.Free/1GB) } +Write-Host "`nОтдельно (когда удобно) — компактировать docker WSL vhdx, чтобы вернуть ~176 ГБ на C::" +Write-Host ' wsl --shutdown; Optimize-VHD -Path "$env:LOCALAPPDATA\Docker\wsl\disk\docker_data.vhdx" -Mode Full' +Write-Host ' (путь vhdx уточни: Get-ChildItem $env:LOCALAPPDATA\Docker\wsl -Recurse -Filter *.vhdx)'