scripts(backup-notifications): unify push + email format across VDS/RUVDS/windows-host

3 host-pipelines (VDS bash, RUVDS+windows-host ps1) had drifted formats:
ntfy title `VDS backup OK $D` vs `RUVDS backup OK ($D)`, tags
`white_check_mark` vs `green_circle`, email subject `[VDS] backup OK` vs
`RUVDS backup -- SUCCESS`. Phone-side фильтрация и desktop reading
ломались за счёт inconsistency.

Unified to:
- ntfy push: title `<HOST> backup OK <date>`, body
  `<duration_human>, size=<>, snapshots=<>, dest=kreknin:<>`,
  tags `green_circle` (OK) / `red_circle` (FAILED).
- email: subject `[<HOST>] backup <STATUS> <date>` (STATUS=OK|FAILED),
  body — structured Date/Duration/Size/Snapshots/Source/Dest/Components/Log.
  Failure body extends with `Tail (last 40 lines)`.

Also imports VDS `run.sh` into repo as `scripts/vds-backup-rsync-kreknin/`
— closes drift из общего `scripts/<slug>/` pattern (RUVDS+windows-host
уже жили там; VDS жил только на /opt/stacks/backup/scripts/).

Deploy status:
- VDS: deployed via scp + sudo install, sha256=27b09ca272bb, smoke ntfy+email ✓
- RUVDS: deployed via scp + Move-Item, sha256=f3bb57a86af5, smoke ntfy+email ✓
- windows-host: deploy.ps1 + smoke-notify.ps1 готовы в scripts/, **pending
  elevated PS у user'а** (ACL=SYSTEM+Administrators, не пишется без UAC).

Spec + decisions + completed: .tasks/unify-backup-notifications.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 07:19:15 +03:00
parent 29724d410f
commit 73ad6dd06a
9 changed files with 610 additions and 35 deletions

39
.tasks/NEXT_SESSION.md Normal file
View File

