Пісочниця: режим перевірки оновлення «стара версія → нова»
Наявна пісочниця перевіряла лише установку з нуля. Шлях «стояла 0.1, стала 0.2» не перевіряло ніщо, а ламається він частіше: міграції поверх даних, зміна конфігурації, старий зонд проти нового колектора. «Попередня версія» — це КОМІТ, а не тег і не дамп. Тег неможливий: перевірка оновлення є вхідним квитком до першого тегу. Дамп не запускає старий колектор і старий зонд, тобто не бачить двох класів поломки з трьох. Коміт дає повне дерево, яке ВИКОНУЄТЬСЯ, а не описується — і тег теж ref, тож --from v0.1.0 запрацює в день першого тегу. Ізоляція закрита першою, зокрема неочевидна діра: обидві версії збиралися б під тегом netpulse/server:dev — тим самим, що ділить бойова інсталяція, і обірваний прогін лишив би :dev на старій збірці. ПРИМІТКА ДО ІСТОРІЇ: частина цих файлів уже потрапила в комітиc83324a,5c9143cі32442f8— я підмів незакомічену роботу агента власним `git add -A`. Історію не переписую (на тих комітах уже пройшов CI), але називаю це тут, щоб `git log` не вводив в оману:5c9143cпро CI містить і 113 рядків цього режиму. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
32442f8177
commit
d73f693cd7
2 changed files with 179 additions and 3 deletions
159
HISTORY.md
159
HISTORY.md
|
|
@ -7862,3 +7862,162 @@ git-дзеркало ДОСЛІВНО. Маскувати їх означає з
|
|||
* архів і дзеркало НЕ маскуються навмисно;
|
||||
* отже, доступ до дзеркала треба вважати рівносильним доступу до всіх
|
||||
паролів у мережі. Це не побічний ефект, а свідомо прийнята ціна.
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-28 — Пісочниця вміє другий шлях: оновлення з версії на версію
|
||||
|
||||
Установку з нуля пісочниця перевіряє з Етапу 12, і саме вона знайшла дві
|
||||
вади, які інакше зустрів би перший клієнт. Але з нуля клієнт ставить один
|
||||
раз, а оновлюється щоразу — і саме цього шляху не перевіряло **ніщо**.
|
||||
ROADMAP називав три причини, з яких ламається саме він: міграції поверх
|
||||
наявних даних, зміна конфігурації, несумісність зонда з новим колектором.
|
||||
Перевіряв їх перший клієнт.
|
||||
|
||||
Тепер є `./netpulse sandbox upgrade`.
|
||||
|
||||
### Питання, на яке довелось відповісти першим
|
||||
|
||||
**Що взагалі означає «попередня версія», якщо версіонування ще немає?**
|
||||
Тегів немає, реєстру немає, образ завжди `netpulse/server:dev`. Робити
|
||||
вигляд, що питання не існує, не можна: від відповіді залежить, чого
|
||||
вартий увесь прогін.
|
||||
|
||||
Варіантів було три.
|
||||
|
||||
* **Тег.** Найправильніший — і сьогодні неможливий. Перевірка оновлення є
|
||||
вхідним квитком *до* першого тегу. Вимагати тег означало б вимагати те,
|
||||
заради чого вона й пишеться; коло замикається на собі.
|
||||
* **Збережений дамп бази.** Найдешевший і доводить найменше. Дамп — це
|
||||
схема з даними, але не бінарники: він не запускає СТАРИЙ колектор і
|
||||
СТАРИЙ зонд, тобто не бачить двох названих класів поломки з трьох.
|
||||
Гірше інше: дамп старіє мовчки. Його зробила версія, яку вже ніхто не
|
||||
збере, і коли прогін почервоніє, розрізнити «зламався код» і «протух
|
||||
дамп» буде нічим. Перевірка, яка вміє брехати про причину, гірша за
|
||||
відсутність перевірки — це вже сплачений урок.
|
||||
* **Коміт git.** Обрано. Коміт — це ПОВНЕ дерево: Go-код, міграції,
|
||||
compose-файл, Caddyfile, Dockerfile. З нього збираються справжні старі
|
||||
образи, тобто попередня версія не описана, а **виконується**. Той самий
|
||||
ref дасть той самий стенд і за півроку.
|
||||
|
||||
І головне: це не тимчасове рішення. Тег у git — теж ref, тому в день
|
||||
першого тегу тут не зміниться жодного рядка, `--from v0.1.0` запрацює
|
||||
сам.
|
||||
|
||||
Типовий ref **обчислюється**: найновіший коміт, у якого міграцій менше,
|
||||
ніж у HEAD. Причина та сама, що й у решті установника — зелений прогін,
|
||||
який нічого не перевірив, гірший за відсутність прогону. Оновлення без
|
||||
жодної нової міграції доводить лише те, що служби перезапустились, і
|
||||
мовчки видається за доказ, що міграції котяться поверх даних. Якщо в парі
|
||||
версій нових міграцій немає, режим кричить про це двічі: при виборі й у
|
||||
підсумку.
|
||||
|
||||
### П'ять етапів, і кожен називає себе при падінні
|
||||
|
||||
`ЗУПИНКА на кроці «схема й ролі»` не каже головного — чиї саме міграції
|
||||
не накотились, старі чи нові. Тому з'явився рівень крупніший за крок:
|
||||
`ЗУПИНКА на етапі «В · оновлення до нової версії», крок «міграції поверх
|
||||
наявних даних»`.
|
||||
|
||||
* **А** — попередня версія ставиться з нуля тим самим `cmd_install` і
|
||||
проходить ту саму самоперевірку. Якщо впало тут, оновлення ні до чого:
|
||||
зламана сама попередня версія.
|
||||
* **Б** — наливання. Локації, 24 хости, доба ICMP і метрик із кроком
|
||||
5 хвилин (тобто кілька тисяч рядків через межу чанка Timescale),
|
||||
конфіги NCM, тригер і алерти. Без даних накочування поверх не доводить
|
||||
нічого: на порожній таблиці проходить будь-яка міграція.
|
||||
* **В** — дамп, збірка нової версії, міграції, перезапуск служб.
|
||||
* **Г** — та сама `selfcheck`, що й після чистої установки. Окремого
|
||||
набору тверджень навмисно немає.
|
||||
* **Д** — кількості «до» проти «після», по рядках.
|
||||
|
||||
### Старий зонд проти нового колектора
|
||||
|
||||
Найдорожча з трьох названих поломок і єдина, якої не видно з сервера:
|
||||
зонди стоять у чужих мережах і оновлюються не разом із сервером. Тут це
|
||||
перевіряється безкоштовно, бо `agent` живе під профілем compose, і
|
||||
`up -d` його не чіпає: після оновлення служб контейнер зонда лишається на
|
||||
образі **попередньої** версії. Питання одне — чи дійшов від нього хоч
|
||||
один такт із міткою пізнішою за момент перезапуску. Дві хвилини чекання,
|
||||
бо такт раз на 30 секунд плюс перепідключення; хибне червоне тут
|
||||
відправило б шукати неіснуючу несумісність протоколу. Другим кроком зонд
|
||||
перезбирається й перевіряється ще раз — заразом доводячи, що посвідчення
|
||||
в томі переживає перестворення контейнера й нового запрошення не треба.
|
||||
|
||||
### Ізоляція: що довелось закрити першим
|
||||
|
||||
Окреме ім'я проєкту compose, окремі томи, окрема мережа,
|
||||
`.env.sandbox-upgrade` замість бойового `.env`, порти від **18300** —
|
||||
свідомо за межами діапазону 18080…18272, який перебирає перший режим.
|
||||
|
||||
Але головне знайшлось не тут. Обидві версії збиралися б під тегом
|
||||
`netpulse/server:dev` — тим самим, що ділить із пісочницею **бойова
|
||||
інсталяція**. Друга збірка перетерла б першу, а обірваний прогін лишив би
|
||||
`:dev` указувати на СТАРУ збірку. Тому тег став змінною: `sandbox-prev`
|
||||
і `sandbox-new`, і `:dev` не згадується в цьому режимі жодного разу.
|
||||
Прибирання зносить і теги.
|
||||
|
||||
Дерево попередньої версії розгортається через `git archive` — він лише
|
||||
читає; `worktree` завів би запис у `.git`, `checkout` зрушив би робочу
|
||||
копію, тобто перевірка міняла б те, що перевіряє. Лежить дерево в
|
||||
`.sandbox-prev/` поруч із проєктом, а не в `/tmp`: там часто tmpfs, і
|
||||
другий примірник вихідних текстів ліг би в оперативну пам'ять — рівно ту,
|
||||
якої пісочниці й так ледве вистачає. З контексту збірки його виключає
|
||||
новий `.dockerignore` (заодно звідти прибрано `.env`: контекст іде
|
||||
демонові цілком, і паролям бази там робити нічого).
|
||||
|
||||
`./netpulse sandbox down` тепер прибирає **обидва** режими одразу.
|
||||
Пам'ятати, у якому режимі стенд піднімали, людина не зобов'язана.
|
||||
|
||||
### Дві хибні тривоги, вловлені до першого прогону
|
||||
|
||||
Звірка «до й після» мала два місця, у яких вона збрехала б **червоним**:
|
||||
|
||||
* Алерти рахувались у `alr.alerts` за `dedup_key`. Але фоновий такт
|
||||
переносить погашені алерти в `alr.alerts_history`, куди `dedup_key` не
|
||||
переїжджає взагалі, — і рядок, що переїхав, виглядав би як знищений.
|
||||
Тепер налиті алерти мічені в `context`, а рахуються по обох таблицях:
|
||||
`context` переїжджає разом із рядком.
|
||||
* Ряди метрик рахувались за `metric_key='cpu.util'` без прив'язки до
|
||||
хоста. Локальний зонд увесь цей час працює й пише свою телеметрію —
|
||||
вона потрапила б у той самий лічильник. Тепер кожен точний запит
|
||||
звужено до хостів `sb-sw-*`.
|
||||
|
||||
Правил у звірці два, і різниця між ними змістовна. `exact` — рядки, які
|
||||
налила сама пісочниця: їхня кількість не має права змінитись ані в який
|
||||
бік, бо поменшало означає «знищило», а побільшало — «роздвоїло», і обидва
|
||||
беззвучні. `min` — усе інше: система під час оновлення жива, і вимагати
|
||||
там рівності означало б хибне червоне на кожному другому прогоні.
|
||||
|
||||
### Чого цей режим НЕ доводить
|
||||
|
||||
Абзац обов'язковий, і не з ввічливості: перевірка, яку вважають повнішою
|
||||
за неї саму, шкідливіша за її відсутність.
|
||||
|
||||
* **Гілку «наявна інсталяція» в міграторі.** База пісочниці народжується
|
||||
чистою, тому `public.netpulse_install.fresh` лишається `true` назавжди
|
||||
— і мігратор іде гілкою «чиста база: видано паролі ролям». Рядок
|
||||
«наявна інсталяція: паролі ролей не чіпаю» тут не з'явиться ніколи, а
|
||||
отже перехід стенду, зробленого до 0063
|
||||
(`deploy/RLS-EXISTING-INSTALL.md`), лишається неперевіреним.
|
||||
* **Зміни в самому установнику між версіями.** Обидва етапи веде один і
|
||||
той самий `./netpulse` — старий не виконується взагалі. Вимірювальний
|
||||
прилад має бути тим самим на обох кінцях вимірювання, інакше різниця в
|
||||
приладі читається як різниця у виробі. Ціна відома й прийнята.
|
||||
* **Оновлення через кілька версій підряд** — перевіряється рівно один
|
||||
стрибок.
|
||||
* Усе те, чого не доводить і перший режим: Let's Encrypt, DNS, трапи на
|
||||
162/udp, поведінка під навантаженням.
|
||||
|
||||
### І чесно про те, що не прогнано
|
||||
|
||||
Написано й перевірено на розборі: `sh -n` і `dash -n` (POSIX, не bash),
|
||||
`scripts/check.sh` — усе зелене; вибір ref і розгортання дерева прогнано
|
||||
наживо на трьох випадках (автовибір, `--from` із двома новими міграціями,
|
||||
`--from` без жодної), прибирання після кожного не лишило слідів.
|
||||
**Самого стенду не піднято жодного разу: у цьому оточенні немає docker.**
|
||||
Тобто збірка старого дерева, наливання SQL, накат міграцій поверх даних,
|
||||
такт старого зонда й звірка кількостей — усе це поки доведене
|
||||
міркуванням, а не запуском. Саме той стан, проти якого написана
|
||||
пісочниця; перший прогін на стенді має бути перед першим тегом, а не
|
||||
після.
|
||||
|
|
|
|||
23
ROADMAP.md
23
ROADMAP.md
|
|
@ -482,6 +482,20 @@ CI-раннер ми запустили 2026-08-27. Бракує лише тог
|
|||
даних, оновити до нової, і прогнати ту саму самоперевірку. Без цього
|
||||
перший же реліз перевіряє себе на клієнтові.
|
||||
|
||||
**Написано 2026-08-28: `./netpulse sandbox upgrade`.** Попередня версія
|
||||
береться з коміта git (тег — теж ref, тому `--from v0.1.0` запрацює в
|
||||
день першого тегу без правок); ставиться з нуля, наливається хостами,
|
||||
телеметрією, конфігами й алертами, оновлюється, проганяє ту саму
|
||||
самоперевірку, і окремо звіряє кількості до й після. Заразом перевіряє
|
||||
СТАРИЙ зонд проти НОВОГО колектора — контейнер зонда під профілем
|
||||
compose, тому `up -d` його не чіпає.
|
||||
|
||||
**Але на стенді це ще не бігало жодного разу** — писалось там, де немає
|
||||
docker. Поки не прогнано наживо, цей рядок закритим вважати не можна:
|
||||
установка, перевірена лише розбором, доводить рівно те саме, що й сухий
|
||||
прогін. Подробиці — `deploy/README.md`, розділ «Пісочниця, режим
|
||||
другий», і `HISTORY.md` за 2026-08-28.
|
||||
|
||||
**Сумісність зонда й сервера.** Зонди стоять у мережах клієнтів і
|
||||
оновлюються не одночасно з сервером. Правило «який зонд працює з яким
|
||||
сервером» ніде не записане й не перевіряється.
|
||||
|
|
@ -509,9 +523,12 @@ CI-раннер ми запустили 2026-08-27. Бракує лише тог
|
|||
|
||||
Це єдина річ, яка блокує продаж, і вона не про код.
|
||||
|
||||
1. **Оновлення з версії на версію не перевіряв ніхто.** Пісочниця
|
||||
перевіряє установку з нуля. Шлях «стояла 0.1 — стала 0.2» ламається
|
||||
частіше, а перевіряє його зараз перший клієнт.
|
||||
1. **Оновлення з версії на версію: перевірка написана, наживо не
|
||||
бігала.** `./netpulse sandbox upgrade` робить повний шлях — попередня
|
||||
версія з нуля, дані, накат міграцій поверх них, та сама
|
||||
самоперевірка, звірка кількостей і старий зонд проти нового
|
||||
колектора. Лишається прогнати її на стенді: доки цього немає,
|
||||
перевіряє шлях і далі перший клієнт.
|
||||
2. **Немає версіонування.** Образ завжди `v0.1.0`, реєстру немає, тега
|
||||
немає. Поки цього немає, «оновитись» означає «залити дерево й
|
||||
зібрати», тобто те, що роблю я вручну.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue