248 lines
12 KiB
Markdown
248 lines
12 KiB
Markdown
# How It Was Done — Developer Guide (закрытая страница)
|
||
|
||
**Filename & Versioning:** howitwasdone.md / 2026‑02‑04 / Draft v1
|
||
|
||
Этот документ — единый технический мануал. Он доступен только по прямой ссылке и не включён в публичную навигацию.
|
||
|
||
## Оглавление
|
||
1. Архитектура и методы (CRUD)
|
||
2. База знаний ошибок
|
||
3. Глоссарий (со ссылками на места употребления)
|
||
4. Билд и публикация провайдера и документации
|
||
|
||
---
|
||
|
||
## 1. Архитектура и методы (CRUD)
|
||
|
||
### 1.1 Архитектура универсального rebuild
|
||
- Ядро: universal_rebuild/internal/core (универсальный клиент API и общий flow операций).
|
||
- Провайдер: universal_rebuild/internal/provider (schema, конфигурация, подключение ресурсов).
|
||
- YAML-спеки: universal_rebuild/resources_yaml (источник истины).
|
||
- Генератор: universal_rebuild/tools/gen (генерация Go-ресурсов и registry).
|
||
|
||
Ключевое правило: новая логика — только новые функции/файлы. Существующий Go‑код не менять без согласования.
|
||
|
||
<a id="discovery"></a>
|
||
### 1.2 Источник параметров (discovery)
|
||
Параметры извлекаются через proxy endpoint API:
|
||
- /index.cfm?endpoint=/services/{svcId}
|
||
- /index.cfm?endpoint=/serviceOperation/{svcOperationId}
|
||
- (опц.) /index.cfm?endpoint=/param-value-list/{svcOperationCfsParamId}
|
||
|
||
Схема: сервис → операции → CFS параметры → YAML → генерация Go.
|
||
|
||
<a id="create-universal"></a>
|
||
### 1.3 Create (универсальный 7‑шаговый паттерн)
|
||
1) POST /instances → instanceUid
|
||
2) POST /instanceOperations (create) → instanceOperationUid
|
||
3) GET /instanceOperations/{uid}?fields=cfsParams
|
||
4) POST /instanceOperationCfsParams для каждого параметра
|
||
5) GET /instanceOperations/{uid}/validate-cfs
|
||
6) POST /instanceOperations/{uid}/run с payload {}
|
||
7) Polling до завершения операции
|
||
|
||
Критично: параметры отправляются все, включая дефолты.
|
||
|
||
<a id="read-adopt"></a>
|
||
### 1.4 Read / Adopt
|
||
- При isDeleted или explainedStatus=deleted — state очищается.
|
||
- При совпадении display_name и resume_if_exists=true — adopt/resume.
|
||
- Предупреждения показываются только на create и не мешают managed ресурсам.
|
||
|
||
<a id="update-modify"></a>
|
||
### 1.5 Update / Modify
|
||
- IDs параметров на modify отличаются от create.
|
||
- Нельзя хардкодить ID: нужно получать manifest операции и строить маппинг.
|
||
- Если modify отсутствует в availableOperations — выдаётся ясная ошибка.
|
||
|
||
<a id="polling-rules"></a>
|
||
### 1.6 Polling (железные правила)
|
||
- Завершение операции определяется только по dtFinish.
|
||
- После dtFinish результат определяется isSuccessful.
|
||
- Для VM применяется двойной контроль: статус операции + статус инстанса (ERROR/STOPPED).
|
||
|
||
### 1.7 Нормализация типов
|
||
- map/json → "{}"
|
||
- list/array → "[]"
|
||
- Пустые строки в JSON‑параметрах запрещены (валидаторы на plan).
|
||
|
||
<a id="soft-delete"></a>
|
||
### 1.8 Soft Delete
|
||
- Для тяжёлых ресурсов delete заменяется на suspend (карантин/retention).
|
||
- Повторный apply при suspend может выполнять resume.
|
||
|
||
---
|
||
|
||
## 2. База знаний ошибок
|
||
|
||
### A. Аутентификация и токены
|
||
**Симптом:** 401 Unauthorized / Authorization header expected
|
||
**Причина:** токен истёк или не передан в окружение
|
||
**Решение:** обновить access_token и сохранить в файле HH‑MM‑SS.token; убедиться, что Terraform читает токен
|
||
|
||
### B. Поллинг зависает
|
||
**Симптом:** apply «висит», операция не завершается
|
||
**Причина:** ожидание по статусу инстанса/операции без dtFinish
|
||
**Решение:** критерий завершения — dtFinish; далее isSuccessful
|
||
|
||
### C. Modify: Invalid CFS parameter (400)
|
||
**Причина:** отправлены create IDs для modify
|
||
**Решение:** получать manifest операции и динамически маппить IDs
|
||
|
||
### D. Modify недоступен
|
||
**Симптом:** action modify not available
|
||
**Причина:** modify нет в availableOperations
|
||
**Решение:** проверять доступные операции и выдавать явную ошибку
|
||
|
||
### E. Map/JSON/List: Invalid format
|
||
**Симптом:** 400 Invalid format map/array/json
|
||
**Причина:** пустые строки вместо {} или []
|
||
**Решение:** нормализация по типу, trim, отправка {} или []
|
||
|
||
### F. VM: зависание на FW / 500 String[]→GUID
|
||
**Симптом:** зависание на стадии FW, 500 checkParam
|
||
**Причина:** пустые/невалидные JSON‑массивы, ошибки backend
|
||
**Решение:** валидация JSON массивов, дефолт ["0.0.0.0/0"], фильтрация пустых значений; при повторении — эскалация на поддержку
|
||
|
||
### G. VM modify: checkParam instanceOperationCfsParamUid
|
||
**Симптом:** 500 Invalid call of function checkParam
|
||
**Причина:** дублирование параметров при POST/PUT
|
||
**Решение:** гибридный PUT/POST по наличию instanceOperationCfsParamUid; проверить формат эндпойнта
|
||
|
||
### H. Postgres: split() on null
|
||
**Симптом:** Cannot invoke method split() on null object
|
||
**Причина:** передан UUID конкретного S3‑бакета
|
||
**Решение:** использовать UUID сервиса S3 (svcId 12), а не бакета
|
||
|
||
### I. GPG/Registry
|
||
**Симптом:** authentication signature from unknown issuer
|
||
**Причина:** ключ подписи не совпадает с ключом в registry
|
||
**Решение:** обновить signing_keys на сервере или пересобрать/подменить бинарник
|
||
|
||
**Симптом:** openpgp invalid data
|
||
**Причина:** ASCII‑armor для .sig
|
||
**Решение:** бинарная detached подпись без --armor
|
||
|
||
### J. Registry/S3
|
||
**Симптом:** presigned URL не работает через Ingress
|
||
**Причина:** Host заголовок ломает подпись
|
||
**Решение:** proxy‑режим download на сервере registry
|
||
|
||
### K. Документация: 404
|
||
**Причина:** неверный S3‑ключ (hostname в префиксе)
|
||
**Решение:** фиксированный префикс docs/<ns>/<name>/<version>/
|
||
|
||
### L. Версии Terraform Plugin Framework
|
||
**Симптом:** ошибки сборки при апгрейде
|
||
**Причина:** несовместимость framework и plugin‑go
|
||
**Решение:** использовать совместимые версии
|
||
|
||
### M. TLS handshake timeout
|
||
**Причина:** сетевые условия/VPN
|
||
**Решение:** повторить apply
|
||
|
||
---
|
||
|
||
## 3. Глоссарий (с ссылками на места употребления)
|
||
|
||
Каждый термин содержит ссылки на разделы этого же документа, где он используется.
|
||
|
||
- **instance** — экземпляр сервиса в Nubes Cloud.
|
||
- Ссылки: [Create](#create-universal)
|
||
|
||
- **instanceOperation** — асинхронная операция над instance (create/modify/delete/suspend/resume).
|
||
- Ссылки: [Create](#create-universal), [Polling](#polling-rules)
|
||
|
||
- **cfsParams** — список параметров операции, получаемый через manifest операции.
|
||
- Ссылки: [Create](#create-universal), [Discovery](#discovery)
|
||
|
||
- **svcOperationCfsParamId** — ID параметра операции, различается для create и modify.
|
||
- Ссылки: [Update / Modify](#update-modify)
|
||
|
||
- **dtFinish** — единственный надёжный индикатор завершения операции.
|
||
- Ссылки: [Polling](#polling-rules)
|
||
|
||
- **isSuccessful** — результат операции после dtFinish.
|
||
- Ссылки: [Polling](#polling-rules)
|
||
|
||
- **resourceRealm** — окружение/realm; иногда обязателен и задаётся пользователем.
|
||
- Ссылки: [Read / Adopt](#read-adopt)
|
||
|
||
- **display_name** — человекочитаемое имя; используется для adopt/resume.
|
||
- Ссылки: [Read / Adopt](#read-adopt)
|
||
|
||
- **resume_if_exists** — включение adopt/resume по display_name.
|
||
- Ссылки: [Read / Adopt](#read-adopt)
|
||
|
||
- **delete_mode** — режим удаления (delete/suspend/state_only).
|
||
- Ссылки: [Soft Delete](#soft-delete)
|
||
|
||
- **suspend** — мягкое удаление (карантин/retention).
|
||
- Ссылки: [Soft Delete](#soft-delete)
|
||
|
||
- **validate-cfs** — проверка параметров операции до run.
|
||
- Ссылки: [Create](#create-universal)
|
||
|
||
- **state.out** — выходные данные API; при отсутствии задаются null.
|
||
- Ссылки: [Read / Adopt](#read-adopt)
|
||
|
||
- **computed** — вычисляемые поля, должны быть известны после apply.
|
||
- Ссылки: [Read / Adopt](#read-adopt)
|
||
|
||
- **registry protocol** — API Terraform Registry (discovery + versions + download).
|
||
- Ссылки: [Публикация](#publish-registry)
|
||
|
||
- **signing_keys** — публичные GPG ключи, выдаваемые registry.
|
||
- Ссылки: [Публикация](#publish-registry)
|
||
|
||
- **NLI** — Natural Language Infrastructure (AI‑парсинг инструкций).
|
||
- Ссылки: [AI‑интеграция](#ai-nli)
|
||
|
||
---
|
||
|
||
## 4. Билд и публикация провайдера и документации
|
||
|
||
### 4.1 Сборка провайдера (universal_rebuild)
|
||
Общий цикл:
|
||
1) Генерация YAML параметров сервисов.
|
||
2) Генерация Go‑ресурсов.
|
||
3) Сборка бинарника go build.
|
||
|
||
Ключевые каталоги:
|
||
- universal_rebuild/resources_yaml
|
||
- universal_rebuild/internal/resources_gen
|
||
- universal_rebuild/tools/gen
|
||
|
||
<a id="publish-registry"></a>
|
||
### 4.2 Публикация провайдера в Registry
|
||
- Артефакты: zip, SHA256SUMS, SHA256SUMS.sig
|
||
- Подпись: для .sig использовать бинарную detached подпись
|
||
- Хранилище: S3 bucket terraform‑registry
|
||
- Префикс — по правилам registry‑сервера
|
||
|
||
### 4.3 Документация (MkDocs)
|
||
- Сборка: Docker образ squidfunk/mkdocs-material
|
||
- Результат: директория site/
|
||
- Публикация: scripts/publish-docs.sh
|
||
- Путь: docs/<namespace>/<name>/<version>/
|
||
|
||
### 4.4 Важные нюансы
|
||
- При смене домена обновлять registry и ключи подписи.
|
||
- Presigned URL через Ingress может ломаться — использовать proxy mode.
|
||
- Технические папки исключаются из публикации.
|
||
|
||
### 4.5 Рекомендованный порядок работ
|
||
1) Discovery параметров сервиса
|
||
2) Генерация YAML
|
||
3) Генерация Go‑ресурсов
|
||
4) Build
|
||
5) Тесты create/modify/suspend/resume
|
||
6) Документация и публикация
|
||
|
||
<a id="ai-nli"></a>
|
||
### 4.6 AI‑интеграция (NLI)
|
||
Кратко: реализована для ресурса Tubulus через ModifyPlan + askGemini, с защитой от двойного вызова AI.
|
||
|
||
### 4.7 Прямая ссылка
|
||
https://terra.k8c.ru/docs/nubes/nubes/2.0.0/howitwasdone/
|