Files
tf_provider/docs/60_strategy/provider_philosophy.md
T
Repinoid 57e7d4d077 docs(arch): принцип секретов подресурсов + чем postgres отличается от mariadb
В раздел 6 (Подресурсы) добавлен подраздел про секреты, рождаемые операцией
подресурса:
- проблема: vault_secrets родителя — Computed, обновляется только в Read, поэтому
  после create_user пароль недоступен в том же apply (Invalid index);
- принцип: пароль должен быть выходом самого подресурса, не читаться из родителя;
- как привязано к данным, а не хардкодом: признак в YAML-спеке (по аналогии с
  suspend_on_destroy_default), условный блок в общем шаблоне;
- факт из спеков: postgres = пароль генерит платформа (нужен выход), mariadb =
  пароль задаёт пользователь на входе (выход не нужен).
2026-10-01 17:06:52 +03:00

13 KiB
Raw Blame History

Terraform Provider Development Strategy & AI Integration

1. Vision: "The Helpful Kitchen Assistant"

The provider should not just be a silent executor of commands. It should act as an intelligent assistant for users of all skill levels (the "Cook" persona). It must provide context, warnings, and advice before any potentially destructive or wasteful actions are taken.

2. Advanced Pre-Apply Logic

To prevent "bad applies" and incomplete infrastructure states, the provider will implement:

A. Context-Aware Validation (Scanning the Cloud)

  • Data Sources as Sensors: Use Data Sources not just for referencing existing resources, but as "sensors" to understand the current cloud state during terraform plan.
  • Pre-emptive Warnings: Compare the proposed plan against current cloud limits, existing resource names, and regional availability.
  • Example: Trigger a warning if a user is creating a 6th bucket while 5 existing ones are empty.

B. Cascading & Logical Validation (Deep Validation)

  • Attribute Inter-dependency: Check compatibility between linked resources (e.g., App vs DB versions, S3 permissions vs CDN requirements).
  • Early Termination: If Resource A in a chain is logically "broken" or suboptimal, the provider should error out or warn on the entire chain before apply begins.

3. Human-Centric Output & AI Insights

  • Standardized Info: terraform plan should output human-readable summaries of what's already in the cloud, not just what's being changed.
  • AI-Driven Advice:
    • The provider outputs a structured JSON state.
    • An AI Agent (Sub-chef) analyzes this JSON.
    • Result: "Hey, I noticed you're creating a DB in Region A but your VMs are in Region B. This will cause latency. Want to fix it?"

4. Implementation via Taffy API Specifics

  • Lifecycle Utilization: Leverage the 3-step Taffy lifecycle (Operation -> Parameters -> Run).
  • Validation Step: Use the /validate-cfs API endpoint during the Terraform Plan or Create phase (before the final Run) to ensure the cloud accepts the parameters without actually committing the change.

5. Reliability & Uncertainty Tracking

  • All documentation and internal agent logic should use Confidence Scores (e.g., [CONFIDENCE: 85%]).
  • Explicitly mark [UNCERTAINTY] tags for deprecated API features or areas where documentation contradicts observed behavior (from HAR/Traffic analysis).

This document serves as the architectural north star for the project.

6. Подресурсы (subresource) и поведение Terraform

Зачем нужен ForceNew

Для подресурсов вроде create_user, delete_user, create_database часто нет операции modify в API. Это значит, что при изменении ключевых полей (например, username или dbName) мы не можем обновить объект на месте — только удалить и создать заново.

ForceNew — это стандартный механизм Terraform: изменение таких полей приводит к замене ресурса (Delete + Create). Это предотвращает ложные обновления, когда Terraform считает, что всё изменилось, а в API реально ничего не выполнено.

Правило для генерации подресурсов

  • Если у подресурса нет операции modify, то все его параметры считаются ForceNew.
  • Если modify есть, то ForceNew получают параметры, которые участвуют в идентификации/удалении (ключи, по которым ресурс можно уникально определить).

Итоговое поведение

  • Изменение ключевых параметров подресурса => ресурс заменяется.
  • Это соответствует возможностям API и сохраняет корректность состояния Terraform.

Секреты, рождаемые операцией подресурса (принцип и практика)

Проблема (наблюдаемая, 2026-10-01): у части сервисов секрет (пароль пользователя БД) генерируется платформой внутри операции create_user, а доступен он не в выходе подресурса, а в vault_secrets родительского инстанса. При этом vault_secrets родителя — Computed-атрибут, который обновляется только в Read родителя (перечитывание облака на refresh/повторном apply), а не в конце Create подресурса. Следствие: внутри одного apply после create_user пароль нельзя прочитать — vault_secrets["users"] ещё пуст, и обращение к нему даёт Invalid index.

Принцип (правило для генератора): секрет, который порождает операция подресурса, должен становиться выходом самого подресурса сразу по завершении его Create, а не читаться потребителем из родителя. Потребитель берёт пароль из nubes_<svc>_<sub>.<sub>.password, и зависимость по графу Терраформа автоматически разносит создание по времени.

