Files
tf_provider/prompt_for_opus_modifier_architecture_full.md
T

6.3 KiB
Raw Blame History

Спроектировать С НУЛЯ архитектуру/логику «ресурсов-модификаторов» (kind: modifier)

Цель

Перепроектировать модификаторы целиком, чтобы исключить ВСЕ классы багов, не латать по одному. Нужна единая, полная модель поведения — без догадок и костылей. Перечислить ВСЕ кейсы.

Что такое модификатор (текущая фактура)

В YAML (генерируется из API) операции бывают:

  • kind: instance (create/modify/suspend/resume/delete) — обычный CRUD-ресурс;
  • kind: modifier + modifier: <name> — отдельный TF-ресурс, который вызывает modify на родительском инстансе. Сейчас их два: vc_org.ip_space, vc_nsxt.network.

Реальные примеры:

  • vc_org → modifier ip_space (modify 207), параметр vIPConfigure (array-map-fixed);
  • vc_nsxt → modifier network (modify 111), параметры needEnableAVI(bool), virtualServicesCount(int>0), qosProfile(string), ipSpaceName(string), routedNetConfiguration(map-fixed).

Текущий механизм (что есть — факты, не догадки)

  1. Генератор: TOOLS/resource-generator/internal/templates/modifier.go
    • Create и Update идентичны: оба шлют modify с полным набором полей.
    • Deleteno-op (комментарий: «no confirmed inverse payload»).
    • Схема: id computed, <service>_id required, поля Optional (или Required если нет default).
  2. resources_core.CompactParams — выбрасывает пустые строки из payload.
  3. resources_core.BuildActionID(instanceUID, operation, modifierName) — константный ID, не привязан к реальной операции (opUid не сохраняется).
  4. core.RunInstanceOperationUniversalByCode — резолвит code→id через GET /instanceOperations/{opUid}?fields=cfsParams (fallback на /default/{opId}); отправляет переданные params, затем дозаполняет остальные их live-значением (guard: пропускает параметр, если нет ни ParamValue, ни DefaultValue).
  5. Read — через RefreshResourceState: читает state_params инстанса и перезаписывает input-поля из них.

Уже выявленные КЛАССЫ багов (все реально случились)

  • A. Сброс create-поля при modify. modify со сброшенными (null) параметрами трактуется бэкендом как reset-to-default: needEnableAVI стал false после create=true. Причина: модификатор шлёт только свои поля, CompactParams выкидывает пустые, бэкенд видит «отсутствующий» и сбрасывает.
  • B. Досылка синтетики. фикс «досылать всё» слал "0" для integer > 0 (параметр virtualServicesCount), API 400 «Invalid format integer > 0».
  • C. Ложное «Нельзя изменить». ComputeCreateOnly считал needEnableAVI CreateOnly (change-forbidden), хотя в YAML is_modifiable: true — потому что генератор не учитывал modifier-канал и терял IsModifiable. (Зафиксировано отдельно.)
  • D. No-op Delete оставляет эффект на платформе. destroy модификатора убирает ресурс из state, но выделенные IP / включённый ALB остаются на платформе → drift.
  • E. Повторный apply после taint/replace снова гонит modify — риск повторной аллокации (для ip_space), идемпотентность не гарантирована.

Вопросы к Опусу (ответить ПОЛНО, по пунктам, с точными местами правки)

  1. Канон «как сравнить и применить». Должен ли модификатор перед modify читать текущее состояние и слать ДЕЛЬТУ (только реально изменившиеся поля), или ПТЦ полный payload? Как детектить drift в Read?
  2. Досылка незаданных полей (паер-заливы A и B). Какое каноническое правило: когда досылать live-значение, когда дефолт, когда пропускать? Как не сломать integer > 0 и прочие constraints?
  3. Delete/rollback. Где искать обратный payload? Как правильно поступить, пока обратный payload НЕ подтверждён API (no-op допустим? явная ошибка? suspend?).
  4. Idempotency + ID. Как сделать ID модификатора отражающим фактическую операцию (opUid?) и как предотвратить двойную аллокацию при replace/повторном apply?
  5. Связь с родителем. Должен ли модификатор использовать <service>_id как ссылку на родителя (depends_on / borrow state), и как читать UUID родителя?
  6. Create vs Update. Допустимо ли иметь их идентичными, или нужен строго Update-семантик (нет create, только apply-по-десяти)?
  7. Полный перечень кейсов. Перечислить ВСЕ edge-кейсы, которые надо покрыть: create родителя → modifier; remove modifier; replace; partial params; unknown/absent.

Ответ — архитектурный документ (краткий, структурированный), с конкретными файлами и функциями. НЕ код-ревью, а ПРОЕКТ.