From 14ada093351f72c61f36eb4ffa9ab4c686ec44e7 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Mon, 21 Sep 2026 20:52:51 +0300 Subject: [PATCH] =?UTF-8?q?docs(flash):=20=D0=A2=D0=97=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20tainted-replace=20-=20=D1=83=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D1=82=D1=8C=20create-time=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=BA=D1=83=20=D0=B8=D0=B7=20ModifyPlan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/prompt_for_flash_fix_tainted_replace.md | 130 +++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 docs/prompt_for_flash_fix_tainted_replace.md diff --git a/docs/prompt_for_flash_fix_tainted_replace.md b/docs/prompt_for_flash_fix_tainted_replace.md new file mode 100644 index 0000000..2265d95 --- /dev/null +++ b/docs/prompt_for_flash_fix_tainted_replace.md @@ -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 +```