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