From d93ff6648206f6acc6a92a7d69c01d699770aa04 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Thu, 24 Sep 2026 07:25:27 +0300 Subject: [PATCH] chore: save current changes --- .github/copilot-instructions.md | 5 + PLAN_modifier_redesign.md | 5 + ...er_resources_ideology_and_specification.md | 5 + docs/CHAT_RESUME_IAC_2026-09-24.md | 199 ++++++++++++++++++ ...S_ANSWER_IAC_SHTURVAL_MODIFY_2026-09-23.md | 43 ++-- ...SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md | 4 +- .../prompt_for_opus_iac_shturval_modify.md | 4 +- 7 files changed, 243 insertions(+), 22 deletions(-) create mode 100644 docs/CHAT_RESUME_IAC_2026-09-24.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index cde5f74..ba348e4 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -9,3 +9,8 @@ НИКОГДА НЕ ПРЕВЫШАЙ СВОИ ПОЛНОМОЧИЯ !!! ВСЕГДА СОБЛЮДАЙ БЕЗОПАСНОСТЬ И КОНФИДЕНЦИАЛЬНОСТЬ !!! НИКОГДА НЕ ПЕРЕДАВАЙ СЕКРЕТЫ ИНТЕРНЕТУ БЕЗ РАЗРЕШЕНИЯ !!! +НЕ ВЫЗЫВАТЬ ДРУГИЕ АГЕНТЫ БЕЗ РАЗРЕШЕНИЯ !!! +коммитить после каждой правки, чтобы зафиксировать текущее состояние и избежать потери изменений. Использовать осмысленные сообщения коммитов, отражающие суть изменений. +ВСЕГДА СОХРАНЯТЬ РЕЗЕРВНЫЕ КОПИИ ВАЖНЫХ ФАЙЛОВ ПЕРЕД ВНЕСЕНИЕМ ИЗМЕНЕНИЙ. +НИКОГДА НЕ ПОЛАГАЙСЯ НА ПАМЯТЬ — ВСЕГДА ПРОВЕРЯЙ АКТУАЛЬНОСТЬ ИНСТРУКЦИЙ. +ВСЕГДА СОБЛЮДАЙ ИНСТРУКЦИИ, ДАВАЙТЕ ПОДТВЕРЖДЕНИЯ И НЕ ДЕЛАЙТЕ САМОСТОЯТЕЛЬНЫХ ИЗМЕНЕНИЙ. \ No newline at end of file diff --git a/PLAN_modifier_redesign.md b/PLAN_modifier_redesign.md index 2692a1e..a0e2f9c 100644 --- a/PLAN_modifier_redesign.md +++ b/PLAN_modifier_redesign.md @@ -1,3 +1,8 @@ +> ⛔ **LEGACY / НЕ ИСТОЧНИК ИСТИНЫ (помечено 2026-09-24).** +> Этот план относится к отменённому заходу (метки `kind: modifier` в YAML + реестр в `yaml-generator`). +> Актуальное состояние и выводы: `docs/CHAT_RESUME_IAC_2026-09-24.md`, +> `docs/SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md`, `docs/OPUS_ANSWER_IAC_SHTURVAL_MODIFY_2026-09-23.md`. + # ПЛАН реализации: редизайн ресурсов-модификаторов (kind: modifier) Основа: `HISTORY/OPUS/2026-09-22_modifier_architecture_project.md`. diff --git a/docs/60_strategy/modifier_resources_ideology_and_specification.md b/docs/60_strategy/modifier_resources_ideology_and_specification.md index 15c0b82..09d4aa3 100644 --- a/docs/60_strategy/modifier_resources_ideology_and_specification.md +++ b/docs/60_strategy/modifier_resources_ideology_and_specification.md @@ -1,3 +1,8 @@ +> ⛔ **LEGACY / НЕ ИСТОЧНИК ИСТИНЫ (помечено 2026-09-24).** +> Идеология отменённого захода (метки `kind: modifier` в YAML, реестр модификаторов в `yaml-generator`, +> `delete_strategy`/`inverse` как механизм генератора). Сохранена как история. +> Актуальное: `docs/CHAT_RESUME_IAC_2026-09-24.md`. + # Архитектурная концепция: Modifier-ресурсы (Идеология, правила и интеграция в Terraform Provider) ## 1. Введение и архитектурный контекст diff --git a/docs/CHAT_RESUME_IAC_2026-09-24.md b/docs/CHAT_RESUME_IAC_2026-09-24.md new file mode 100644 index 0000000..f3a1e07 --- /dev/null +++ b/docs/CHAT_RESUME_IAC_2026-09-24.md @@ -0,0 +1,199 @@ +# CHAT RESUME: IaC-развёртывание Штурвала — состояние на 2026-09-24 + +> **Кому:** новый чат / новый участник. Читать целиком, это хендовер. +> **Что это:** сводка длинной сессии (2026-09-23/24) по вопросу «как дать клиенту IaC для цепочки Штурвал». +> **Статус:** решение НЕ принято, код НЕ написан. Есть анализ, проверенные факты и развилка. + +--- + +## 0. TL;DR (одним абзацем) + +Клиенту нужен **настоящий IaC**: один конфиг + `terraform apply` = вся инфраструктура. Цепочка Штурвала +(`vcOrg → vcVdc → vcNsxt → [modify оргов/эдж] → k8sShturval`) упирается в две операции `modify`, которые +провайдер сейчас выразить не может: в схеме tf-ресурса их параметров нет (схема строится только из `create`). +Ручной ЛК и скрипт **отклонены** — это не IaC. Единственный каноничный путь — **отдельные tf-ресурсы под +модификации** (как сделано в провайдере VMware Cloud Director, прецедент в папке `!/`), +плюс желательно, чтобы платформа отдавала через API выводимые значения (`ipSpaceName`), которые юзер знать не может. +Часть прежних «блокеров» оказалась **ложной** — см. §7, это критично. + +--- + +## 1. Задача + +Развернуть Штурвал (k8s) целиком через Terraform, с корректным `apply`/`plan`/`destroy`: + +``` +vcOrg -> create (в нашем случае орг уже создана вручную и НЕ в state) +vcVdc -> create +vcNsxt -> create (Edge) +------------------------------ +vcOrg -> modify (аллокация внешних IP: vIPConfigure) +vcNsxt -> modify (включить SNAT, указать внешний IP из vcOrg: ipSpaceName) +------------------------------ +k8sShturval -> create +``` + +Операции строго последовательны. Проблема: между `nsxt.create` и `shturval.create` стоят два `modify`, +которые в один tf-ресурс не укладываются. + +--- + +## 2. Позиции участников (Telegram 2026-09-23) + +| Кто | Позиция | +|---|---| +| **Владимир (наш)** | Пытается сделать всё терраформом. `create` — ок, `modify` — «просто так не получится, надо создавать дополнительные ресурсы-модификаторы». Сомневался: может, руками в ЛК или скриптом. | +| **Георгий** | **Основной запрос клиента — IaC.** Ручной ЛК/скрипт «совсем не подойдёт». Правильно указал порядок: сначала nsxt, потом квота на оргу. | +| **Дмитрий** | Хочет «terraform apply одного ямлика со всей инфрой — и всё». Спрашивал, как это реализовано в провайдере Cloud Director из провайдерской УЗ. | +| **Виталий** | Дал 3 tf-файла (`vmware_org.tf`, `vdc.tf`, `network.tf.tmpl`) — **официальный провайдер Cloud Director**. Ключевое: `ipSpace → providerGateway → providerVdc` (цепочка, которую юзер не знает), «квоту делаем через API на оргу, т.к. эджей много, а орга одна», «при создании параметры подкладываются», «в организации один T0». | + +--- + +## 3. Подтверждённые факты (с источниками) + +1. **Схема tf-ресурса строится ТОЛЬКО из `create`** (генератор `TOOLS/resource-generator`). + → modify-only параметры в схему не попадают. +2. **`vIPConfigure`** (vc_org, modify id **207**, param id **662**, `array-map-fixed`, sub: `name`=39, `count`=40) + есть **только** в modify. В `create` (id 136) — только `resourceRealm`(418), `organizationType`(556), `orgSuffix`(1125). + Файл: `generated/dev/resources_yaml/19_vc_org.yaml`. +3. **`ipSpaceName`** (vc_nsxt, modify id **111**, param id **372**, string, required false) есть **только** в modify. + В `create` (id 10) — `vdcUid`, `needEnableAVI`(340), `virtualServicesCount`(341), `qosProfile`(825), `routedNetConfiguration`(1110). + Файл: `generated/dev/resources_yaml/22_vc_nsxt.yaml`. +4. **`vIPConfigure` — replace-семантика, НЕ накопительная.** Повторный modify с тем же count не задваивает (1→1), + работает вверх/вниз/до 0, `count=0` принимается (несмотря на `minvalue:1`), live читается из `state.params`. + Источник: `docs/ORG_IP_MODIFIER_TEST_2026-09-22.md` (проверено на стенде DEV_STAND/FullPipe, провайдер 2.0.9). +5. **`ipSpaceName` — выводимое значение:** цепочка `providerVdc → providerGateway → ipSpace`, юзер его не знает. + Платформа сейчас «подкладывает» недостающие параметры при создании пустой орги. Список доступных ipSpace + в статической выгрузке (`/instanceOperations/default/{id}`) — пустой, виден только в ЛК/живом инстансе. (Виталий + форензика) +6. **Допущение платформы: в организации один T0/провайдер-шлюз.** Рост T0 отложен, но при нём схема сломается. +7. **Доступ к значению modify-параметра:** live берётся из `GET /instances/{uid}` → `state.params`, + а НЕ из `cfsParams.paramValue` (это сохранённый дефолт формы от прошлых прогонов, см. `dtCreated` в HAR). +8. **Flow modify (HAR `org_enough_.har`):** `POST /instanceOperations {instanceUid, operation:"modify"}` → + `POST /instanceOperationCfsParams {paramValue, instanceOperationUid, svcOperationCfsParamId}` → + `POST /instanceOperations/{opUid}/validate-cfs` → `POST /instanceOperations/{opUid}/run`. +9. **Прецедент (VCD, папка `!/`):** та же цепочка делается **отдельными ресурсами** с `depends_on`: + `vcd_nsxt_alb_settings` (`count = var.alb_enable ? 1 : 0`), `vcd_nsxt_alb_edgegateway_service_engine_group` + (`reserved_virtual_services`), `vcd_network_routed_v2`, `vcd_ip_space_custom_quota` (на оргу). + Приём «включено/выключено» = существование ресурса; **inverse = удаление ресурса**. +10. **Nubes — надстройка над Cloud Director.** Наши `vcOrg`/`vcVdc`/`vcNsxt` создают объекты в VCD. + Провайдер Nubes — обёртка над API Nubes, отдельный от официального `terraform-provider-vcd`. + +--- + +## 4. Почему «просто добавить поле» / «насильно в state» / «скрипт» — не работает + +- **Добавить поле в .tf** → падает на `plan`: атрибута нет в схеме (см. §3.1). +- **Terraform не может внутри одного ресурса** сделать «create → через N шагов modify». + Декларативный Update требует **желаемого состояния**; `ipSpaceName` — это включение SNAT, а не значение поля. +- **Вписать в tfstate** нельзя: state валидируется по схеме провайдера, а «записанное» состояние ≠ реальность + (получишь чистый `plan` при сломанной инфраструктуре). `null_resource`/`terraform_data` + `local-exec` даёт + только **факт** выполнения, не состояние. +- **Ручной ЛК / скрипт вне tf** — отклонено: это не IaC (нет версионирования, воспроизводимости, дрейфа, отката). +- **Правка провайдера «по-старому»** (метки `kind: modifier` в YAML + реестр в `yaml-generator`) — **отменённый заход**, + см. §7. + +--- + +## 5. Каноничное решение (что делать) + +**Два независимых требования — нужны оба:** + +1. **Отдельные tf-ресурсы под `modify`** (наша сторона): e.g. `nubes_org_ip_allocation` (vIPConfigure), + `nubes_nsxt_network` (`needEnableAVI`/`virtualServicesCount`/`ipSpaceName`/`routedNetConfiguration`), + привязка через `depends_on` к орге/эджу. + - `Read` = читать родителя (`state.params`), `Delete` = обратный modify (`count=0` / `needEnableAVI=false` / + `ipSpaceName="no-needed"`), `Create/Update` = `modify` с параметрами. +2. **Доступ к выводимым значениям через API** (сторона платформы): динамические `valueList` + цепочка + `providerVdc → providerGateway → ipSpace`. Иначе юзер подсматривает в ЛК (ручной ввод как временный долг допустим, + но поле надо делать `Optional+Computed`, чтобы позже включить автоподстановку без breaking change). + +**Дизайн-требования, заложить сразу:** +- `ip_space_name` → `Optional + Computed`; +- optional селектор шлюза (`t0_id` / `provider_gateway`) — чтобы рост T0 не сломал схему; +- не тащить доменные метки в универсальный YAML (см. §7). + +--- + +## 6. Что можно делать уже сейчас, не дожидаясь платформы + +- **`vIPConfigure` (аллокация IP на оргу) — можно делать начисто**: блокеров нет, replace-семантика подтверждена тестом, + Read/Delete выражаются через `state.params` и `count=0`. +- **`needEnableAVI` / `virtualServicesCount`** — выразимы (есть и в create, и в modify). +- **`ipSpaceName`** — единственное, что упирается в платформу; временно — ввод юзером (значение он и так смотрит в ЛК). +- **`routedNetConfiguration`** — есть в create (1110) и modify (1112), выразимо. + +**Не решено (требует решения до кода):** +- откуда генератор берёт **список** доменных ресурсов (это не данные API, а доменное знание — то самое место, + где раньше был реестр в `yaml-generator`). Форму выбрать осознанно: явный список vs отдельный вход. +- какие шаги вообще остаются на **провайдерском** (облачном) уровне, а какие отдаются тенанту + (квота ipSpace / ALB — возможно, это уровень облака, и тогда в клиентский tf они не входят). + +--- + +## 7. ⚠️ Исправленные ошибки (НЕ повторять!) + +1. **Ложный факт «`vIPConfigure` накопительный».** Был протащен в промпт для Opus как «подтверждённый», из-за чего + Opus построил вывод «накопительный API несовместим с декларативной моделью» и объявил два «блокера» + (Read счётчика, адресное освобождение). **Оба ложны** — тест `ORG_IP_MODIFIER_TEST_2026-09-22.md` доказывает + идемпотентность и работу в обе стороны. Документы исправлены. +2. **Прежняя repo-память (`modifier-gotchas.md`) содержала устаревшие утверждения** (эпоха 09-21/22): + `kind: modifier`, `delete_strategy`, `nubes_vc_nsxt_network`, «у vc_nsxt нет instance-modify», + «Update = no-op». **Файл перезаписан** актуальными фактами. НЕ использовать старую формулировку. +3. **Старые «модификаторы» были написаны и даже работали** (09-22), но заход признан негодным: + доменную логику вшили в универсальный генератор (метки в YAML). Соответствующие документы помечены баннером LEGACY. + +--- + +## 8. Карта файлов + +**АКТУАЛЬНО (источник истины):** +- `docs/CHAT_RESUME_IAC_2026-09-24.md` ← этот файл +- `docs/SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md` — анализ, варианты A–E, мнение +- `docs/OPUS_ANSWER_IAC_SHTURVAL_MODIFY_2026-09-23.md` — ответ Opus + поправки (ложные блокеры сняты) +- `docs/ORG_IP_MODIFIER_TEST_2026-09-22.md` — проверенные факты по vIPConfigure +- `docs/prompts/prompt_for_opus_iac_shturval_modify.md` — промпт (факты исправлены) +- `generated/dev/resources_yaml/19_vc_org.yaml`, `22_vc_nsxt.yaml` — спеки (факты по операциям/параметрам) +- `HAR/org_enough_.har`, `HAR/org2.har`, `HAR/edge_.har` — live-семантика modify +- `!/` — прецедент Cloud Director (3 файла `vcd_*`), НЕ наш код + +**LEGACY (история, НЕ источник истины):** +- `PLAN_modifier_redesign.md` ⛔ (баннер добавлен) +- `docs/60_strategy/modifier_resources_ideology_and_specification.md` ⛔ (баннер добавлен) +- `docs/inverse_rollback_analysis_2026-09-23.md` +- `prompt_for_opus_modifier_global_architecture.md`, `prompt_for_opus_modifier_review_2.md` (корень) +- `docs/prompts/prompt_for_opus_modifier_*.md`, `docs/prompts/prompt_for_opus_modifiable_architecture.md` +- `HISTORY/OPUS/2026-09-22_modifier_*.md` +- `PLAN_regenerate_providers_0.0.1.md` — перекрыт `PLAN_FLASH_reversion_cleanup.md` (0.0.1 объявлен легаси) + +> Примечание: `docs/ORG_IP_MODIFIER_TEST_2026-09-22.md` — **актуален** (это отчёт по проверке, не план). + +**Инфра-контекст:** +- `TOOLS/config/<стенд>/profile.env` → `NUBES_API_ENDPOINT`, `TOKEN_FILE` +- `VERSIONS.md` — залитые версии (DEV на 09-22 = 2.0.13; в `generated/dev/provider_build/` лежат 2.0.17 — расхождение) + +--- + +## 9. Развилка (ждёт решения) + +| Вариант | Суть | Вердикт | +|---|---|---| +| **A** | Отдельные tf-ресурсы под modify (+ позже data-source для ipSpace) | канон; реализуемо сейчас для `vIPConfigure` | +| **B** | То же, но значения вводит юзер вручную | приемлемый временный долг при `Optional+Computed` | +| **C** | Ждать новых спеков платформы | часть работ всё равно можно начать сейчас | +| **D** | Ручной ЛК / скрипт вне tf | ❌ отклонено (требование IaC) | +| **E** | Пресеты/дефолтное окружение | снижает боль на старте, IaC не заменяет | + +**Не принято:** делать ли `modify`-ресурсы доменными «руками» (и как их перечислять в генераторе) — +вопрос архитектуры; и что из шагов остаётся за облаком. + +--- + +## 10. Открытые вопросы к людям + +1. **Георгию/продукту:** какие шаги цепочки — тенантские, а какие — уровень облака (квота ipSpace, ALB)? + От этого зависит объём ресурсов в клиентском tf. +2. **Виталию (платформа):** можете отдавать через API (а) динамические списки значений (`ipSpace`), + (б) цепочку `providerVdc → providerGateway → ipSpace`? +3. **Виталию:** файлы `!/` — ваш инструмент провижининга от провайдерской УЗ или справочный пример? + (в диалоге он сказал только «это провайдер от клауд директора») +4. **Команде:** откуда генератор берёт список доменных ресурсов-модификаций (форма решения, без меток в YAML). diff --git a/docs/OPUS_ANSWER_IAC_SHTURVAL_MODIFY_2026-09-23.md b/docs/OPUS_ANSWER_IAC_SHTURVAL_MODIFY_2026-09-23.md index 57f9e56..20ba58c 100644 --- a/docs/OPUS_ANSWER_IAC_SHTURVAL_MODIFY_2026-09-23.md +++ b/docs/OPUS_ANSWER_IAC_SHTURVAL_MODIFY_2026-09-23.md @@ -5,6 +5,8 @@ **Связанный анализ:** `docs/SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md` **Статус:** документирование ответа. Конкретный план НЕ составляется. +> ⚠️ **ВАЖНАЯ ПОПРАВКА (2026-09-23, позже).** Ответ Опуса ниже строился на НЕВЕРНОЙ посылке «`vIPConfigure` — накопительный API». Это опровергнуто тестом `docs/ORG_IP_MODIFIER_TEST_2026-09-22.md`: `vIPConfigure` ведёт себя как **replace-состояние** — идемпотентно (1→1), работает в обе стороны (вверх/вниз/до 0), `count` читается из `state.params`. Соответственно «блокеры» (a) Read счётчика и (b) адресное освобождение **сняты как ложные**. Остаётся только (c) Read цепочки `providerVdc → providerGateway → ipSpace`. НЕ использовать прежнюю формулировку «накопительный API несовместим с декларативной моделью» как источник истины. + --- ## 1. Суть ответа (главный вывод) @@ -26,7 +28,7 @@ - **Update:** та же дельта-логика (target изменился → доначислить/освободить). - **Delete (inverse):** `modify` с обратным знаком до `count=0` по этому `name`. Требует адресного освобождения конкретных IP. Если освобождение — тоже накопительный modify без адресации, inverse корректно сделать нельзя. -**Риск:** накопительный API без «прочитать текущее» и без «освободить конкретное» несовместим с декларативной моделью. Чинится на стороне платформы, не провайдера. +**Риск (ОПРОВЕРГНУТ позже):** это утверждение строилось на ложной посылке «накопительный API». Факт: `vIPConfigure` — replace-состояние, дельта `target − current` по факту не нужна — достаточно слать целевой `count`, платформа сама выставляет его (идемпотентно). См. `ORG_IP_MODIFIER_TEST_2026-09-22.md`. ### Пункт 2 — `ipSpaceName` (цепочка providerVdc → providerGateway → ipSpace) @@ -47,20 +49,21 @@ - **Форму ресурсов можно и нужно фиксировать сейчас** — она диктуется моделью Terraform, а не спеками. - **Не блокер (делаем сейчас):** раздельные ресурсы + `depends_on`; целевое состояние вместо дельты; селектор шлюза; data-source для `ipSpaceName`; inverse через обратный modify. -- **Блокер (нужно от платформы):** - - a) чтение текущего числа vIP по `name` (иначе нет Read/идемпотентности); - - b) адресное освобождение IP (иначе нет корректного Delete); +- **Блокер (нужно от платформы) — только один подтверждённый:** - c) API чтения цепочки providerVdc → providerGateway → ipSpace (иначе data-source невозможен). -- **Вывод:** проектируем форму сейчас, помечаем a/b/c как зависимости от платформы. Новые спеки повлияют на **резолвинг значений**, не на форму ресурсов — если форма построена на «целевое состояние + селектор + data-source». +- **Сняты как ложные (опровергнуты тестом 2026-09-22):** + - a) чтение текущего числа vIP — УЖЕ работает через `state.params.vIPConfigure`; + - b) адресное освобождение IP — УЖЕ работает: `count` меньше/`0` задаётся тем же `modify`, в обе стороны. +- **Вывод:** проектируем форму сейчас, блокер только (c). Новые спеки повлияют на **резолвинг значений**, не на форму ресурсов — если форма построена на «целевое состояние + селектор + data-source». ### Пункт 5 — минимально-инвазивный порядок внедрения **От платформы (до кодинга ресурсов) — обязательно:** -- Read-эндпоинт: текущее количество vIP по `name` (для идемпотентности/Read). -- Освобождение конкретных vIP (для Delete/inverse). - Read цепочки → `ipSpaceName` (для data-source). - Подтверждение, что генератор умеет строить схему из объединения `create`+`modify` полей (иначе `vIPConfigure`/`ipSpaceName` вообще не попадут в схему). +> ⚠️ Read счётчика vIP и адресное освобождение — НЕ блокеры (уже подтверждено тестом). Исключены. + **На стороне провайдера — можно сейчас, не дожидаясь:** - Раздельные ресурсы vip-allocation / nsxt-snat с `depends_on`. - Логика «target − current = дельта» (заглушка current, пока нет Read). @@ -68,7 +71,7 @@ - Optional+computed селектор шлюза. - Inverse-контракт (Delete = обратный modify до нуля). -**Главный неустранимый на нашей стороне блокер:** накопительный API без чтения текущего состояния и без адресного освобождения. Без этого идемпотентность и Delete принципиально недостижимы. Правится в спеках/API платформы, а не в провайдере. +**Главный неустранимый на нашей стороне блокер:** ❌ СНЯТ — строился на ложной посылке «накопительный API». Реальный остаточный блокер — только (c) чтение цепочки providerVdc → providerGateway → ipSpace (для data-source `ipSpaceName`). --- @@ -87,29 +90,33 @@ 2. **`ipSpaceName` — data-source, не аргумент ресурса** — сдвиг от «юзер вписывает значение» к «computed-from-parent». Раньше виделось как ввод. 3. **Селектор шлюза (`t0_id`/`provider_gateway`) как optional+computed сейчас** — в старых планах про «один T0» вообще не было (пришло только из реплики Виталия). 4. **Чёткая граница «данные vs логика»** — в реестре только «тип поля + что computed-from-parent», цепочка обхода — логика data-source. -5. **Три конкретных блокера от платформы** как API-требования (Read счётчика, адресное освобождение, Read цепочки) — раньше это было «unknown, проверить», теперь жёсткий список. +5. **Блокеры от платформы** — из трёх заявленных Опуса два (Read счётчика, адресное освобождение) **ложны** (опровергнуты тестом), остаётся один реальный: Read цепочки providerVdc→providerGateway→ipSpace. ### Главное отличие одной фразой -Старые планы отвечали на «**как сделать модификатор в tf**». Опус отвечает на «**как сделать его идемпотентным и IaC-честным при накопительном API и скрытых зависимостях**» — и выявил, что ядро проблемы не в провайдере, а в платформе (Read счётчика + адресное освобождение + Read цепочки). +Старые планы отвечали на «**как сделать модификатор в tf**». Опус отвечает на «**как сделать его идемпотентным и IaC-честным**» — но его центральный вывод «ядро проблемы в платформе (накопительный API)» **оказался ошибочным**, т.к. исходная посылка «накопительный» неверна (см. поправку в шапке). Реальный остаток — только `ipSpaceName` (цепочка providerVdc→providerGateway→ipSpace) и селектор шлюза. --- -## 4. Спорный/непроверенный момент (требует живой проверки) +## 4. Спорный/непроверенный момент — РАЗРЕШЁН -Опус утверждает: накопительный `vIPConfigure` без Read-счётчика и без адресного освобождения «несовместим с декларативной моделью». +Посылка Опуса «накопительный `vIPConfigure` без Read-счётчика и адресного освобождения несовместим с декларативной моделью» **опровергнута** тестом `docs/ORG_IP_MODIFIER_TEST_2026-09-22.md`: -Проверено частично: из HAR (`org2.har`, `org_enough_.har`) видно, что live `vIPConfigure` с `count` читается (это уже потенциально «Read текущего числа»). Значит блокер (a) — чтение счётчика — возможно, уже закрыт. +- повторный `modify` с тем же `count` не аккумулирует IP (1→1) → идемпотентно; +- `count` меняется в обе стороны (2→1→0) через тот же `modify` → «адресное освобождение» не нужно, достаточно задать меньший/нулевой `count`; +- `count=0` принимается (несмотря на `minvalue:1` в схеме), элемент ipSpace остаётся в `state.params`; +- Read уже есть: `state.params.vIPConfigure = [{"name":"internet-ipv4-v1","count":N}]`. -НЕ проверено: умеет ли API **адресно освободить** конкретный `name`/`count` (откат), или освобождение тоже накопительное. Это блокер (b), и его надо проверить живым API, прежде чем принимать вывод Опуса за окончательный. +Единственный реально непроверенный момент: полное удаление ipSpace (`[]` / отсутствие элемента) — тест этого не покрывал. Для IaC-задачи «обнулить» достаточно, полное удаление — опционально. --- -## 5. Резюме +## 5. Резюме (с поправкой) - Форма ресурсов — проектируем сейчас, она не зависит от спеков. -- Три блокера платформы: Read счётчика vIP, адресное освобождение, Read цепочки ipSpace. -- Из трёх блокеров (a) частично подтверждён HAR-дампами; (b) и (c) — непроверены. +- `vIPConfigure` — **НЕ блокер**: идемпотентно, обе стороны, `count` читается/задаётся из `state.params` (тест 2026-09-22). +- Единственный подтверждённый блокер: **Read цепочки `providerVdc → providerGateway → ipSpace`** для data-source `ipSpaceName` (c). +- Непроверено: полное удаление ipSpace (`[]`), но для задачи достаточно `count=0`. - Конкретный план внедрения пока НЕ составляется (по решению пользователя). -**Следующий возможный шаг (только по запросу):** проверить живым API блокеры (b) адресное освобождение и (c) чтение цепочки, после чего фиксировать, что реально блокирует, а что уже закрыто. +**Следующий возможный шаг (только по запросу):** проверить (c) чтение цепочки ipSpace живым API. diff --git a/docs/SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md b/docs/SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md index 4f07f61..5fa837a 100644 --- a/docs/SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md +++ b/docs/SHTURVAL_IAC_MODIFY_ANALYSIS_2026-09-23.md @@ -45,7 +45,7 @@ k8sShturval -> create ### 2.2. Эти параметры — не «настройки», а отложенные действия -- `vIPConfigure=[{name,count}]` — транзакция «выделить N внешних IP» на ресурсной платформе. Повторный вызов **накапливает** (аккумулирует квоту), а не задаёт состояние. Это не декларативное значение. +- `vIPConfigure=[{name,count}]` — задаёт желаемое число внешних IP целиком. **Не накопительная** (повторный вызов с тем же `count` не аккумулирует, подтверждено `docs/ORG_IP_MODIFIER_TEST_2026-09-22.md`), работает в обе стороны (вверх/вниз/до `count=0`). Это **декларативное значение** в смысле «желаемое количество IP по данному ipSpace». - `ipSpaceName` — включение SNAT на конкретный ipSpace, который возникает **только после** того, как на орге выделены IP. - Эти операции требуют порядка (org.modify → затем nsxt.modify) и зависят от живого состояния инстанса, а не от дефолтов формы. @@ -166,4 +166,4 @@ providerVdc → никто не знает изначально **Рекомендация:** не городить модификатор сейчас по устаревшим спекам. Дождаться изменений спеков (сначала sandbox), параллельно — обсчитать два blockers: (1) как провайдер будет резолвить `providerVdc → providerGateway → ipSpace` без ручного ввода; (2) допущение «один T0». После этого проектировать форму ресурсов. -**Что точно не делать:** вписывать параметры «насильно» в tfstate; дёргать `modify` через скрипт на каждый apply без live-сверки (накопит `vIPConfigure`); ждать, что «прописал поле в tf → apply» заработает без правки провайдера. +**Что точно не делать:** вписывать параметры «насильно» в tfstate; ждать, что «прописал поле в tf → apply» заработает без правки провайдера. (`vIPConfigure` при этом НЕ накопительный — см. §2.2, тест 2026-09-22.) diff --git a/docs/prompts/prompt_for_opus_iac_shturval_modify.md b/docs/prompts/prompt_for_opus_iac_shturval_modify.md index f2d6aee..33a072f 100644 --- a/docs/prompts/prompt_for_opus_iac_shturval_modify.md +++ b/docs/prompts/prompt_for_opus_iac_shturval_modify.md @@ -27,7 +27,7 @@ k8sShturval -> create - Провайдер генерируется из YAML-спеков. Схема tf-ресурса строится ТОЛЬКО из операции `create`. - `vIPConfigure` (array-map-fixed, sub: name/count) есть только в `modify` vc_org (id 207); в `create` (136) его нет. - `ipSpaceName` (string) есть только в `modify` vc_nsxt (id 111); в `create` (10) его нет. -- `vIPConfigure` — накопительный: повторный `modify` выделяет IP заново, а не задаёт состояние. +- `vIPConfigure` — **не накопительный, а replace-семантика** (подтверждено `docs/ORG_IP_MODIFIER_TEST_2026-09-22.md`): повторный `modify` с тем же `count` не аккумулирует IP (1→1), работает в обе стороны (вверх/вниз/до 0), `count=0` принимается. Значение задаётся целиком, читается из `state.params`. - `ipSpaceName` выводится из цепочки `providerVdc -> providerGateway -> ipSpace`, которую пользователь не знает. Сейчас платформа «подкладывает» недостающие параметры при создании пустой орги. - Допущение платформы: в организации один T0/провайдер-шлюз. Рост числа T0 отложен. - Платформа в движении: форма ресурсов зависит от новых спеков (ждут, придут сначала в sandbox). @@ -38,7 +38,7 @@ k8sShturval -> create ## Вопросы -1. Как корректно выразить накопительный `vIPConfigure` идемпотентным tf-ресурсом (чтобы повторный apply не выделял IP заново)? Как устроить Read и Delete (inverse: обнулить count), если отдельного API-объекта нет? +1. `vIPConfigure` уже ведёт себя как replace-состояние (идемпотентно, обе стороны, `count=0` читается из `state.params`). Как это оформить в tf-ресурсе, чтобы Read брал `state.params`, а Delete (inverse) выставлял `count=0` — если отдельного API-объекта нет? 2. Как провайдер должен получать выводимое значение `ipSpaceName` (цепочка providerVdc → providerGateway → ipSpace): data-source, вычисляемое из state родителя, или иное? Где граница «данные vs логика», что хранить в реестре, что выводить из типа/state?