docs(flash): ТЗ на фикс tainted-replace - убрать create-time проверку из ModifyPlan
This commit is contained in:
@@ -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
|
||||
```
|
||||
Reference in New Issue
Block a user