@@ -0,0 +1,39 @@
---
_last_updated_: 2026-05-25T07:30:00+03:00
session_id: 2026-05-25-unify-backup-notifications
---
# Next session handoff
## Recent commits
- `scripts(backup-notifications): unify push + email format across VDS/RUVDS/windows-host` (этот раунд)
- `wiki(claude): add session-handoff trigger line`
- `wiki(ingest): RUVDS IIS migration + daily backup pipeline`
- `tasks(books-ssh-audit-shared-vds): close 🟢`
- `tasks(windows-host-fallback-backup-daily): close 🟢`
## Open треки
| Трек | Готовность | Entry-point |
|---|---|---|
| `unify-backup-notifications` 🟡 | 90% — 3 scripts edited, VDS+RUVDS deployed+smoke ✓, **windows-host deploy pending elevated PS** | `.tasks/unify-backup-notifications.md` + `scripts/windows-host-fallback-backup-daily/deploy.ps1` |
| `iis-migration-to-ruvds` 🟡 | soak (kupimknigi + emspb DNS flipped 2026-05-24) | `.tasks/iis-migration-to-ruvds.md` |
| `infra-inventory` ⚪ | ready, not started | `.tasks/infra-inventory.md` |
| `books-vds-bookva-bootstrap` 🔵 | blocked on victor/books tenant-split Phase 4 | `.tasks/books-vds-bookva-bootstrap.md` |
## Спроси user'а
- **Открывал ли elevated PowerShell и запустил `& .\scripts\windows-host-fallback-backup-daily\deploy.ps1`?** Это closes `unify-backup-notifications`.
- **Пришли ли TEST ntfy + email от VDS + RUVDS** (2 push'а с title `[TEST] <HOST> backup OK 2026-05-25`)? Format читается одинаково?
- **DNS swap для оставшихся 22 hostnames** (`iis-migration-to-ruvds` next-action #3) — продолжаем или ждём ещё soak'а?
## Не делать (preemptive guards)
- **Не push без grant'а** (project-discipline Rule 4 — session-start = ask-mode). Этот раунд commit'а — local-only пока user не разрешит push.
- **Не trigger полный backup-run для smoke** (21-81 min wall-clock). Smoke = только notify-channel через `smoke-notify.ps1`, не full pipeline.
- **Не оставлять windows-host deploy в подвешенном состоянии** — без deploy он сегодня ночью (03:00 MSK) пушнёт в STAROM формате, regression. После deploy → закрыть task `unify-backup-notifications`.
## Memory updates за сессию
- (нет на этом раунде)

View File

@@ -1,5 +1,20 @@
# Admin Task Board
_Updated: 2026-05-24 (`books-ssh-audit-shared-vds` 🟢 closed — audit clean: 1 retained vitya key, 0 revoked, removed cosmetic dead root key, sshd hardening verified via `sshd -T`. Doc в `.wiki/concepts/books-ssh-access.md`. Pre-cutover acceptance для tenant-split Phase 3 ✅. Earlier today: `windows-host-fallback-backup-daily` 🟢 closed (daily 03:00 MSK rclone SFTP windows-host → kreknin live, 23 GB / 4868 sec smoke #1). Все 3 host'а (windows + RUVDS + VDS) backup'ятся на kreknin sequentially за одну ночь. Current scope: IIS migration в soak (kupimknigi + emspb flipped, tandemmebel excluded), infra-inventory ready, остальные books-* awaits tenant-split Phase 3-4 design Direction.)_
_Updated: 2026-05-25 (`unify-backup-notifications` 🟡 paused — 3 scripts edited под единый push+email format; VDS+RUVDS deployed + smoke notify ✓; windows-host deploy pending elevated PS у user'а. VDS `run.sh` импортирован в repo как canonical source. Pre-existing: `books-ssh-audit-shared-vds` 🟢, `windows-host-fallback-backup-daily` 🟢, все 3 daily backups live на kreknin.)_
## 🟡 [unify-backup-notifications] — единый формат push + email для всех 3 backup-pipelines (VDS / RUVDS / windows-host)
**Status:** paused (pending windows-host elevated deploy)
**Where I stopped:** 2026-05-25 — 3 scripts edited + parser-check ✓. **VDS + RUVDS deployed + smoke notify ✓** (ntfy_ok + email_ok с TEST-prefix). **windows-host pending elevated deploy**`scripts/windows-host-fallback-backup-daily/deploy.ps1` готов, user запустит из elevated PS позже. Smoke на windows-host skipped по user-decision (доверяем parser-проверке).
**Next action:**
1. User: open elevated PowerShell, `cd C:\Users\vitya\projects\.admin`, `& .\scripts\windows-host-fallback-backup-daily\deploy.ps1`.
2. (Optional) `& .\scripts\windows-host-fallback-backup-daily\smoke-notify.ps1` — отправит TEST ntfy + email, verify format.
3. Verify первой ночью (2026-05-25 03:00 MSK windows-host → 04:30 RUVDS → 05:00 VDS) что push'и + email'ы пришли с единым форматом, нет regression.
4. Закрыть task.
**Branch:** master
<!-- created-by: vitya / 2026-05-25 / trigger: user-decision — unify backup notifications -->
<!-- paused: vitya / 2026-05-25 / pending windows-host elevated deploy -->
---
<!--
Status legend:

View File

@@ -0,0 +1,127 @@
# unify-backup-notifications
## Goal
Привести notification-формат всех 3 backup-pipelines (VDS, RUVDS, windows-host) к единому виду: **один формат для ntfy push** + **один формат для email**. Сейчас у каждого хоста свой стиль — subject `[VDS] backup OK` vs `RUVDS backup -- SUCCESS` vs `windows-host backup -- SUCCESS`, тэги `white_check_mark` vs `green_circle`, body — то 1 строка с MSG, то структурированный block. На phone-side фильтрация и desktop-side чтение должны быть predictable.
Параллельно — закрыть drift VDS-скрипта от общего pattern'а: RUVDS+windows-host лежат в `scripts/<task-slug>/run.ps1` локально, VDS жил только на remote (`/opt/stacks/backup/scripts/run.sh`). Импортирую как `scripts/vds-backup-rsync-kreknin/run.sh` (canonical source), правлю локально, deploy.
## Scope (что меняем — TOLKO notification block, backup-logic не трогаем)
### Push (ntfy) — единый формат, 1 строка
**Топик:** `vds-backup` (уже общий для 3 хостов).
**Tags:** `green_circle` (OK) / `red_circle` (FAILED).
**Priority:** `default` / `high`.
```
Title: <HOST> backup OK <date>
Body: <duration_human>, size=<size>, snapshots=<count>, dest=kreknin:<path>
Title: <HOST> backup FAILED <date>
Body: After <duration_human>: <error>. See <logpath>
```
Где `<HOST>` ∈ {`VDS`, `RUVDS`, `windows-host`}.
`<duration_human>` = `Xm YYs` (e.g. `21m07s`, `0m45s`).
### Email — единый формат, structured multi-line
**Subject:** `[<HOST>] backup <STATUS> <date>` где `STATUS` ∈ {`OK`, `FAILED`}.
**Body (success):**
```
<HOST> daily backup completed successfully.
Date: <date>
Duration: <duration_human>
Size: <size>
Snapshots: <count>
Source: <hostname> (<ip>)
Dest: kreknin:<path>
Components:
- <component 1>
- <component 2>
...
Log: <log-path>
```
**Body (failure):**
```
<HOST> daily backup FAILED.
Date: <date>
Duration: <duration_human>
Error: <error>
Source: <hostname> (<ip>)
Log: <log-path>
Tail (last 40 lines):
<tail>
```
## Key files
- `scripts/vds-backup-rsync-kreknin/run.sh` — bash, deployed to VDS `/opt/stacks/backup/scripts/run.sh`. Functions: `notify()` (ntfy), `email_send()` (msmtp). Callers — line 122-123 (success) + 49-53 (failure).
- `scripts/ruvds-backup-daily-kreknin/run.ps1` — PS1, deployed to RUVDS `C:\ProgramData\backup\run.ps1`. Functions: `Notify-Ntfy` + `Notify-Email`. Callers — line 140-161 (success) + 169-170 (failure).
- `scripts/windows-host-fallback-backup-daily/run.ps1` — PS1, deployed to windows-host `C:\ProgramData\backup\run.ps1`. Same function names. Callers — line 169-189 (success) + 197-198 (failure).
## Implementation steps
1. Edit VDS `run.sh`: добавить `[<HOST>] backup <STATUS> <date>` email-subject, structured body для success+failure, ntfy tags на `green_circle`/`red_circle`.
2. Edit RUVDS `run.ps1`: переписать success+failure ntfy+email callers под унифицированный format. Поменять subject на `[RUVDS] backup OK <date>` etc.
3. Edit windows-host `run.ps1`: same.
4. Deploy:
- windows-host: `Copy-Item scripts/windows-host-.../run.ps1 → C:\ProgramData\backup\run.ps1` (elevated; user может потребоваться UAC).
- RUVDS: `scp` to `C:\ProgramData\backup\run.ps1` через ssh-key.
- VDS: `scp` + `sudo install` to `/opt/stacks/backup/scripts/run.sh`.
5. Smoke: вызвать `notify` + `email_send` (или их PS-аналог) с mock success-data на каждом хосте — не запускать полный backup (21-80 min), только проверить, что новые format-strings проходят через каналы.
6. Verify user-side: phone ntfy app получил, gmail получил, форматы единые.
7. Commit + push.
## Acceptance
- [x] 3 scripts в `scripts/` имеют идентичный notification-block (modulo language: bash vs ps1).
- [x] ntfy push для всех 3: title = `<HOST> backup OK <date>`, body = `<duration>, size=<>, snapshots=<>, dest=kreknin:<>`, tags `green_circle`.
- [x] Email subject для всех 3: `[<HOST>] backup OK <date>`. Body — единый template.
- [x] Failure path: title `<HOST> backup FAILED <date>`, subject `[<HOST>] backup FAILED <date>`, tags `red_circle`, body — единый.
- [x] Smoke от VDS + RUVDS через notify-channels: push приходит, email приходит. (2026-05-25, см. completed steps)
- [ ] Smoke от windows-host — **deferred** (user-decision 2026-05-25: пропустить smoke, доверяем parser-проверке).
- [ ] **Deploy на windows-host pending** — user сделает elevated PS позже. До deploy'а windows-host остаётся на pre-unify формате.
- [ ] User-verify: phone ntfy уведомления — TEST из VDS + RUVDS пришли, format читается?
## Completed steps
- [x] **2026-05-25:** spec написана + STATUS.md обновлён, task 🔴 active.
- [x] **2026-05-25:** VDS `run.sh` импортирован из `vds.kzntsv.site:/opt/stacks/backup/scripts/run.sh` в `scripts/vds-backup-rsync-kreknin/run.sh` — closes drift из общего `scripts/<slug>/` pattern.
- [x] **2026-05-25:** 3 scripts edited: VDS bash + RUVDS ps1 + WHOST ps1. Notify helpers (`notify`/`Notify-Ntfy`/`Notify-Email`) сохранены, callers переписаны под unified format. Parser-check ✓ всех 3 (bash -n / `[Parser]::ParseFile`).
- [x] **2026-05-25:** VDS deployed: `scp /tmp/run.sh.new` + `sudo install -m 755 -o root -g root``/opt/stacks/backup/scripts/run.sh`. SHA256=`27b09ca272bb` match. Backup pre-unify в `.bak-pre-unify`.
- [x] **2026-05-25:** RUVDS deployed: `scp``C:\ProgramData\backup\run.ps1.new``Move-Item -Force`. SHA256=`f3bb57a86af5` match. Backup в `.bak-pre-unify`.
- [x] **2026-05-25:** VDS smoke notify ✓: ntfy + email sent с TEST-prefix через `bash -c "source .env; ..."` snippet.
- [x] **2026-05-25:** RUVDS smoke notify ✓: SCP + run `smoke-notify.ps1``ntfy_ok` + `email_ok`.
- [x] **2026-05-25:** windows-host `smoke-notify.ps1` + `deploy.ps1` подготовлены в `scripts/windows-host-fallback-backup-daily/`. **Pending elevated execution user'ом.**
## Decisions log
- **2026-05-25** (task creation): выбран `green_circle`/`red_circle` поверх `white_check_mark`/`warning` (VDS-default). Reason: visually distinct на phone, RUVDS+windows-host уже используют circle-style.
- **2026-05-25**: `OK` вместо `SUCCESS` в subject — shorter, у VDS уже было `OK`.
- **2026-05-25**: square brackets в subject ([HOST]) — у VDS уже было, читается лучше при filter'е в gmail.
- **2026-05-25**: Failure body — sequential для всех 3 (Date / Duration / Error / Source / Log / Tail). У VDS уже был tail-of-log; экстендим на RUVDS+WHOST.
- **2026-05-25**: VDS `run.sh` импортирован в repo как `scripts/vds-backup-rsync-kreknin/run.sh` — closes drift из общего pattern (`scripts/<slug>/`). Deploy = scp + sudo install обратно на VDS.
## Open questions
- [ ] **Snapshots count для RUVDS/WHOST.** VDS делает `ls -1d $DEST_BASE/20*-*-* | wc -l` через SSH. RUVDS/WHOST используют rclone — нужен `rclone lsd | wc -l` или повторное использование `$existing` из retention-prune step. Включим в edit.
- [ ] **Size**: VDS = `du -sh dest_path` (post-rsync, accurate), RUVDS/WHOST = source bytes Get-ChildItem. Standardize? Слишком expensive делать `rclone size` на dest (extra round-trip). **Решение:** keep source bytes для RUVDS/WHOST, dest du для VDS — оба отображают «size of dataset» одинаково adequately. В email можно подписать как `Size: <X> GB`, не различая источник.
- [ ] **Source IP/hostname**: hardcode (VDS=`89.253.255.94`, RUVDS=`80.64.31.36`, windows-host=`94.19.247.14`) vs `$(hostname -I)` / `$env:COMPUTERNAME`. Hardcode — short-term, проще; для prod-grade нужен detect.
## Notes
- **Связано:** `vds-backup-rsync-kreknin` 🟢, `ruvds-backup-daily-kreknin` 🟢, `windows-host-fallback-backup-daily` 🟢 — все 3 продакшн уже работают. Эта таска — cosmetic + observability unification, не функциональная.
- **Атомарный revert:** `git revert HEAD` + redeploy 3-х previous scripts. Pre-edit content закоммичен.
<!-- created-by: vitya / 2026-05-25 / trigger: user-decision — unify push+email across VDS/RUVDS/windows-host -->