docs(strategy): оркестрация взаимозависимых ресурсов и паттерн привязок

- complex_provisioning_workflow.md — цепочка vcOrg -> vcVdc -> vcNsxt -> Штурвал,
  включая modify-шаги и пошаговые модификации
- shturval_dev_provisioning_spec.md — точные параметры и ID операций DEV-стенда
  для цепочки развёртывания k8s_sthutrval_cluster
- terraform_association_pattern_and_pipeline.md — Resource Association Pattern
  (разделение сущности и ресурсов-привязок/модификаций)
This commit is contained in:
Repinoid
2026-09-18 18:44:36 +03:00
parent 106ddbe092
commit 0464a30642
3 changed files with 329 additions and 0 deletions
@@ -0,0 +1,138 @@
# Оркестрация взаимозависимых ресурсов и пошаговых модификаций (на примере Штурвал)
## 1. Контекст и проблематика
### Исходная последовательность развертывания
Для развертывания инстанса сервиса **Штурвал** требуется подготовить сетевую и виртуальную инфраструктуру, состоящую из трёх взаимозависимых компонентов:
1. `vcOrg/create` — создание виртуальной организации (vCD Org).
2. `vcVdc/create` — создание виртуального дата-центра (vDC) внутри организации.
3. `vcNsxt/create` — создание сетевого шлюза NSX-T (включение AVI, выделение 4 Service Engine).
4. `vcOrg/modify` — модификация организации (добавление 3 внешних IP-адресов).
5. `vcNsxt/modify` — повторная модификация NSX-T (включение SNAT, привязка выделенного `ipSpace` из `vcOrg`).
6. `Штурвал/create` — создание кластера сервиса «Штурвал».
### В чём архитектурная сложность для Terraform
В стандартной декларативной модели Terraform каждый ресурс управляется монолитно: один блок `resource` соответствует полному жизненному циклу одной сущности (Create -> Read -> Update -> Delete).
В описанном сценарии возникает **чередующаяся (interleaved) зависимость**:
* `vcOrg` должен существовать до `vcVdc` и `vcNsxt`.
* Но добавление IP-адресов в `vcOrg` (шаг 4) и настройка SNAT в `vcNsxt` (шаг 5) должны выполняться **после** создания базового `vcNsxt` (шаг 3).
* Штурвал (шаг 6) требует, чтобы и IP-адреса, и SNAT уже были применены.
Если пытаться упаковать шаги 1 и 4 в один ресурс `cloud_vc_org`, а шаги 3 и 5 — в один `cloud_vc_nsxt`, возникает тупик в графе зависимостей Terraform (Directed Acyclic Graph, DAG), либо API вернет ошибку из-за несвоевременного вызова параметров.
---
## 2. Архитектурное решение: Паттерн отдельных ресурсов модификации (Subresource / Action Pattern)
Канонический подход в экосистеме Terraform (аналогично `aws_security_group` + `aws_security_group_rule`, `aws_vpc` + `aws_route`) — **декомпозиция отложенных действий и привязок в отдельные управляемые ресурсы провайдера**.
### Структура ресурсов
1. **Базовые ресурсы жизненного цикла (Core Instances):**
* `cloud_vc_org` — создает и держит базу организации.
* `cloud_vc_vdc` — создает VDC внутри Org.
* `cloud_vc_nsxt` — создает NSX-T шлюз (AVI, 4 SE).
2. **Ресурсы отложенной конфигурации / модификаций (Action / Subresources):**
* `cloud_vc_org_ip_allocation` (или `cloud_vc_org_modify_ip`) — управляет пулом выделенных IP-адресов организации.
* `cloud_vc_nsxt_snat` (или `cloud_vc_nsxt_modify_snat`) — управляет правилом SNAT и связкой с `ip_space`.
3. **Целевой сервис:**
* `cloud_shturval` — разворачивает кластер Штурвал.
### Пример манифеста HCL
```hcl
# 1. Создание организации
resource "cloud_vc_org" "org" {
name = "demo-org"
}
# 2. Создание VDC
resource "cloud_vc_vdc" "vdc" {
name = "demo-vdc"
org_id = cloud_vc_org.org.id
}
# 3. Создание NSX-T (включение AVI и 4 Service Engine)
resource "cloud_vc_nsxt" "nsxt" {
name = "demo-nsxt"
vdc_id = cloud_vc_vdc.vdc.id
enable_avi = true
service_engines = 4
}
# 4. Модификация vcOrg: добавление 3 IP после готовности NSX-T
resource "cloud_vc_org_ip_allocation" "org_ips" {
org_id = cloud_vc_org.org.id
ip_count = 3
# Явная зависимость гарантирует выполнение после создания NSX-T
depends_on = [cloud_vc_nsxt.nsxt]
}
# 5. Модификация vcNsxt: включение SNAT с ipSpace из vcOrg
resource "cloud_vc_nsxt_snat" "snat" {
nsxt_id = cloud_vc_nsxt.nsxt.id
ip_space = cloud_vc_org_ip_allocation.org_ips.ip_space_id
enabled = true
}
# 6. Создание сервиса Штурвал
resource "cloud_shturval" "cluster" {
name = "demo-shturval"
vdc_id = cloud_vc_vdc.vdc.id
# Зависит от полной готовности сетевой связки
depends_on = [
cloud_vc_nsxt_snat.snat,
cloud_vc_org_ip_allocation.org_ips
]
}
```
Terraform самостоятельно строит идеальный граф исполнения:
```mermaid
graph TD
A[cloud_vc_org] --> B[cloud_vc_vdc]
B --> C[cloud_vc_nsxt]
C --> D[cloud_vc_org_ip_allocation]
D --> E[cloud_vc_nsxt_snat]
E --> F[cloud_shturval]
```
---
## 3. Интеграция в провайдер
### Реализация через генератор провайдера
Согласно политике репозитория (Immutability Policy), код конкретных ресурсов не правится вручную, а генерируется:
1. В схему генератора добавляются описания новых сущностей:
* Тип `action` или `subresource` для вызова эндпоинтов модификации.
* Контракты входных/выходных атрибутов (`org_id`, `ip_count`, `ip_space_id`, `nsxt_id`, `enabled`).
2. Кодогенератор генерирует стандартные CRUD-структуры Terraform Plugin Framework / SDK.
### Жизненный цикл ресурсов модификации
* **Create**:
- Вызывает соответствующий API-метод (`POST /api/v1/vcOrg/{id}/modify` или `/api/v1/vcNsxt/{id}/modify`).
- Дожидается применения задачи (task tracking / polling).
- Сохраняет идентификатор операции или полученный `ip_space_id` в Terraform State.
* **Read**:
- Запрашивает текущее состояние родительского ресурса через GET API.
- Проверяет, выделены ли IP / активен ли SNAT.
* **Update**:
- Если меняется количество IP или настройки SNAT — отправляет повторный запрос на модификацию.
* **Delete (terraform destroy)**:
- При уничтожении инфраструктуры порядок разворачивается в обратную сторону.
- Сначала удаляется `cloud_shturval`.
- Затем `cloud_vc_nsxt_snat` отключает SNAT.
- Затем `cloud_vc_org_ip_allocation` освобождает выделенные IP.
- И только затем удаляются базовые `vcNsxt`, `vcVdc` и `vcOrg`.
---
## 4. Альтернативные подходы
1. **Smart Provider (комбинированный Create)**:
- Если API позволяет вызывать шаги последовательно внутри одного HTTP-сеанса бэкенда, провайдер мог бы скрыть это внутри `Create` ресурса `cloud_shturval`.
- *Минус*: теряется гибкость и прозрачность статусов; сбой на промежуточном этапе оставляет "зависшие" ресурсы в облаке без записи в tfstate.
2. **Модули Terraform (Module Wrapper)**:
- Описанная выше структура ресурсов упаковывается в официальный Terraform-модуль `terraform-nubes-shturval`, скрывая сложность связей от конечного пользователя и предоставляя простой интерфейс ввода параметров.