Files
tf_provider/NOTES/30_analysis/ARCHITECTURE_NEW.md
T
Repinoid 9aed2dcdd9 fix(provider): нормализация регистра UUID при отправке map-fixed JSON в API
- resources_core.BuildJSON оборачивает результат в jsonutil.LowercaseUUIDsInText:
  платформа сравнивает регистр UUID при create, а ресурсы отдают id в UPPERCASE
  (nsxtUid/vdcUid) -> без нормализации create Штурвала падал 'Edge не развёрнут
  в указанном vDC' (обнаружено на провайдере 2.0.23 из-под Windows).
- Одна точка покрывает все map-fixed-параметры (create/modify/redeploy),
  регенерация не требуется.
- Документация: HISTORY/2026-09-30, docs/60_strategy/terraform_case_sensitivity_fix.md §11,
  NOTES/30_analysis/ARCHITECTURE_NEW.md §6.5, docs/help/architecture-and-methods.md §7.

Не выпущено: версия не поднималась, релиз/регенерация не выполнялись.
2026-09-30 08:34:04 +03:00

216 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- ⛔ LEGACY: deck-api.ngcloud.ru ЗАКРЫВАЕТСЯ. Актуальный API: lk-api-gateway.ngcloud.ru/api/v1/svc -->
# Universal Rebuild — Архитектура и рабочая цепочка (актуально)
Документ для нового чата: описывает, как устроено «универсальное ядро», как формируются YAML‑спеки сервисов и как генерируются Go‑ресурсы. Учитывает ошибки/уроки из текущего чата.
---
## 0) Базовые правила работы
- Не менять существующий Go‑код без явного согласования.
- Новая логика — только новые функции/файлы (если не было явного разрешения на правку).
- Все операции с облаком — read‑only, если отдельно не разрешено создание/удаление.
- Для токенов: новый `access_token` сохранять в `/home/naeel/terra/HH-MM-SS.token`.
---
## 1) Архитектура (слои)
### 1.1 Универсальное ядро (core)
**Папка:** `universal_rebuild/internal/core`
- `client.go` — универсальный клиент API и общий flow операций.
- **Критерий завершения операции:** `dtFinish` (см. комментарии в коде). Логику запрещено менять без согласования.
### 1.2 Провайдер (provider)
**Папка:** `universal_rebuild/internal/provider`
- Конфигурация провайдера, получение токена, подключение ресурсов через реестр.
### 1.3 Сгенерированные ресурсы
**Папка:** `universal_rebuild/internal/resources_gen`
- Автогенерируемые ресурсы Terraform по YAML‑спецификациям.
- `registry.go` (генерируется) — регистрирует все ресурсы.
- `crud.go` — общие CRUD‑хелперы (создание/modify/delete). Этот файл **не генерируется**, его нужно сохранять.
### 1.4 YAML‑спеки ресурсов
**Папка:** `universal_rebuild/resources_yaml`
- YAML для каждого сервиса. Источник истины для генератора ресурсов.
- Формат включает `create.params`, `modify.params`, `lifecycle`.
### 1.5 Генераторы
- **YAML‑генератор без instanceUid**
- `universal_rebuild/tools/service_params_gen/main.go`
- Получает параметры сервиса напрямую через `/index.cfm?endpoint=...`.
- **Go‑генератор**
- `universal_rebuild/tools/gen/main.go`
- Читает YAML и генерирует ресурсы + `registry.go`.
### 1.6 Отдельные modifier-ресурсы
Для parent-level операций `modify`, которые должны выполняться отдельным шагом Terraform-цепочки, используется `kind: modifier`.
Пример:
```yaml
- name: modify
kind: modifier
action: modify
modifier: ip_space
params: []
```
Такой блок не попадает в обычный instance CRUD. Go-генератор создаёт отдельный ресурс с именем `nubes_<service>_<modifier>`. Ресурс принимает ID родительского инстанса и параметры операции, выполняет parent `modify` при Create/Update и читает актуальные значения из `state_params` при Read.
Для `vcOrg` используется modifier `ip_space` с параметром `vIPConfigure`; для `vcNsxt` используется modifier `network` с параметрами операции сетевой настройки. Nested API-параметры modifier-ресурсов передаются как JSON-строки, поэтому их Terraform-значения должны быть валидным JSON.
Удаление modifier пока является no-op: подтверждённого обратного payload для отмены выделенных IP или SNAT нет. Операции удаления родительского сервиса не являются rollback и намеренно не вызываются.
---
## 2) Как получить параметры сервиса (без instanceUid)
Источник описан в:
- `docs/40_analysis/har/discovery/service_parameters_fetch.md`
API‑цепочка:
1) `GET /api/v1/index.cfm?endpoint=/services/{svcId}`
- даёт список операций сервиса (`operations`)
2) `GET /api/v1/index.cfm?endpoint=/serviceOperation/{svcOperationId}`
- даёт `cfsParams` (id, code, type, required, default, valueList, refSvcId, func)
3) (опц.) `GET /api/v1/index.cfm?endpoint=/param-value-list/{svcOperationCfsParamId}`
**Почему так:** прямых эндпойнтов на список параметров по `service_id` нет. Параметры извлекаются из описаний операций.
---
## 3) YAML‑генерация (service_params_gen)
**Файл:** `universal_rebuild/tools/service_params_gen/main.go`
Входные переменные:
- `NUBES_API_TOKEN` (если не задан — берётся из `test_universal/terraform.tfvars`)
- `NUBES_API_ENDPOINT` (по умолчанию `https://deck-api.ngcloud.ru/api/v1/index.cfm`)
- `NUBES_SERVICE_ID` (обязателен)
- `NUBES_SERVICE_NAME` (опц.)
- `NUBES_OUTPUT` (опц.)
Пример:
```bash
cd /home/naeel/terra/universal_rebuild
NUBES_SERVICE_ID=1 NUBES_SERVICE_NAME=dummy go run ./tools/service_params_gen/main.go
```
Результат:
- `/home/naeel/terra/universal_rebuild/resources_yaml/dummy.yaml`
---
## 4) Go‑генерация (tools/gen)
**Файл:** `universal_rebuild/tools/gen/main.go`
Что делает:
- читает все YAML из `resources_yaml/`
- генерирует ресурсы в `internal/resources_gen/`
- генерирует `registry.go`
Команда:
```bash
cd /home/naeel/terra/universal_rebuild
go run ./tools/gen/main.go
```
---
## 5) Build
```bash
cd /home/naeel/terra/universal_rebuild
go build -o terraform-provider-nubes
```
---
## 6) Важные нюансы и ошибки (из опыта чата)
### 6.1 resourceRealm
- `resourceRealm` **должен задаваться пользователем в .tf**, если параметр required.
- Нельзя автоподставлять `serviceName` как realm: API отклонит (пример с Postgres).
### 6.2 Warnings о дубликатах
- Предупреждение о `RESOURCE WITH SAME NAME EXISTS` должно появляться только на create (когда state.ID отсутствует).
- Для managed ресурсов (ID уже есть) предупреждения быть не должно.
### 6.3 Deleted ресурсы
- Если `explainedStatus=deleted` или `isDeleted=true` → ресурс считается отсутствующим, state должен очищаться.
### 6.4 Имена параметров
- Генератор может создавать «разбитые» snake_case для CamelCase (например `resource_c_p_u`).
- Это ожидаемо, но если критично — нужен отдельный маппинг (по согласованию).
### 6.5 Регистр UUID в JSON-параметрах (map-fixed) — ОБЯЗАТЕЛЬНО ЗНАТЬ
- Платформа хранит UUID в lowercase, но **сравнивает регистр при create**. Ресурс
`nubes_vc_nsxt` отдаёт `id` в UPPERCASE → `startupConfiguration.vdcUid/nsxtUid`
в верхнем регистре → ошибка «Edge не развёрнут в указанном vDC».
- **Нормализация нужна в ДВУХ разных местах, и они не взаимозаменяемы:**
1. **Сравнение** (план vs state, adopt/suspend/resume, modifier-compare, диагностика) —
`jsonutil.LowercaseUUIDsInText` внутри `JSONStringsEquivalent`, `JsonNormalize()`,
`ParamsMatchForResume`, `normalizeCompareValue`.
2. **Отправка в API** — единственная точка: `resources_core.BuildJSON`
(`provider/internal/resources_core/helpers.go`), её вызывает генератор
(`NestedJSONExpr` в `templates/instance.go`: Create / Modify / Redeploy).
С 30.09 результат оборачивается в `LowercaseUUIDsInText(...)`.
- ⛔ **Не «лечить» это в HCL** (`lower(...)` в конфиге стенда) — это костыль, который
существовал только потому, что путь отправки не нормализовал UUID. Он ломался при
работе из-под Windows на провайдере `2.0.23`.
- Детали, аудит всех мест и границы применимости: `docs/60_strategy/terraform_case_sensitivity_fix.md`
(§10 — регистр при сравнении, §11 — регистр при отправке).
- Не покрыто: скалярные UUID в `normalizeUniversalValueV6` (дефолты create / досылка modify)
и валидация ref-параметров внутри JSON при adopt — см. §11 и HISTORY/2026-09-30.
---
## 7) Проверенная цепочка (dummy)
1) YAML:
```bash
NUBES_SERVICE_ID=1 NUBES_SERVICE_NAME=dummy go run ./tools/service_params_gen/main.go
```
2) Go‑код:
```bash
go run ./tools/gen/main.go
```
3) Build:
```bash
go build -o terraform-provider-nubes
```
---
## 8) Что делать дальше
- Повторять пункты 3–5 для каждого сервиса:
- `NUBES_SERVICE_ID=13 NUBES_SERVICE_NAME=bucket`
- `NUBES_SERVICE_ID=90 NUBES_SERVICE_NAME=postgres`
- Проверять YAML на корректность required‑параметров, `resourceRealm` и defaults.
- Поднимать ресурсы в `.tf` и тестировать: create / modify / suspend / delete.
---
## 9) Где искать доп. материалы
- Архитектура (старые, но полезные):
- `docs/ai_universal_provider_gen.md`
- `docs/00_overview/ai_universal_provider_gen.md`
- API discovery:
- `docs/40_analysis/har/discovery/service_parameters_fetch.md`
---
**Короткая формула:**
`API (services → serviceOperation)` → `YAML` → `Go resources + registry` → `build` → `tests`.
---
## 10) Политика удаления (карантин)
- Многие инстансы **нельзя удалять сразу**: из-за возможных данных действует **2‑недельный карантин**.
- **Dummy** подпадает под эту политику.
- Для `nubes_dummy` при **destroy** или удалении из манифеста выполняется **`suspend`**, а не `delete`.
- При `apply`, если инстанс dummy в состоянии **suspend**, выполняется **`resume`**.