docs: add modifier resources ideology and architecture specification
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
# Архитектурная концепция: Modifier-ресурсы (Идеология, правила и интеграция в Terraform Provider)
|
||||
|
||||
## 1. Введение и архитектурный контекст
|
||||
|
||||
### 1.1. Проблема: Чередующиеся зависимости (Interleaved Lifecycle)
|
||||
В классической декларативной модели Terraform каждый ресурс управляется монолитно: один блок `resource` соответствует полному жизненному циклу одной сущности (Create -> Read -> Update -> Delete).
|
||||
|
||||
Однако при комплексном развертывании инфраструктуры у облачного провайдера (например, цепочка для сервиса **Штурвал** `k8s_sthutrval_cluster`) возникает жесткая **чередующаяся зависимость**:
|
||||
1. `vcOrg/create` — создание тенанта (Организации).
|
||||
2. `vcVdc/create` — создание виртуального датацентра внутри Организации.
|
||||
3. `vcNsxt/create` — создание базового сетевого шлюза (Edge Gateway) с включением AVI ALB и 4 Service Engine.
|
||||
4. `vcOrg/modify` — выделение пула из 3 внешних IP-адресов в Организации (требует, чтобы NSX-T уже существовал).
|
||||
5. `vcNsxt/modify` — включение правила SNAT на шлюзе с привязкой `ipSpace`, созданного на шаге 4 (требует наличия свободных IP).
|
||||
6. `k8sSthutrvalCluster/create` — развертывание кластера Штурвал (требует настроенного SNAT, AVI и свободных IP).
|
||||
|
||||
Попытка «зашить» шаги 4 и 5 внутрь основных ресурсов `vc_org` и `vc_nsxt` приводит к тупику в графе зависимостей Terraform (DAG) или к ошибкам API из-за несвоевременного вызова параметров.
|
||||
|
||||
### 1.2. Решение: Класс Modifier-ресурсов
|
||||
Для разрешения таких зависимостей в архитектуру провайдера вводится специальный класс сущностей — **Modifier-ресурсы (Модификаторы)**.
|
||||
|
||||
* **Instance-ресурс (базовый сервис)** — отвечает за владение и жизненный цикл инстанса в облаке (`POST /create`, `GET /state`, `DELETE /delete`).
|
||||
* **Modifier-ресурс (модификатор)** — отвечает за выполнение отложенной операции конфигурирования/связывания над уже созданным инстансом (`POST /modify`), являясь самостоятельным блоком в графе Terraform.
|
||||
|
||||
---
|
||||
|
||||
## 2. Идеология Terraform: Почему это каноничный подход
|
||||
|
||||
Разделение базовой сущности и отложенных настроек/связей на отдельные ресурсы — это официальный архитектурный паттерн Terraform (**Resource Association / Separate Resource Pattern**), используемый во всех провайдерах первого эшелона:
|
||||
* **AWS**: `aws_security_group` (базовый контейнер) + `aws_security_group_rule` (отдельные правила привязки).
|
||||
* **AWS**: `aws_vpc` + `aws_route_table_association` / `aws_vpn_gateway_attachment`.
|
||||
* **GCP**: `google_project` + `google_project_iam_binding`.
|
||||
|
||||
### Преимущества подхода:
|
||||
1. **Естественный граф зависимостей (DAG)**: Terraform выстраивает порядок шагов исключительно между блоками `resource`. Вынос модификаций в отдельные ресурсы позволяет вклинивать промежуточные сервисы между созданием родителя и его донастройкой.
|
||||
2. **Симметричный и безопасный `destroy`**: При удалении стека Terraform автоматически разворачивает порядок:
|
||||
* Сначала удаляется `k8s_sthutrval_cluster`.
|
||||
* Затем Modifier шлюза отключает SNAT.
|
||||
* Затем Modifier организации освобождает выделенные IP.
|
||||
* И только потом удаляются базовые шлюз, VDC и организация.
|
||||
3. **Предсказуемый `plan` и локализация сбоев**: Любая ошибка настройки локализуется в блоке модификатора, не повреждая стейт базового инстанса.
|
||||
|
||||
---
|
||||
|
||||
## 3. Правила определения входных данных Modifier-ресурса
|
||||
|
||||
Входные данные Modifier-ресурса определяются строго детерминированно на основе официальной YAML-спецификации сервиса из API (`operations` -> `name: modify`).
|
||||
|
||||
### Правило 1: Якорь привязки (`instance_id` / `<service>_id`)
|
||||
Каждый модификатор обязан содержать ровно один обязательный атрибут привязки:
|
||||
* Имя: `instance_id` (или семантическое имя, например `org_id`, `nsxt_id`).
|
||||
* Тип: `string` (UUID).
|
||||
* В манифесте `.tf` значение передаётся как ссылка на атрибут родительского ресурса:
|
||||
```hcl
|
||||
org_id = nubes_vc_org.main.id
|
||||
```
|
||||
Это гарантирует, что Terraform выполнит модификатор **строго после** создания родителя.
|
||||
|
||||
### Правило 2: Строгая функциональная группа параметров
|
||||
Операция `modify` в API может содержать множество разнородных параметров. Модификатор инкапсулирует **только одну целевую функциональную задачу**:
|
||||
* **Для модификатора IP организации (`vc_org_ip_modifier`)**:
|
||||
* Входные параметры берутся из секции `modify` YAML `vc_org`: массив `vIPConfigure` (`name`, `count`).
|
||||
* **Для модификатора SNAT шлюза (`vc_nsxt_snat_modifier`)**:
|
||||
* Входные параметры берутся из секции `modify` YAML `vc_nsxt`: `ipSpaceName`, `needEnableAVI`, `virtualServicesCount`, `routedNetConfiguration`.
|
||||
|
||||
Все параметры операции `modify`, не относящиеся к данной задаче, в схему конкретного модификатора **не включаются**.
|
||||
|
||||
### Правило 3: Наследование типов и валидаций из YAML
|
||||
Схема атрибутов модификатора строится по существующей универсальной таблице типов провайдера:
|
||||
* Обязательность (`required`), значения по умолчанию (`default`), регулярные выражения (`regex`) и диапазоны значений наследуются напрямую из спецификации параметров YAML.
|
||||
|
||||
### Правило 4: Экспорт вычисляемых атрибутов (Computed Outputs)
|
||||
Если модификатор формирует сущность, необходимую последующим шагам, он экспортирует её как `Computed`:
|
||||
* `vc_org_ip_modifier` экспортирует `ip_space_name`.
|
||||
* Модификатор шлюза может сослаться на него напрямую:
|
||||
```hcl
|
||||
ip_space_name = nubes_vc_org_ip_modifier.ips.ip_space_name
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Жизненный цикл Modifier-ресурса в провайдере (CRUD)
|
||||
|
||||
| Метод Terraform | Вызов API облака | Поведение |
|
||||
|---|---|---|
|
||||
| **Create** | `POST /api/v1/svc/{service_id}/{instance_id}/modify` | Отправляет payload с целевыми параметрами модификации. Запускает polling задачи до статуса успешного завершения. Сохраняет ID и параметры в State. |
|
||||
| **Read** | `GET /api/v1/svc/{service_id}/{instance_id}` | Читает текущее состояние родительского инстанса. Извлекает значения целевых параметров (например, текущие IP или статус SNAT) и сверяет с State. |
|
||||
| **Update** | `POST /api/v1/svc/{service_id}/{instance_id}/modify` | Вызывается при изменении атрибутов модификатора в `.tf` файле. Отправляет обновлённый payload и ожидает завершения задачи. |
|
||||
| **Delete** | `POST /api/v1/svc/{service_id}/{instance_id}/modify` | **Откат настройки**: отправляет запрос на деактивацию конкретного функционала (отключение SNAT, обнуление/освобождение пула IP), не удаляя сам родительский инстанс. |
|
||||
|
||||
---
|
||||
|
||||
## 5. Схема интеграции в конвейер провайдера
|
||||
|
||||
Провайдер сохраняет архитектурную чистоту и принцип неизменяемости кода конкретных сервисов (**Immutability Policy**):
|
||||
|
||||
```
|
||||
[ API Облака ]
|
||||
│
|
||||
▼
|
||||
TOOLS/scripts/01_generate_yamls.sh
|
||||
│
|
||||
▼
|
||||
[ generated/<stand>/resources_yaml/ ]
|
||||
(Спецификации стандартных сервисов)
|
||||
│
|
||||
┌───────────────────┴───────────────────┐
|
||||
▼ ▼
|
||||
[ Универсальный Генератор ] [ Модуль Модификаторов ]
|
||||
(Генерирует стандартные (Описывает схему и CRUD
|
||||
*_resource.go сервисов) для Modifier-ресурсов)
|
||||
│ │
|
||||
└───────────────────┬───────────────────┘
|
||||
▼
|
||||
[ Точка сборки: provider.go ]
|
||||
(Регистрация всех ресурсов в
|
||||
едином списке Resources(ctx))
|
||||
│
|
||||
▼
|
||||
TOOLS/scripts/03_build_...
|
||||
│
|
||||
▼
|
||||
[ Единый бинарный провайдер Nubes ]
|
||||
```
|
||||
|
||||
### Шаги интеграции:
|
||||
1. **Генерация стандартных ресурсов**: Универсальный генератор штатно обрабатывает YAML-спецификации сервисов, создавая основные ресурсы инстансов.
|
||||
2. **Добавление кода модификаторов**:
|
||||
* Файлы модификаторов реализуют интерфейс `resource.Resource` (Terraform Plugin Framework) и размещаются в кодовой базе провайдера.
|
||||
* Они используют общее ядро клиента (`provider/core/`) для отправки запросов и трекинга асинхронных операций.
|
||||
3. **Регистрация в провайдере**:
|
||||
* В функции `Resources(ctx)` провайдера фабричные методы модификаторов (например, `NewVcOrgIpModifierResource`, `NewVcNnxtSnatModifierResource`) добавляются в общий срез доступных ресурсов наряду со стандартными ресурсами сервисов.
|
||||
4. **Сборка**:
|
||||
* Провайдер компилируется в один исполняемый файл. Для пользователя Terraform новые ресурсы доступны нативно: `nubes_vc_org_ip_modifier`, `nubes_vc_nsxt_snat_modifier`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Пример сквозного использования в HCL
|
||||
|
||||
Итоговый пользовательский сценарий развертывания выглядит чисто, декларативно и прозрачно:
|
||||
|
||||
```hcl
|
||||
# 1. Создание Организации
|
||||
resource "nubes_vc_org" "org" {
|
||||
organization_type = "iaas"
|
||||
resource_realm = "sandbox.nubes.ru"
|
||||
}
|
||||
|
||||
# 2. Создание VDC
|
||||
resource "nubes_vc_vdc" "vdc" {
|
||||
organization_uid = nubes_vc_org.org.id
|
||||
network_provider = "default"
|
||||
provider_vdc = "fast-2.8"
|
||||
cpu_allocated = 80
|
||||
mem_allocated = 200
|
||||
|
||||
storage_config = [
|
||||
{
|
||||
name = "fast"
|
||||
size = 2000
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 3. Создание базового Edge NSX-T (включение AVI и 4 SE)
|
||||
resource "nubes_vc_nsxt" "edge" {
|
||||
vdc_type = "vdc"
|
||||
vdc_uid = nubes_vc_vdc.vdc.id
|
||||
need_enable_avi = true
|
||||
virtual_services_count = 4
|
||||
|
||||
routed_net_configuration = {
|
||||
ip_addr_pool = "10.10.102.0/24"
|
||||
main_dns = "8.8.8.8"
|
||||
second_dns = "8.8.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
# 4. Модификатор Org: выделение 3 IP (выполняется после Edge)
|
||||
resource "nubes_vc_org_ip_modifier" "org_ips" {
|
||||
org_id = nubes_vc_org.org.id
|
||||
|
||||
vip_configure = [
|
||||
{
|
||||
name = "shturval-ip-space"
|
||||
count = 3
|
||||
}
|
||||
]
|
||||
|
||||
# Явная зависимость гарантирует готовность Edge
|
||||
depends_on = [nubes_vc_nsxt.edge]
|
||||
}
|
||||
|
||||
# 5. Модификатор Edge: включение SNAT с ipSpace из шага 4
|
||||
resource "nubes_vc_nsxt_snat_modifier" "edge_snat" {
|
||||
nsxt_id = nubes_vc_nsxt.edge.id
|
||||
ip_space_name = nubes_vc_org_ip_modifier.org_ips.vip_configure[0].name
|
||||
|
||||
need_enable_avi = true
|
||||
virtual_services_count = 4
|
||||
|
||||
routed_net_configuration = {
|
||||
ip_addr_pool = "10.10.102.0/24"
|
||||
main_dns = "8.8.8.8"
|
||||
second_dns = "8.8.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
# 6. Развертывание кластера Штурвал
|
||||
resource "nubes_k8s_sthutrval_cluster" "cluster" {
|
||||
startup_configuration = {
|
||||
vdc_uid = nubes_vc_vdc.vdc.id
|
||||
nsxt_uid = nubes_vc_nsxt.edge.id
|
||||
cluster_name = "k8s-prod-cluster"
|
||||
}
|
||||
|
||||
control_plane_configuration = {
|
||||
count = 1
|
||||
sizing_policy = "standard-cp"
|
||||
sizing_disk = 50
|
||||
}
|
||||
|
||||
worker_configuration = [
|
||||
{
|
||||
count = 2
|
||||
sizing_policy = "standard-worker"
|
||||
sizing_disk = 50
|
||||
label_deck = true
|
||||
}
|
||||
]
|
||||
|
||||
# Требует полной готовности сетевой связки и свободных IP
|
||||
depends_on = [
|
||||
nubes_vc_nsxt_snat_modifier.edge_snat,
|
||||
nubes_vc_org_ip_modifier.org_ips
|
||||
]
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user