docs: страница «Как работает провайдер: отличия от канонического Terraform» (freeze/destroy, пайплайн vDC→Edge→IP→SNAT→Штурвал, FAQ) + кейс UUID внутри JSON в case-sensitivity документе

This commit is contained in:
Nail
2026-09-24 20:40:18 +03:00
parent 10520670a5
commit aaf87d966b
2 changed files with 254 additions and 1 deletions
@@ -239,5 +239,59 @@ gr.NeedsStringsImport = hasRestoreCasingParams(gr.SchemaParams) || analyzeNeedsS
## 9. Версия
Фикс введён в версии провайдера **5.0.46**.
Фикс введён в версии провайдера **5.0.46** (старая линия; актуальные линии — prod `1.*`, dev `2.*`, test `3.*`, см. §10).
Сгенерированные ресурсы пересозданы после изменения генератора.
---
## 10. Обновление 2026-09-24: UUID внутри JSON (важно)
**Что уточнилось.** Посылка «API всегда возвращает lowercase» **неверна**. На живом стенде (Shturval dev-00)
один и тот же UUID приходил в разных регистрах: `vdcUid` — `d0937335-…` (lowercase), а `nsxtUid` кластера —
`2C37FED1-…` (UPPERCASE). Значит ориентироваться на «API нормализует» нельзя: сравнивать нужно всегда
без учёта регистра.
**Где вылезло.** Первый `apply` после «заморозки» стенда упал на усыновлении приостановленного кластера:
```
Error: required params mismatch for resource_name shturval-dev: startupConfiguration
(plan={… "nsxtUid":"2c37fed1-…" }, actual={… "nsxtUid":"2C37FED1-…" }).
```
**Почему предыдущие пять фиксов не помогли.** Они закрывали: отправку в API (`core/refsvc.go`,
`core/refsvc_resolve.go`), сравнение **одиночных** значений (`resources_core/params_compare.go`,
`normalizeCompareValue`), сравнение create-only атрибутов (`strings.EqualFold` в шаблоне генератора)
и восстановление регистра в state. Ни один из них не смотрит **внутрь JSON**, а adopt приостановленного
инстанса сравнивает параметр целиком как JSON:
`RequiredParamsMismatch` → `paramsEquivalent` → `JSONStringsEquivalent` → `jsonutil.normalizeJSONScalarsToStrings`,
где строки возвращались как есть (`case string: return val`). У Штурвала ref-параметры упакованы в JSON
(`startupConfiguration`), а путь adopt-suspended задействован впервые.
**Аудит: где регистр UUID может вылезти (проверено 24.09).**
| # | Место | Что ломает |
|---|---|---|
| 1 | `resources_core/required_params_compare.go` (`paramsEquivalent` → `JSONStringsEquivalent`) | adopt приостановленного инстанса — hard error (этот кейс) |
| 2 | `core/modifier_compare.go` | ложное «параметр изменился» → лишний `modify` на каждом apply |
| 3 | `resources_core/state_refresh.go` (сохранение планового JSON) | в state уедет регистр API вместо значения из config |
| 4 | `resources_core/resource_diagnostics_required.go` (create-диагностика) | та же `RequiredParamsMismatch` |
| 5 | `resources_core/params_compare.go` (`ParamsMatchForResume`) | одиночный UUID ок, JSON — та же дыра |
| 6 | `resources_core/json_planmodifier.go` (`JsonNormalize()`) | для JSON-атрибутов с UUID внутри — риск вечного diff |
| 7 | `resources_core/ref_validation.go` (`ValidateRefParamsOnAdopt`) | ref-параметр, зашитый внутрь JSON, **не проверяется вообще** (открыто) |
| 8 | `core/operation_run*.go` (`lookupLiveParam`) | подстановка live-значений по ключам: при другом регистре ключа может молча не сработать (открыто, требует живой проверки) |
**Фикс (провайдер `2.0.23`, dev).**
- `internal/core/jsonutil/jsonutil.go`: добавлен `LowercaseUUIDsInText` (UUID-подстрока → lowercase), и строковые
значения **внутри JSON** теперь нормализуются в `normalizeJSONScalarsToStrings` — закрывает пункты 1–5.
- `internal/resources_core/json_planmodifier.go`: `JsonNormalize()` после `json.Compact` приводит UUID-подстроки
к lowercase (типы и порядок ключей **не** меняются — план обязан совпадать с config) — закрывает пункт 6.
- Тесты: `internal/core/jsonutil/jsonutil_test.go`, `internal/resources_core/params_compare_test.go`
(в т.ч. на реальном `startupConfiguration` кластера).
**Дополнение к алгоритму диагностики (§8):**
7. Если расхождение — внутри JSON-параметра, проверьте именно UUID-подстроки и их регистр (не только одиночные
значения); смотрите `jsonutil.LowercaseUUIDsInText`.
8. Не «лечите» это нормализацией плана целиком (скаляры → строки, сортировка ключей): для атрибутов из config
допустимо менять только регистр UUID-подстрок, иначе Terraform ругнётся на несоответствие плана конфигу.