docs(HISTORY): сессия 2026-09-21 - фиксы генератора, refSvc, FullPipe (vDC+Edge)

This commit is contained in:
Repinoid
2026-09-21 20:08:40 +03:00
parent bffe3d9950
commit 61c7e207ba
@@ -0,0 +1,219 @@
# 2026-09-21 — FullPipe (vDC + Edge): серия фиксов генератора и провайдера
## Контекст
Поднимался полный стенд `DEV_STAND/FullPipe` (целевой пайплайн: Организация → vDC → Edge),
заливался провайдер в реестр (`nubes-dev/nubes`). По ходу вылезла цепочка багов —
в генераторе ресурсов, в сгенерированном коде и в docs-генераторе.
Версия на выходе: **2.0.5** (DEV, namespace `nubes-dev`).
---
## Баг 1. Непересобираемый генератор (stale binary) — устранён ранее в этот же день
**Симптом:** `kind: modifier` в YAML не поддерживался; генерация YAML падала.
**Причина:** `02_generate_resources_and_docs_v2.sh` пересобирал `resource-generator`
только по `mtime`. Лежавший в `TOOLS/resource-generator/bin/resource-generator`
устаревший бинарь затенял исходники.
**Фикс:**
- генераторы (`resource-generator`, `docs-generator`) пересобираются **всегда** из исходников;
- устаревший бинарник удалён; `TOOLS/resource-generator/bin/` добавлен в `.gitignore`;
- обновлены `README.md`, `TOOLS/README.md`.
- Коммит: `7ecd2aa Fix generator rebuild and release pipeline`.
---
## Баг 2. `declared and not used: resolvedKafkaUid` — сборка падала
**Симптомы (сборка из сгенерированного кода):**
```
internal/resources_gen/119_akhq_resource.go:246:2: declared and not used: resolvedKafkaUid
internal/resources_gen/111_dnsrecord_resource.go:248:2: declared and not used: resolvedZoneUid
internal/resources_gen/21_vc_vdc_resource.go:244:2: declared and not used: resolvedOrganizationUid
... (и ещё по всем ресурсам с refSvc в create)
```
**Причина:** в шаблоне `TOOLS/resource-generator/internal/templates/instance.go`:
- блок объявления резолва шёл по `{{range .SchemaParams}}` — т.е. объявлял `resolvedX`
для **всех** refSvc-полей;
- а мапа `params` в `Create` НЕ содержала refSvc-условия и писала сырое `data.X`.
Итог: `resolvedX` объявлен, но нигде не использован → ошибка компиляции.
**Фикс (шаблон `instance.go`, `subresource.go`):**
- циклы резолва переведены на `{{range .CreateParams}}` / `{{range .ModifyParams}}`;
- в мапу `params` в `Create` добавлено refSvc-условие:
```
{{.ID}}: resolved{{ToCamel .Code}}, // в API уходит UUID
{{else}} data.X // сырое значение
```
- Коммит: `2286d34`.
---
## Баг 3. `terraform destroy` падал: «РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (RUNNING)»
**Симптом:**
```
terraform destroy
nubes_vc_vdc.vdc: Refreshing state... [id=...]
╷ Error: РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (RUNNING)
```
**Причина:** `ModifyPlan` сгенерированного ресурса на **destroy-плане** запускал
create-time проверку существования/adopt (`PlanExistingResourceDiagnostics...` →
`FindInstanceByDisplayName`). Гварды `config == nil` и
`State.Raw.IsNull() && Plan.Raw.IsNull()` destroy не отсекали (config ненулевой —
блок ресурса ещё в `.tf`; а в destroy-плане state есть, plan = null).
Debug-подтверждение: `/tmp/nubes_find_debug.log` →
`PlanExistingResourceDiagnostics entered: serviceId=21 name="fullpipe-vdc" adopt=false`.
**Обходной путь (временный):** `adopt_existing_on_create=true` — но это «телега впереди
лошади»: destroy не должен зависеть от adopt.
**Фикс (шаблон `instance.go`, `ModifyPlan`):** добавить destroy-guard
```
if req.Plan.Raw.IsNull() { return }
```
Теперь destroy-план не запускает create-time проверку и доходит до `Delete`,
который по `suspend_on_destroy=true` отправляет `suspend`.
Логика suspend уже была в `Delete`: `deleteMode := "state_only"` → `"suspend"`.
- Коммит: `2286d34`.
---
## Баг 4. `Provider produced inconsistent result after apply`: `.organization_uid` было `"kontora"`, стало UUID
**Симптом:**
```
.provider produced an unexpected new value: .organization_uid:
was cty.StringVal("kontora"), but now cty.StringVal("ec4d3a6a-...")
```
**Причина:** refSvc-поле резолвилось и **записывалось обратно в state**, из-за чего
state (UUID) не совпадал с plan (user input).
**Фикс (универсальный, все сервисы):**
- резолв идёт только в локальную переменную `resolvedX`; в state остаётся ровно то,
что ввёл пользователь (имя ИЛИ UUID);
- refresh исключает refSvc-поля (`{{if eq .RefSvcId 0}}`) — не перезаписывает ввод;
- `ResolveRefSvcParamValue` принимает имя (→ UUID) и UUID (→ lowercase);
обратный маппинг `ResolveRefSvcParamDisplayName` для refresh.
- Коммит: `2286d34`.
---
## Баг 5. `Provider returned invalid result object after apply`: `vdc_group_uid` остался unknown
**Симптом (создание Edge):**
```
Error: Provider returned invalid result object after apply
After the apply operation, the provider still indicated an unknown value for
nubes_vc_nsxt.edge.vdc_group_uid.
```
**Причина:** в схеме refSvc-поля были `Optional: true, Computed: true` **без дефолта**
(строка шаблона: `{{- else if or .IsJson (gt .RefSvcId 0) }}Computed: true,{{- end }}`).
Если пользователь поле не задавал (например, `vdc_group_uid` при `vdc_type="vdc"`),
Terraform планировал его как **unknown** и требовал от провайдера известное значение.
Провайдер его не вычисляет (по дизайну хранит ввод юзера) → остаётся unknown → ошибка.
`Computed: true` — рудимент **старого** дизайна (когда провайдер писал резолвленный UUID
в state). После перехода на «храним ввод юзера» он стал вредным.
**Фикс (оба шаблона: `instance.go`, `subresource.go`):**
```
- {{- else if or .IsJson (gt .RefSvcId 0) }}Computed: true,{{- end }}
+ {{- else if .IsJson }}Computed: true,{{- end }}
```
Теперь незаданный refSvc = `null` (известное значение). `IsJson` оставлен Computed
намеренно (нужно для нормализации JSON из API).
Проверено: в сгенерированном `22_vc_nsxt_resource.go` →
`"vdc_group_uid": schema.StringAttribute{Optional: true, ...}` (без `Computed`).
- Коммит: `bffe3d9`.
---
## Баг 6. docs-generator: вложенный `map-fixed` рендерится как блок (НЕ исправлено → TODO)
Пример в сгенерированной доке (`generated/dev/docs/vc_nsxt_example.md`) рисует
`routed_net_configuration` **блоком**, но схема — `SingleNestedAttribute`, значит нужен
аргумент `= { ... }`. Копирование примера → `terraform validate` падает:
`Unsupported block type`.
Виноват `TOOLS/docs-generator/internal/writers/writers.go` → `formatParamOrBlock`
(~стр. 715). Подробности — `docs/TODO/docs_generator_nested_attr_syntax.md`.
Коммит: `92e04da`.
---
## Баг 7. FullPipe: дефолт `vdc_storage_config = "fast"`
**Симптом:** дефолт в `variables.tf` — `[{"name":"fast","size":200}]`.
Имя политики берётся из ресурсного пула (`getKeyListFromStruct(...providerVdcs[...].storage)`),
и `fast` в окружении не существует.
**История (по git):** `fast` появился в первом коммите стенда `7ff98f8` — причём их было
**два**: `vdc_provider_vdc = "fast-2.8"` и `vdc_storage_config = "fast"`. Коммит
`7d44697` («Fix FullPipe VDC example placeholders») поправил только `provider_vdc`
(`"fast-2.8"` → `null`), а `storage_config` не тронул. Так что «опять fast» — это
незакрытый второй хвост, а не откат.
**Фикс:** дефолт → `[{"name":"SATA","size":"200"}]` (совпадает с рабочим `terraform.tfvars`).
Коммит: `d608fba`.
---
## Добавлено в стенд FullPipe
- `DEV_STAND/FullPipe/edge.tf` — ресурс `nubes_vc_nsxt.edge` (create),
`vdc_uid = nubes_vc_vdc.vdc.id` (Edge создаётся после vDC),
`routed_net_configuration = { ... }` (аргумент, не блок — см. Баг 6).
- переменные `nsxt_*` в `variables.tf`, outputs `nsxt_*` в `outputs.tf`,
пример в `terraform.tfvars.example`.
- `versions.tf` → провайдер `2.0.4` (затем `2.0.5`).
- Коммит: `d608fba`.
---
## Изменённые файлы (генератор)
| Файл | Что |
|------|-----|
| `TOOLS/resource-generator/internal/templates/instance.go` | destroy-guard в `ModifyPlan`; резолв refSvc по `.CreateParams`; refSvc-условие в мапе `params`; refSvc без `Computed` |
| `TOOLS/resource-generator/internal/templates/subresource.go` | резолв по `.CreateParams`/`.ModifyParams`; refSvc без `Computed` |
| `TOOLS/scripts/02_generate_resources_and_docs_v2.sh` | детерминированная пересборка генераторов |
| `.gitignore`, `README.md`, `TOOLS/README.md` | игнор бинарника, доки |
## Версии
| Стенд | Namespace | Версия |
|---|---|---|
| DEV | `nubes-dev` | `2.0.5` |
## Коммиты сессии (master)
```
bffe3d9 fix(generator): refSvc-поля без Computed (unset = null, а не unknown)
92e04da docs(TODO): баг docs-generator - вложенный map-fixed как блок вместо = {}
d608fba stand(FullPipe): vc_nsxt (edge.tf), storage_config fast->SATA, provider 2.0.4
1401003 release(dev): 2.0.4
2286d34 fix(generator): destroy-guard в ModifyPlan + универсальный refSvc (имя или UUID)
7ecd2aa Fix generator rebuild and release pipeline
```
## Открытые вопросы
- [ ] docs-generator: `map-fixed` → `= { ... }`, `array-map-fixed` → JSON/jsonencode
(см. `docs/TODO/docs_generator_nested_attr_syntax.md`).
- [ ] Проверить `IsJson`-поля без дефолта: тот же класс unknown-after-apply? (не воспроизводилось).
- [ ] `fast` в тест-фикстуре `provider/internal/core/client_test.go:287` и спек-доке
`docs/60_strategy/...:158` — не трогали.