189 lines
9.9 KiB
Markdown
189 lines
9.9 KiB
Markdown
# Universal Provider (ядро + генератор ресурсов) — подробный отчёт
|
||
|
||
Дата: 2026-01-31
|
||
|
||
## Цель
|
||
Нужна архитектура «универсального провайдера», где:
|
||
- есть **ядро** (общий клиент и универсальный флоу операций);
|
||
- есть **папка ресурсов** (Go-файлы ресурсов);
|
||
- есть **папка YAML-описаний сервисов** (чтобы DevOps мог добавить сервис одним файлом);
|
||
- есть **генератор**, который:
|
||
- читает YAML,
|
||
- генерирует ресурсы,
|
||
- генерирует реестр ресурсов,
|
||
- дальше выполняется build (ядро + ресурсы из папки).
|
||
|
||
В итоге: если файла ресурса нет — в провайдере его не будет. Если YAML изменён — перегенерация.
|
||
|
||
---
|
||
|
||
## Итоговая архитектура (v2.0.0, «голое» ядро + ресурсы)
|
||
Новая сборка размещена в:
|
||
- [nubes_provider_gen](nubes_provider_gen)
|
||
|
||
Структура:
|
||
- [nubes_provider_gen/internal/core](nubes_provider_gen/internal/core) — **ядро** (клиент, универсальный flow, запуск операций)
|
||
- [nubes_provider_gen/internal/provider](nubes_provider_gen/internal/provider) — **провайдер** (schema + клиент)
|
||
- [nubes_provider_gen/internal/resources_gen](nubes_provider_gen/internal/resources_gen) — **сгенерированные ресурсы** (Go)
|
||
- [nubes_provider_gen/resources_yaml](nubes_provider_gen/resources_yaml) — **YAML-описания сервисов**
|
||
- [nubes_provider_gen/tools/gen](nubes_provider_gen/tools/gen) — **генератор**
|
||
- [nubes_provider_gen/test_persistent](nubes_provider_gen/test_persistent) — тестовые манифесты
|
||
|
||
### 1) Ядро (core)
|
||
Файл: [nubes_provider_gen/internal/core/client.go](nubes_provider_gen/internal/core/client.go)
|
||
|
||
Содержит:
|
||
- `UniversalClient` с HTTP-клиентом и API endpoint/token.
|
||
- Универсальный flow **CreateGenericInstanceUniversalV6**:
|
||
1. POST /instances
|
||
2. POST /instanceOperations (create)
|
||
3. GET /instanceOperations/{opUid}?fields=cfsParams
|
||
4. POST /instanceOperationCfsParams (явные параметры)
|
||
5. POST /instanceOperationCfsParams (дефолтные/пустые для пропущенных)
|
||
6. GET /instanceOperations/{opUid}/validate-cfs
|
||
7. POST /instanceOperations/{opUid}/run
|
||
- Универсальные операции:
|
||
- `RunInstanceOperationUniversal` (delete/suspend/resume и т.д.)
|
||
- `RunInstanceOperationUniversalWithDefaults` (modify с автоподстановкой параметров)
|
||
- Утилиты:
|
||
- `FindInstanceByDisplayName`
|
||
- `GetInstanceState`
|
||
|
||
**Почему нужно WithDefaults для modify**
|
||
На modify требуются обязательные параметры (часто даже те, что не меняются). Без них backend падает.
|
||
|
||
### 2) Провайдер (provider)
|
||
Файл: [nubes_provider_gen/internal/provider/provider.go](nubes_provider_gen/internal/provider/provider.go)
|
||
|
||
- Тип провайдера: `nubes`
|
||
- Адрес: `terrareg.kube5s.ru/nubes/nubes`
|
||
- Ресурсы приходят из **реестра**:
|
||
- `resources_gen.AllResources()` — возвращает список функций создания ресурсов.
|
||
|
||
### 3) Генератор (tools/gen)
|
||
Файл: [nubes_provider_gen/tools/gen/main.go](nubes_provider_gen/tools/gen/main.go)
|
||
|
||
Функции:
|
||
- Читает все YAML-файлы в `resources_yaml/`
|
||
- Генерирует ресурсный Go-файл в `internal/resources_gen/` для каждого YAML
|
||
- Генерирует `registry.go` с `AllResources()`
|
||
|
||
То есть:
|
||
- **Добавили YAML → сгенерировали Go → build**
|
||
- Нет YAML → нет Go → нет ресурса
|
||
|
||
### 4) YAML-описания
|
||
Файл: [nubes_provider_gen/resources_yaml/dummy.yaml](nubes_provider_gen/resources_yaml/dummy.yaml)
|
||
|
||
Минимальная схема (пример dummy):
|
||
- `name`, `service_id`, `display_name_default`
|
||
- `create.params` — ID параметров create
|
||
- `modify.params` — ID параметров modify
|
||
- `lifecycle` — defaults для `adopt_existing_on_create` и `suspend_on_destroy`
|
||
|
||
---
|
||
|
||
## Что было сделано (конкретные шаги)
|
||
|
||
### Шаг 1. «Голое» ядро + генератор
|
||
Создан отдельный проект:
|
||
- [nubes_provider_gen](nubes_provider_gen)
|
||
Сделан core + provider + tools/gen + resources_yaml.
|
||
|
||
### Шаг 2. YAML для dummy
|
||
Создан YAML dummy: [nubes_provider_gen/resources_yaml/dummy.yaml](nubes_provider_gen/resources_yaml/dummy.yaml)
|
||
|
||
### Шаг 3. Генерация ресурсов
|
||
Команда:
|
||
- `go run ./tools/gen`
|
||
|
||
Сгенерированы:
|
||
- [nubes_provider_gen/internal/resources_gen/dummy_resource.go](nubes_provider_gen/internal/resources_gen/dummy_resource.go)
|
||
- [nubes_provider_gen/internal/resources_gen/registry.go](nubes_provider_gen/internal/resources_gen/registry.go)
|
||
|
||
### Шаг 4. Build
|
||
Команда:
|
||
- `go build -o terraform-provider-nubes`
|
||
|
||
### Шаг 5. Тесты dummy
|
||
Тестовый конфиг:
|
||
- [nubes_provider_gen/test_persistent/main.tf](nubes_provider_gen/test_persistent/main.tf)
|
||
- [nubes_provider_gen/test_persistent/dev_override.tfrc](nubes_provider_gen/test_persistent/dev_override.tfrc)
|
||
|
||
Проверены сценарии:
|
||
1. `apply` (create/adopt) — OK
|
||
2. `modify` (duration 750 → 820) — OK
|
||
3. `destroy` (`suspend_on_destroy = true`) — OK
|
||
4. `apply` после suspend (resume/adopt c явным `adopt_existing_on_create`) — OK
|
||
5. удаление ресурса из манифеста + `apply` — OK
|
||
6. возвращение ресурса в манифест + `apply` — OK
|
||
|
||
---
|
||
|
||
## Ошибки и как решались
|
||
|
||
### 1) `action modify not available`
|
||
Причина: в Update использовался `id` из `Plan` (неизвестен).
|
||
Решение: брать `id` из `State`.
|
||
|
||
### 2) `API error 400: Parameter specified does not belong to this operation`
|
||
Причина: неверные ID параметров modify.
|
||
Решение: для modify использовать `287/288` вместо `198/199`.
|
||
|
||
### 3) `API error 500: checkParam ... instanceOperationCfsParamUid` (повторно)
|
||
Причина: операция modify требует подстановки всех параметров; без них backend падает.
|
||
Решение:
|
||
- Добавлен `RunInstanceOperationUniversalWithDefaults` — читает `cfsParams` и заполняет недостающие
|
||
- Позже для dummy оказалось нужно отправлять **все** параметры (не только required)
|
||
|
||
### 4) `TLS handshake timeout`
|
||
Причина: VPN/сеть.
|
||
Решение: повторить команду.
|
||
|
||
### 5) `status 401`
|
||
Причина: токен истёк/невалидный.
|
||
Решение: заменить токен и сохранить по правилу `/home/naeel/terra/HH-MM-SS.token`.
|
||
|
||
### 6) Критерий завершения операции (важно)
|
||
Любая операция (create/modify/delete/suspend/resume) считается **завершённой**, когда у неё заполнено **время окончания**.
|
||
Это является признаком завершения **и успеха, и ошибки**. В UI и API ориентируемся на наличие `dtFinish`.
|
||
|
||
---
|
||
|
||
## Текущее состояние
|
||
- Провайдер «голый» + ресурсы из YAML работает.
|
||
- `dummy` полностью тестируется из YAML → Go → build.
|
||
- В `resources_gen` присутствует 1 ресурс: `nubes_dummy`.
|
||
|
||
---
|
||
|
||
## План (следующий шаг)
|
||
1) Расширить YAML-схему:
|
||
- поддержку дополнительных параметров (например, failInProgress, whereFail и т.п.)
|
||
- поддержку optional параметров с явными defaults
|
||
2) Добавить генерацию документации из YAML
|
||
3) Добавить проверку схемы YAML (валидация) перед генерацией
|
||
4) Скрипт "build pipeline":
|
||
- gen → registry → go build
|
||
5) Опционально: тестовый фреймворк для «batch» тестов
|
||
|
||
---
|
||
|
||
## Важные файлы
|
||
- Ядро: [nubes_provider_gen/internal/core/client.go](nubes_provider_gen/internal/core/client.go)
|
||
- Генератор: [nubes_provider_gen/tools/gen/main.go](nubes_provider_gen/tools/gen/main.go)
|
||
- Реестр: [nubes_provider_gen/internal/resources_gen/registry.go](nubes_provider_gen/internal/resources_gen/registry.go)
|
||
- YAML dummy: [nubes_provider_gen/resources_yaml/dummy.yaml](nubes_provider_gen/resources_yaml/dummy.yaml)
|
||
- Сгенерированный ресурс: [nubes_provider_gen/internal/resources_gen/dummy_resource.go](nubes_provider_gen/internal/resources_gen/dummy_resource.go)
|
||
- Тесты: [nubes_provider_gen/test_persistent/main.tf](nubes_provider_gen/test_persistent/main.tf)
|
||
|
||
---
|
||
|
||
## MAYDO (отложено до запроса заказчика)
|
||
- Добавить в YAML `outputs` (из `state/out`) и `state_params` (из `state/params`).
|
||
- Добавить `param_meta`: `valueList`, `func`, `refSvcId`, `dataDescriptor`.
|
||
- Добавить `secrets` (из `vault`) с пометкой чувствительных данных.
|
||
- Добавить `operations` (man/описания, доступные операции) для генерации доков.
|
||
- Добавить поддержку `subparams` (nested/list/json) и типизацию сложных структур.
|
||
- Добавить обработку версий операций (если API это отдаёт).
|