From e25ef02a1adece09d8eb0cd6aeb9422a29e9c934 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Thu, 24 Sep 2026 14:04:08 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D1=83=D0=B1=D1=80=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D1=83=D1=81=D1=82=D0=B0=D1=80=D0=B5=D0=B2=D1=88=D0=B5=D0=B5=20?= =?UTF-8?q?=C2=AB=D0=BA=D0=B0=D0=BD=D0=BE=D0=BD=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B2=20plan-modifier=C2=BB=20(=D1=81=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D1=82=20Opus=20=D0=B1=D1=8B=D0=BB=20=D0=BD=D0=B5?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=B5=D0=BD);=20=D0=BF=D0=BB=D0=B0=D0=BD=20?= =?UTF-8?q?=D0=B6=D0=B8=D0=B2=D0=BE=D0=B3=D0=BE=20=D0=BF=D1=80=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=20FullPipe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PLAN_FULLPIPE_LIVE_RUN_2026-09-24.md | 78 +++++++++++++++++++ ...opus_review_modify_resources_2026-09-24.md | 28 ++++--- docs/curated/modifiers/org_ip_and_snat.md | 4 +- 3 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 NOTES/10_plans/PLAN_FULLPIPE_LIVE_RUN_2026-09-24.md diff --git a/NOTES/10_plans/PLAN_FULLPIPE_LIVE_RUN_2026-09-24.md b/NOTES/10_plans/PLAN_FULLPIPE_LIVE_RUN_2026-09-24.md new file mode 100644 index 0000000..6b9b4b5 --- /dev/null +++ b/NOTES/10_plans/PLAN_FULLPIPE_LIVE_RUN_2026-09-24.md @@ -0,0 +1,78 @@ +# ПЛАН: живой прогон цепочки на DEV_STAND/FullPipe (2026-09-24) + +> Стенд: dev, орга **`organ`** (`57eeacd1-dc7f-4a52-b903-7e5f7d3c1164`, realm `sandbox.nubes.ru`, тип `saas`, +> CD-имя `WZ01325-saas`). Провайдер `2.0.19` (`terraform init -upgrade` уже сделан, `validate` — Success). +> **`apply`/`destroy` запускает только пользователь.** + +## 0. Что уже готово + +- Ресурсы `nubes_vc_org_ip_allocation` (modify `vIPConfigure`) и `nubes_vc_nsxt_snat` (modify `ipSpaceName`) — + в провайдере, собраны в `2.0.19`, залиты в `nubes-dev`, есть unit-тесты канонизации. +- Конфиг стенда: `DEV_STAND/FullPipe/` — `vdc.tf`, `edge.tf`, `modifiers.tf` (аллокация после эджа, затем SNAT), + `organization = "organ"` + `org_uid`. +- Орга создана вручную (в tf её нет) — по решению пользователя. + +## 1. Цель прогона + +Проверить **одним `apply`**: `vdc → edge → IP на орге → SNAT`, затем чистый повторный `plan` и корректный +`destroy`. Это первый живой прогон обоих новых ресурсов: CRUD до сих пор не проверялся. + +## 2. Перед прогоном (проверить значения) + +1. `vdc_network_provider` (`snb1`), `vdc_provider_vdc` (`Intel Broadwell 2.4`), `vdc_storage_config` (`SATA`) — + убедиться в ЛК, что доступны для орги `organ` (значения брались из ЛК для прежней орги). +2. `ip_space_name` — сначала может быть недоступен: **список ipSpace в ЛК падает** (`Can't cast Complex Object + Type Struct to String`), пока нет vDC/эджа. Брать имя из прежних HAR: `internet-ipv4-v1`. +3. `ip_count` — `"3"` (строка). + +## 3. Шаги прогона (пользователь) + +| # | Команда | Ожидаемый результат | +|---|---|---| +| 1 | `terraform plan` | создание: `nubes_vc_vdc.vdc` → `nubes_vc_nsxt.edge` → `nubes_vc_org_ip_allocation.org_ip` → `nubes_vc_nsxt_snat.snat`; порядка не меньше | +| 2 | `terraform apply` | всё создаётся за один проход | +| 3 | `terraform plan` (повторно) | **пустой** — главный тест канонизации (иначе вечный diff) | +| 4 | проверить API (см. §4) | `vIPConfigure` и `ipSpaceName` в live-состоянии | +| 5 | изменить `ip_count` 3 → 2, `plan`+`apply` | меняется только аллокация, state сходится | +| 6 | `terraform destroy` | порядок `snat (no-needed)` → `org_ip (count=0)` → `edge` → `vdc`; орги не касается | + +## 4. Что проверять и чем + +```bash +TOK=$(tr -d '\n' < secrets/narodDEV.token) # токен орги organ +# состояние орги +curl -s -H "Authorization: Bearer $TOK" 'https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc/instances/' +# состояние эджа +curl -s -H "Authorization: Bearer $TOK" 'https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc/instances/' +``` + +**Гипотезы, которые прогон подтверждает/опровергает:** + +1. **Имена live-ключей**: `state.params.vIPConfigure` (орга) и `state.params.ipSpaceName` (эдж) — взяты из HAR, + кодом не проверены. Если Read вернёт не то → увидим дрейф/пустое значение. +2. **Частичный payload не затирает остальное**: SNAT-модификация шлёт только `372`; `needEnableAVI` + и `virtualServicesCount` должны остаться прежними (`true` / `1`), т.к. досылаются из live + (`core/operation_run_bycode.go`). Проверить в состоянии эджа до/после. +3. **Один `apply`** проходит целиком без второго прогона (ради этого и делались ресурсы). +4. **Нет вечного diff** после apply (канонизация `vip_configure`). +5. **`Required` + пустое live** не даёт ошибок (лечение из ревью). + +## 5. Точки отказа и что делать + +| Симптом | Вероятная причина | Действие | +|---|---|---| +| аллокация падает `Can't cast ... Struct to String` | платформа ещё не видит `job.vcd.networkProvider`/`providerGateway` (эдж/VDC не в состоянии) | проверить порядок и фактическое состояние эджа; при необходимости — пауза/повторный `apply` | +| `Provider produced inconsistent result after apply` на `vdc`/`edge` | read-back перекрыл план (известный класс дефектов) | записать в NOTES, разбирать отдельно (это уже не про наши ресурсы) | +| повторный `plan` не пустой | порядок ключей/формат не сошлись | сверить, что вернул live, с `formatVipConfigure` | +| SNAT не включился | `372` не доехал / неверное имя ipSpace | проверить `state.params.ipSpaceName` эджа и лог операции | +| `destroy` падает | обратный modify на живой/мёртвый родитель | смотреть тексты диагностик ресурсов (мы развели: ошибка API ≠ «родителя нет») | + +## 6. После прогона + +1. Отчёт в `NOTES/30_analysis/` — что прошло, что упало, с HAR/логами. +2. Обновить память репозитория (подтверждённые факты вместо гипотез). +3. Если найдутся баги — отдельные коммиты + при необходимости новый релиз провайдера. +4. Публикация документации (`04_build_and_publish_docs.sh`) — отдельной командой. + +**Не входит в этот прогон:** кластер Штурвал (`nubes_k8s_shturval_cluster`) — отдельным шагом, после того как +SNAT подтверждён. diff --git a/NOTES/20_prompts/prompt_for_opus_review_modify_resources_2026-09-24.md b/NOTES/20_prompts/prompt_for_opus_review_modify_resources_2026-09-24.md index a6f0f70..be2fdbf 100644 --- a/NOTES/20_prompts/prompt_for_opus_review_modify_resources_2026-09-24.md +++ b/NOTES/20_prompts/prompt_for_opus_review_modify_resources_2026-09-24.md @@ -808,14 +808,24 @@ func (m jsonNormalizePlanModifier) PlanModifyString(_ context.Context, req planm (только destroy) — **задокументировать** в описании атрибута. - Раздел 3 (риски живой платформы) без прогона не закрывается — остаётся открытым. -## Требуется сделать (по итогам ревью) — ВЫПОЛНЕНО (коммиты `ba6c4f5`, `4b497e6`, `1236c59`) +## Итог по ревью: что сделано и где ревью ошиблось -1. ✅ Заменить `JsonNormalize()` на канонизирующий plan-modifier (`parse → formatVipConfigure`) — - закрывает баг порядка ключей (в т.ч. для `jsonencode`). -2. ✅ Убрать запись `null` в `Required`-атрибуты (`vip_configure`, `ip_space_name`) — при пустом live - сохраняется текущее значение state (проверка «что отправили — то и в state»). -3. ✅ `Delete`: ошибки API → `AddError`; warning оставлен только для отсутствующего родителя. -4. ✅ `setSnat`: вместо тихой подмены — валидация пустой строки. +**⚠️ Совет Opus (вариант «б», канонизация в plan-modifier) — НЕВЕРЕН.** Plan-modifier не имеет права +менять значение пользовательского атрибута: Terraform отвечает +`Provider produced invalid plan: planned value does not match config value`. +Это правило описано в нашем же сгенерированном коде (`22_vc_nsxt_resource.go`, комментарий в `ModifyPlan`). +Проверено живым `terraform plan` 2026-09-24 (ошибка воспроизведена). + +Правильное решение (коммит `807dfde`): +- plan-modifier удалён полностью (`JsonNormalize` тоже снят — он компактит, то есть тоже менял бы значение); +- в `Read` — смысловое сравнение `vipAllocationsEqual`: если смысл совпал (порядок ключей/формат не важны), + значение пользователя НЕ переписывается; пишется только реальный дрейф. + +**Выполнено корректно:** +1. ✅ Убран plan-modifier, менявший пользовательское значение; сравнение — смысловое (коммит `807dfde`). +2. ✅ `null` в `Required`-атрибуты не пишется — при пустом live сохраняется текущее значение state. +3. ✅ `Delete`: ошибки API → `AddError`; warning только для отсутствующего родителя. +4. ✅ `setSnat`: валидация пустой строки вместо тихой подмены на `no-needed`. 5. ✅ Задокументировано: «снять всё» через `vip_configure` нельзя, только `destroy`. -6. ✅ Поправлены/добавлены тесты канонизации (`jsonencode`-форма, пробелы, `[{}]`, невалидный JSON). -7. ⏳ Новый релиз провайдера (2.0.19) с повторной заливкой в `nubes-dev`. +6. ✅ Тесты: смысловое сравнение (порядок ключей, разный count/имя, пустая аллокация). +7. ⚠️ Релиз `2.0.19` залит, но **содержит сломанный plan-modifier** — для работы из реестра нужен `2.0.20`. diff --git a/docs/curated/modifiers/org_ip_and_snat.md b/docs/curated/modifiers/org_ip_and_snat.md index b3a0155..7be9d82 100644 --- a/docs/curated/modifiers/org_ip_and_snat.md +++ b/docs/curated/modifiers/org_ip_and_snat.md @@ -16,8 +16,8 @@ | `vip_configure` | string (JSON), обязательный | Массив аллокаций: `[{"name":"internet-ipv4-v1","count":"3"}]`. `count` — строка | | `keep_on_destroy` | bool, по умолчанию `false` | Не снимать квоту при `destroy` | -Порядок ключей и форматирование не важны — значение канонизируется при планировании -(важно потому, что `jsonencode` сортирует ключи по алфавиту). +Порядок ключей и форматирование не важны — сравнение смысловое (важно потому, что `jsonencode` сортирует +ключи по алфавиту). Снять аллокацию через `vip_configure` **нельзя** (пустой массив отклоняется): для этого удали ресурс — тогда отправится обратный `modify` с `count = "0"`.