docs(flash): ТЗ на фикс tainted-replace - убрать create-time проверку из ModifyPlan

This commit is contained in:
Repinoid
2026-09-21 20:52:51 +03:00
parent e8da976a7b
commit 14ada09335
@@ -0,0 +1,130 @@
# ТЗ для DeepSeek Flash: убрать create-time проверку существования из `ModifyPlan`
Дата: 2026-09-21 | Статус: не сделано | Версия провайдера на момент бага: 2.0.6
## Цель
Починить `terraform destroy` (и любую `tainted`-замену), который падает с
`РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (RUNNING)`.
## Контекст
- Репозиторий: `/home/naeel/TF/tf_provider`
- Провайдер: `terraform-provider-nubes`, Go, `terraform-plugin-framework v1.8.0`
- Ресурсы генерируются шаблоном, **НЕ правятся руками**
- Модуль провайдера живёт в `provider/` (не в корне репозитория)
## Симптом
```
$ terraform destroy
nubes_vc_vdc.vdc: Refreshing state... [id=db2cefc3-...]
nubes_vc_nsxt.edge: Refreshing state... [id=8AAEC14D-...]
│ Error: РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (RUNNING)
│ with nubes_vc_nsxt.edge,
│ on edge.tf line 1, in resource "nubes_vc_nsxt" "edge":
```
То же самое при обычном `terraform plan`.
## Причина (подтверждена фактами)
1. `nubes_vc_nsxt.edge` в state помечен **`tainted`** (следствие прошлой неудачной
apply с `vdc_group_uid`: `Provider returned invalid result object after apply`).
Проверка: `terraform.tfstate``instances[].status == "tainted"`.
2. Tainted-ресурс Terraform обязан **заменить** (destroy + create). Это видно в плане:
```
# nubes_vc_nsxt.edge is tainted, so must be replaced
-/+ resource "nubes_vc_nsxt" "edge" {
```
3. `terraform destroy` сначала выполняет **внутренний обычный plan**
(`Context.destroyPlan: calling Context.plan` — видно в `TF_LOG=TRACE`), и уже
на этом шаге планируется замена edge.
4. Create-узел замены вызывает `ModifyPlan` с **prior state = null**, поэтому guard
`if state != nil && !state.ID.IsNull() && ...` пропускается, и доходит до
create-time проверки существования.
5. Проверка находит **живой** инстанс в облаке (старый edge ещё не удалён — удаление
идёт на apply) → `РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (RUNNING)` → plan падает →
`destroy` не начинается.
Ключевое: на уровне `ModifyPlan` **невозможно** отличить «создание нового ресурса»
от «create-узла замены» — у обоих prior state = null. Поэтому проверки существования
в `ModifyPlan` быть не должно в принципе.
Доказательство, что вызов идёт из `ModifyPlan`: `/tmp/nubes_find_debug.log` содержит
`[FIND-DEBUG] PlanExistingResourceDiagnostics entered: serviceId=22 name="fullpipe-edge"`.
Эту строку пишет только Plan-функция; `Create...` в этот лог не пишет.
## Правка
**Один файл:** `TOOLS/resource-generator/internal/templates/instance.go`, шаблон метода `ModifyPlan`.
Удалить целиком блок от строки
```go
if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
return
}
```
до строки
```go
resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, {{.ServiceID}}, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs, {{.SupportsSuspendDestroy}})...)
```
включительно. Это весь хвост `ModifyPlan` после блока «Missing required attribute»:
`adoptExistingOnCreate`, resolve refSvc, `params`, `desiredDomain`, `domainServiceIDs`
и сам вызов диагностики.
### Что НЕ трогать
- destroy-guard `if req.Plan.Raw.IsNull() { return }` — **оставить**;
- блок create-only проверок (по `state.ID`) — **оставить**;
- блок «Missing required attribute» — **оставить**;
- `Create` — там вызов `CreateExistingResourceDiagnosticsWithDomainAndServices`
**остаётся**: проверка выполняется на apply, уже после удаления старого инстанса.
### Побочный эффект (принять как норму)
Из plan пропадают проверки ref-параметров / domain / существования по имени. Это
штатное поведение Terraform: на apply `Create` резолвит refSvc (с ошибкой) и делает
проверку существования.
## Проверка
```bash
cd /home/naeel/TF/tf_provider && ./TOOLS/scripts/02_generate_resources_and_docs_v2.sh --profile TOOLS/config/dev
```
```bash
TMP=$(mktemp -d) && cp -R provider "$TMP/provider" && find "$TMP/provider/internal/resources_gen" -maxdepth 1 -type f -name '*.go' -delete && cp generated/dev/go/*.go "$TMP/provider/internal/resources_gen/" && (cd "$TMP/provider" && go build ./...) && echo BUILD_OK && rm -rf "$TMP"
```
Затем проверить сгенерированный код:
- `generated/dev/go/22_vc_nsxt_resource.go`: в `ModifyPlan` вызова
`PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices` больше нет;
- в `Create` вызов `CreateExistingResourceDiagnosticsWithDomainAndServices` остался.
Если после удаления какой-то импорт стал неиспользуемым (`fmt`, `resources_core`) —
проверить сборкой. Обычно `Create` сохраняет те же импорты, отдельная правка флага
`NeedsFmtImport` не требуется.
## Что НЕ делать
- **НЕ собирать и НЕ заливать** провайдер — только правка шаблона + генерация + сборка-проверка.
- Не править сгенерированный код руками.
- Не трогать `provider/internal/resources_core/resource_diagnostics_required.go`.
## Критерий готовности
`BUILD_OK` и в сгенерированном edge `ModifyPlan` нет create-time проверки.
## Обходной путь без правок (если надо убить стенд прямо сейчас)
```bash
terraform untaint nubes_vc_nsxt.edge && terraform destroy
```