Как это «прописано для postgres», а не хардкод в шаблоне. В общий шаблон подресурса (TOOLS/resource-generator/internal/templates/subresource.go) НЕ зашивается имя сервиса. Признак «у этого подресурса-пользователя пароль генерируется платформой» должен приходить из данных спека (YAML), как уже сделано для suspend_on_destroy_default / adopt_existing_on_create_default (раздел 7). В шаблоне появится условный блок, срабатывающий только при наличии этого признака.

Различия сервисов (факт из спеков):

Сервис Пароль пользователя Что нужно
PostgreSQL (90) генерирует платформа → vault_secrets["users"] выход пароля у postgres_user из Vault по завершении create_user
MariaDB (115) задаёт САМ пользователь (входной параметр password в create_user) ничего — пароль уже в манифесте, nubes_mariadb_user.x.password

Вывод: фича «выход пароля» нужна только подресурсам, у которых create_user не принимает пароль на входе (то есть где он auto-generated). Хардкодить перечень сервисов в шаблоне запрещено — признак декларируется в YAML-спеке сервиса.

7. Каноничная lifecycle-логика для сервисов с suspend/resume

Этот раздел обязателен для всех агентов, генераторов и разработчиков. Если в других документах встречаются старые правила (resume_if_exists, delete_mode), приоритет всегда у этого раздела.

Область действия:

  • Только instance-ресурсы, у которых API поддерживает suspend/resume.
  • Для сервисов без suspend действует обычная логика create/modify/delete.

Флаги:

  • adopt_existing_on_create (optional, default: false) — разрешает усыновление уже running ресурса при create/apply.
  • suspend_on_destroy (optional, default: true) — при destroy/удалении из манифеста выполнять suspend вместо удаления из state.

Правила по умолчанию:

  • Никакого неявного adopt/import: без adopt_existing_on_create=true найденный running ресурс считается конфликтом.
  • На destroy выполняется suspend по умолчанию (suspend_on_destroy=true).
  • Режим state-only допускается только при явном suspend_on_destroy=false.

8. Обязательные правила apply / plan / destroy / modify

Apply/Create (instance с suspend/resume)

  • Всегда проверить облако по resource_name перед create.
  • Если ресурс не найден в облаке или найден только в статусе deleted — всегда create.
  • Если ресурс в статусе suspend:
    • при adopt_existing_on_create=true и совпадении основных параметров — resume + adopt, и явное сообщение в plan/apply;
    • при adopt_existing_on_create=false — hard error (явно требовать включить флаг для resume/adopt);
    • при несовпадении — hard error с перечислением несовпавших ключей.
  • Если ресурс в статусе running:
    • при adopt_existing_on_create=true — adopt (import-поведение) с явным сообщением в plan;
    • при adopt_existing_on_create=false — hard error "resource already exists".
  • Если ресурс в статусе not created — hard error "проверьте ресурс в личном кабинете" (без auto-adopt/create).
  • Если ресурс в статусе creating/pending/failed — hard error.

Формат диагностик (обязательно)

  • Диагностики должны быть многострочными и читаемыми.
  • В тексте обязательно указывать:
    • итоговое решение (adopt/resume/error),
    • какой флаг повлиял (adopt_existing_on_create/suspend_on_destroy),
    • детализированные поля (resource_name, service_id, instance_uid, status, status_raw, operation_pending, operation_in_progress) отдельными строками.
  • Для конфликта resource already exists при adopt_existing_on_create=false диагностика обязана явно предлагать оба пути:
    • изменить resource_name, если нужен новый ресурс;
    • включить adopt_existing_on_create=true и повторить apply для импорта/усыновления существующего ресурса.

Destroy / удаление из манифеста (instance с suspend/resume)

  • Если suspend_on_destroy=true — выполнить suspend.
  • Если suspend_on_destroy=false — удалить только из Terraform state, без delete/suspend вызовов в API (осознанный override).

Modify

  • При diff по immutable/create-only параметрам — hard error (replace запрещён).
  • При diff только по mutable параметрам — выполнить modify.

Replace

  • Для сервисов с suspend запрещён любой implicit replace (delete+create).
  • Попытка replace должна завершаться ошибкой на этапе plan.

9. Контрольный список для реализации

Plan messages (обязательно)

  • Явно указывать обнаруженный cloud status: deleted/suspend/running/not created/creating.
  • Явно указывать, какой флаг повлиял на решение: adopt_existing_on_create или suspend_on_destroy.
  • Для веток resume и adopt показывать причину выбора действия.

Safety guards

  • Для suspend + mismatch не допускать auto-resume.
  • Для running без adopt_existing_on_create=true не допускать auto-adopt.
  • После resume/adopt выполнять read-back и обновлять state только по фактическому ответу API.

Терминология

  • resume_if_exists и delete_mode считаются legacy-терминами и не используются в новой логике.