760 lines
34 KiB
Markdown
760 lines
34 KiB
Markdown
# Полный анализ кодовой базы и план развития
|
||
|
||
**Дата:** 2026-03-13
|
||
**Проект:** Terraform Provider for Nubes Cloud
|
||
**Версия провайдера:** dev (legacy) / 5.0.18 (universal_rebuild)
|
||
**Go:** 1.24 / Terraform Plugin Framework: v1.16 (legacy), v1.8 (rebuild)
|
||
|
||
---
|
||
|
||
## Содержание
|
||
|
||
1. [Общая архитектура](#1-общая-архитектура)
|
||
2. [Инвентаризация кода](#2-инвентаризация-кода)
|
||
3. [Критические проблемы (P0)](#3-критические-проблемы-p0)
|
||
4. [Серьёзные проблемы (P1)](#4-серьёзные-проблемы-p1)
|
||
5. [Средний приоритет (P2)](#5-средний-приоритет-p2)
|
||
6. [Анализ по слоям](#6-анализ-по-слоям)
|
||
7. [Эволюция API-клиента](#7-эволюция-api-клиента)
|
||
8. [Генератор кода v2](#8-генератор-кода-v2)
|
||
9. [Соответствие provider_philosophy.md](#9-соответствие-provider_philosophymd)
|
||
10. [Тестирование](#10-тестирование)
|
||
11. [Безопасность](#11-безопасность)
|
||
12. [Дорожная карта (Roadmap)](#12-дорожная-карта-roadmap)
|
||
13. [Рекомендации по агенту/модели](#13-рекомендации-по-агентумодели)
|
||
|
||
---
|
||
|
||
## 1. Общая архитектура
|
||
|
||
### Два провайдера в одном репозитории
|
||
|
||
| Компонент | Каталог | Версия | Registry Address | Статус |
|
||
|-----------|---------|--------|------------------|--------|
|
||
| **Legacy Provider** | `/internal/`, `/main.go` | dev | `registry.terraform.io/nubes/nubes` | Ручной код, 13 ресурсов |
|
||
| **Universal Provider** | `/universal_rebuild/` | 5.0.18 | `terra.k8c.ru/nubes/nubes` | Генерируемый, ~50 ресурсов |
|
||
|
||
### Архитектурные слои
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────┐
|
||
│ TERRAFORM CLI / HCL │
|
||
├─────────────────────────────────────────────────┤
|
||
│ Provider Layer (provider.go) │
|
||
│ ├── Resource Registration │
|
||
│ ├── Auth (token / env / file) │
|
||
│ └── HTTP Client Init │
|
||
├─────────────────────────────────────────────────┤
|
||
│ Resource Layer │
|
||
│ ├── Manual (vm, edge, vdc, vapp, postgres…) │ ← legacy, internal/provider/
|
||
│ └── Generated (50+ services) │ ← universal_rebuild/internal/resources_gen/
|
||
├─────────────────────────────────────────────────┤
|
||
│ Core Layer │
|
||
│ ├── UniversalClient (API V6 flow) │
|
||
│ ├── Instance Lookup / State │
|
||
│ ├── Operation Runner / Polling │
|
||
│ └── Timeout Management │
|
||
├─────────────────────────────────────────────────┤
|
||
│ CRUD Layer (resources_core/) │
|
||
│ ├── CreateResource / UpdateResource / Delete │
|
||
│ ├── adoptExistingInstanceOnCreate() │
|
||
│ ├── State Refresh / Output Mapping │
|
||
│ └── Params Compare / Ref Resolution │
|
||
├─────────────────────────────────────────────────┤
|
||
│ Nubes Cloud API (deck-api.ngcloud.ru/api/v1) │
|
||
└─────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Конвейер генерации
|
||
|
||
```
|
||
API (live) YAML specs Go code + Docs
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
01_generate_yamls.sh → resources_yaml/*.yaml → 02_generate_*.sh
|
||
(service_ops_gen) (gen_v2 + docs_template_gen_v2)
|
||
│
|
||
▼
|
||
03_build_and_upload.sh → S3
|
||
04_build_and_publish_docs.sh → S3
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Инвентаризация кода
|
||
|
||
### Legacy Provider (`internal/`)
|
||
|
||
| Файл | LOC | Назначение | Качество |
|
||
|------|-----|------------|----------|
|
||
| `provider/provider.go` | 110 | Регистрация, auth, HTTP клиент | ⚠️ InsecureSkipVerify |
|
||
| `provider/client_impl.go` | ~350 | HTTP-клиент (NubesClient) | Без retry, без polling |
|
||
| `provider/vm_resource.go` | ~500 | VM lifecycle (лучший ресурс) | ✅ Полный CRUD + import |
|
||
| `provider/edge_resource.go` | ~400 | Edge gateway | ✅ Полный flow |
|
||
| `provider/vdc_resource.go` | ~300 | VDC с triggers | ✅ Multi-stage create |
|
||
| `provider/vapp_resource.go` | ~250 | vApp | ✅ Базовый CRUD |
|
||
| `provider/postgres_resource.go` | ~200 | Postgres | ⚠️ Только create/delete |
|
||
| `provider/s3bucket_resource.go` | ~200 | S3 bucket | ✅ CRUD |
|
||
| `provider/pgadmin_resource.go` | ~150 | PgAdmin | ⚠️ Ограниченный |
|
||
| `provider/org_resource.go` | ~100 | Organization | ⚠️ Минимальный |
|
||
| `provider/quickstart_resource.go` | ~300 | Full-stack helper | Специальный |
|
||
| `provider/tubulus_resource.go` | ~200 | AI/Gemini интеграция | Экспериментальный |
|
||
| `provider/validators.go` | ~150 | Валидаторы | ✅ Хорошо |
|
||
| `core/client.go` | 1065 | UniversalClient (V1–V6) | 🔴 Раздут, 6 версий |
|
||
| `core/instance_lookup.go` | 87 | Поиск инстансов | ⚠️ Нет exact match |
|
||
| `core/instance_ops.go` | 159 | Операции + polling | ⚠️ Fixed 5s interval |
|
||
| **Итого** | **~4500** | | |
|
||
|
||
### Universal Rebuild (`universal_rebuild/`)
|
||
|
||
| Каталог | Файлов | LOC | Назначение |
|
||
|---------|--------|-----|------------|
|
||
| `internal/core/` | 5 | ~1400 | UniversalClient V6, timeouts, refSvc |
|
||
| `internal/provider/` | 2 | ~300 | Provider setup, timeout embed |
|
||
| `internal/resources_core/` | 16 | ~2500 | CRUD, state refresh, diagnostics, params |
|
||
| `internal/resources_gen/` | ~100+ | ~15000+ | Сгенерированные ресурсы (50 сервисов) |
|
||
| `resources_yaml/` | ~50 | — | YAML-спецификации сервисов |
|
||
| `tools/gen_v2/` | 1 | ~2500 | Генератор Go-кода |
|
||
| `tools/docs_template_gen_v2/` | 1 | ~800 | Генератор документации |
|
||
| `tools/service_ops_gen/` | 1 | ~800 | API → YAML генератор |
|
||
| `tools/service_params_gen/` | 1 | ~600 | Параметрический генератор |
|
||
| **Итого** | **~180** | **~24000+** | |
|
||
|
||
### Generated Code Summary (`resources_gen/`)
|
||
|
||
| Тип ресурса | Кол-во | Примеры |
|
||
|-------------|--------|---------|
|
||
| Instance (CRUD) | ~50 | postgres, rabbitmq, kafka, k8s, vc_vm |
|
||
| Subresource (user/db) | ~20 | postgres_user, postgres_database |
|
||
| Action (restart/etc.) | ~10 | postgres_restart, postgres_recovery |
|
||
| Registry | 1 | registry.go (auto-сгенерированный список) |
|
||
|
||
---
|
||
|
||
## 3. Критические проблемы (P0)
|
||
|
||
### P0-1: InsecureSkipVerify=true в production
|
||
|
||
**Где:** `internal/provider/provider.go:103`
|
||
|
||
```go
|
||
TLSClientConfig: &tls.Config{
|
||
InsecureSkipVerify: true, // ← MITM уязвимость
|
||
}
|
||
```
|
||
|
||
**Риск:** Атака "человек посередине" (MITM) — перехват API-токенов и данных.
|
||
|
||
**Решение:**
|
||
```go
|
||
// Новый атрибут провайдера:
|
||
"insecure": schema.BoolAttribute{
|
||
Optional: true,
|
||
Description: "Skip TLS certificate verification (dev only)",
|
||
},
|
||
// + env var NUBES_INSECURE
|
||
```
|
||
|
||
**Также проверить:** `universal_rebuild/internal/provider/provider.go` — аналогичная проблема.
|
||
|
||
---
|
||
|
||
### P0-2: Захардкоженный путь debug-лога
|
||
|
||
**Где:** `internal/core/client.go:18`
|
||
|
||
```go
|
||
f, err := os.OpenFile("/home/naeel/terra/debug_nubes.log", ...)
|
||
```
|
||
|
||
**Риск:** Сбой на любой другой машине. Потенциальная утечка данных в файл вне проекта.
|
||
|
||
**Решение:**
|
||
- Использовать `tflog` (terraform plugin logging) вместо файлового лога
|
||
- Или env var `NUBES_DEBUG_LOG` с fallback на `/tmp/nubes_debug.log`
|
||
|
||
---
|
||
|
||
### P0-3: Ноль автотестов
|
||
|
||
**Факт:** В репозитории не найдено ни одного `*_test.go` файла.
|
||
|
||
**Риск:**
|
||
- Регрессии при правках генератора
|
||
- Невозможно валидировать lifecycle-логику без ручной проверки
|
||
- Нет CI/CD confidence
|
||
|
||
**Решение:** См. раздел [10. Тестирование](#10-тестирование).
|
||
|
||
---
|
||
|
||
### P0-4: 6 версий CreateGenericInstance в одном файле
|
||
|
||
**Где:** `internal/core/client.go` — 1065 строк, 6 методов.
|
||
|
||
| Версия | Строки | Статус |
|
||
|--------|--------|--------|
|
||
| V1 `CreateGenericInstance` | 52-168 | Legacy, не используется |
|
||
| V2 `...Universal` | 195-334 | Legacy |
|
||
| V3 `...UniversalV2` | 361-504 | Legacy |
|
||
| V4 `...UniversalV3` | 531-676 | Legacy |
|
||
| V5 `...UniversalV4` | 703-840 | Legacy |
|
||
| V6 `...UniversalV5` | 867-1000 | Production |
|
||
|
||
**Риск:** Путаница — какой метод вызывать? Разная нормализация. Разные баги.
|
||
|
||
**Решение:**
|
||
- V1–V5 — пометить `// Deprecated: use CreateGenericInstanceUniversalV5`
|
||
- Убедиться, что все ресурсы используют V6/V5
|
||
- В перспективе — удалить мёртвый код (после аудита вызовов)
|
||
|
||
---
|
||
|
||
## 4. Серьёзные проблемы (P1)
|
||
|
||
### P1-1: Lifecycle-флаги — legacy vs. canonical
|
||
|
||
**Требование (provider_philosophy.md §7-9):**
|
||
- `adopt_existing_on_create` (default: `false`)
|
||
- `suspend_on_destroy` (default: `true`)
|
||
|
||
**Реальность в legacy:**
|
||
- `internal/generated/bolvan_resource_universal_lifecycle.go` использует `delete_mode` и `resume_if_exists`
|
||
- Это прямо запрещено в стратегии
|
||
|
||
**Реальность в universal_rebuild:**
|
||
- `resources_core/crud.go` использует `resumeIfExists` bool параметр
|
||
- Генератор `gen_v2` генерирует канонические флаги `suspend_on_destroy`, `adopt_existing_on_create`
|
||
- **Разрыв:** CRUD-слой принимает bool, но не полностью реализует decision matrix из §7
|
||
|
||
**Решение:**
|
||
1. Обновить `crud.go` — полная реализация status-matrix:
|
||
- `not created` → hard error
|
||
- `creating/pending/failed` → hard error
|
||
- `suspend` + `adopt=false` → hard error с диагностикой
|
||
- `running` + `adopt=true` → adopt (import)
|
||
- `running` + `adopt=false` → hard error "already exists"
|
||
2. Legacy bolvanka — отдельная задача, не трогать
|
||
|
||
---
|
||
|
||
### P1-2: Read() — стабы в сгенерированных ресурсах
|
||
|
||
**Проблема:** Многие сгенерированные ресурсы имеют пустой `Read()`.
|
||
|
||
**Последствия:**
|
||
- Terraform не видит state drift (облако изменилось, TF state устарел)
|
||
- `terraform plan` после `apply` показывает расхождения
|
||
- `terraform import` бесполезен без Read
|
||
|
||
**Уже решено в universal_rebuild?**
|
||
Да, `state_refresh.go:RefreshResourceState()` обеспечивает полный read-back. Но нужно убедиться, что все сгенерированные ресурсы этот метод ВЫЗЫВАЮТ в своём Read().
|
||
|
||
---
|
||
|
||
### P1-3: Нет retry/backoff для API-вызовов
|
||
|
||
**Где:** Все HTTP-вызовы через `doRequest()` — один попытка, без retry.
|
||
|
||
**Реальный сценарий:**
|
||
- API вернул 503 (maintenance) → terraform apply упал
|
||
- Сетевой timeout → terraform apply упал
|
||
- Rate limit (429) → terraform apply упал
|
||
|
||
**Решение:**
|
||
```go
|
||
// Добавить в core/client.go
|
||
func (c *UniversalClient) doRequestWithRetry(ctx context.Context, ...) (*http.Response, error) {
|
||
maxRetries := 3
|
||
backoff := 2 * time.Second
|
||
for attempt := 0; attempt <= maxRetries; attempt++ {
|
||
resp, err := c.doRequest(ctx, ...)
|
||
if err == nil && resp.StatusCode < 500 && resp.StatusCode != 429 {
|
||
return resp, nil
|
||
}
|
||
if attempt < maxRetries {
|
||
time.Sleep(backoff * time.Duration(1<<attempt)) // exponential
|
||
}
|
||
}
|
||
return lastResp, lastErr
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### P1-4: Polling с фиксированным интервалом 5с
|
||
|
||
**Где:** `instance_ops.go:81` — `time.NewTicker(5 * time.Second)`
|
||
|
||
**Проблема:**
|
||
- Для быстрых операций (suspend ~10с) — 5с интервал нормально
|
||
- Для долгих (create VM ~5мин) — 5с создаёт лишние API-запросы
|
||
- Нет adaptive polling (увеличение интервала со временем)
|
||
|
||
**Решение:**
|
||
```go
|
||
// Adaptive polling: 3s → 5s → 10s → 15s → 30s (max)
|
||
intervals := []time.Duration{3*time.Second, 5*time.Second, 10*time.Second, 15*time.Second, 30*time.Second}
|
||
```
|
||
|
||
---
|
||
|
||
### P1-5: FindInstanceByDisplayName — неточный поиск
|
||
|
||
**Где:** `instance_lookup.go:29`
|
||
|
||
**Проблема:** Ищет подстрокой по `displayName`, нет exact match. Если есть "mydb" и "mydb-test", может вернуть неверный инстанс.
|
||
|
||
**Решение:** Добавить exact match фильтр после получения результатов:
|
||
```go
|
||
if instance.DisplayName == displayName { // exact match
|
||
return instance, nil
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Средний приоритет (P2)
|
||
|
||
### P2-1: Дублирование client.go между legacy и universal_rebuild
|
||
|
||
Два файла `client.go`:
|
||
- `internal/core/client.go` (1065 строк, V1–V6)
|
||
- `universal_rebuild/internal/core/client.go` (1034 строк, V6 + refSvc)
|
||
|
||
**Решение:** Legacy provider постепенно заменяется universal_rebuild. Не рефакторить — просто фиксировать (freeze) legacy.
|
||
|
||
---
|
||
|
||
### P2-2: Update() не реализован в большинстве ресурсов
|
||
|
||
Сгенерированные ресурсы через `gen_v2` уже генерируют Update() если у сервиса есть `modify` операция. Ручные ресурсы (edge, vdc, org) — нет.
|
||
|
||
**Решение:** Для ручных ресурсов — оставить как есть (ForceNew), если modify не критичен. Для generated — уже работает.
|
||
|
||
---
|
||
|
||
### P2-3: Нет валидации YAML-спецификаций
|
||
|
||
Генератор `01_generate_yamls.sh` → YAML → `gen_v2` — нет промежуточной валидации YAML на корректность/полноту.
|
||
|
||
**Решение:** Добавить JSON Schema для YAML-спецификаций и валидировать перед генерацией.
|
||
|
||
---
|
||
|
||
### P2-4: Нормализация параметров — разные стратегии
|
||
|
||
| Версия | Стратегия normalization |
|
||
|--------|------------------------|
|
||
| V1-V2 | empty → empty |
|
||
| V3-V4 | empty → `{}` (map) / `[]` (array) |
|
||
| V5-V6 | TrimSpace + null-string + `\"\"` → empty |
|
||
|
||
**Решение:** Зафиксировать V6 behavior как единственный стандарт. Задокументировать.
|
||
|
||
---
|
||
|
||
### P2-5: Отсутствие structured logging
|
||
|
||
- `tflog` используется, но нет единого формата
|
||
- Нет trace ID / correlation ID для chain запросов
|
||
- Debug-лог в файл вместо terraform framework
|
||
|
||
**Решение:** Стандартизировать tflog с трейсами:
|
||
```go
|
||
tflog.Debug(ctx, "API request", map[string]interface{}{
|
||
"method": "POST",
|
||
"url": url,
|
||
"instance_uid": uid,
|
||
"operation": opName,
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Анализ по слоям
|
||
|
||
### 6.1 Provider Layer
|
||
|
||
| Аспект | Legacy | Universal Rebuild |
|
||
|--------|--------|-------------------|
|
||
| Auth | token/env/file ✅ | token/env/file ✅ |
|
||
| TLS | InsecureSkipVerify 🔴 | InsecureSkipVerify 🔴 |
|
||
| HTTP Timeout | 300s | Configurable ✅ |
|
||
| Resources | 13 (ручные) | 50+ (генерируемые) |
|
||
| Schema | Hand-written | Generated from YAML ✅ |
|
||
|
||
### 6.2 Resource Layer
|
||
|
||
**Legacy ресурсы (ручные):**
|
||
- VM — лучший: полный CRUD, import, status polling, рабочие timeout'ы
|
||
- Edge — хороший: multi-step create, operation discovery
|
||
- VDC — хороший: triggers для пересоздания
|
||
- Postgres, PgAdmin, Org — минимальные, часть Methods не реализованы
|
||
|
||
**Universal ресурсы (generated):**
|
||
- Полный CRUD для instance если есть create/modify/suspend operations
|
||
- Subresource (user, database) с ForceNew если нет modify
|
||
- Action (restart, recovery) с trigger field `run_id`
|
||
- Lifecycle flags: `suspend_on_destroy`, `adopt_existing_on_create` ✅
|
||
- State refresh через `RefreshResourceState` ✅
|
||
|
||
### 6.3 Core Layer
|
||
|
||
**Сильные стороны:**
|
||
- Единый API flow (V6): create → init op → send params → validate → run → wait
|
||
- Timeout management с override per-service
|
||
- RefSvc resolution (linked services)
|
||
- Operation polling с dtFinish проверкой
|
||
|
||
**Слабые стороны:**
|
||
- Нет retry / circuit breaker
|
||
- Фиксированный polling interval
|
||
- 6 версий Create в legacy (мусор)
|
||
- Debug log в файл (hardcoded path)
|
||
|
||
### 6.4 CRUD Layer (`resources_core/`)
|
||
|
||
**Сильные стороны:**
|
||
- `adoptExistingInstanceOnCreate()` — базовая adopt-логика
|
||
- `RefreshResourceState` — generic state sync с type conversion
|
||
- `RequiredParamsMismatch()` — сравнение params при adopt
|
||
- `resource_diagnostics.go` — форматированные диагностики
|
||
|
||
**Слабые стороны:**
|
||
- Decision matrix из philosophy § 7 не полностью реализована
|
||
- Delete behavior: "state_only" по умолчанию если пустая строка — нарушает `suspend_on_destroy=true` default
|
||
- Нет обработки статусов `creating`, `pending`, `failed`
|
||
|
||
---
|
||
|
||
## 7. Эволюция API-клиента
|
||
|
||
```
|
||
V1 (simple)
|
||
│ + server defaults
|
||
V2 (Universal)
|
||
│ + name/code hints для normalization
|
||
V3 (UniversalV2)
|
||
│ + label field
|
||
V4 (UniversalV3)
|
||
│ + TrimSpace, null → empty
|
||
V5 (UniversalV4)
|
||
│ + debug file logging, `\"\"` handling
|
||
V6 (UniversalV5) ← PRODUCTION (legacy provider)
|
||
│
|
||
└─→ V6 Rebuilt ← PRODUCTION (universal_rebuild)
|
||
+ refSvc resolution
|
||
+ configurable timeouts
|
||
+ ensureInstanceCreated()
|
||
+ operation timeout per-service
|
||
```
|
||
|
||
**Рекомендация:**
|
||
- Legacy V1-V5 → пометить deprecated, не удалять (immutability policy)
|
||
- В перспективе: legacy provider замораживается, весь development идёт в `universal_rebuild`
|
||
|
||
---
|
||
|
||
## 8. Генератор кода v2
|
||
|
||
### Архитектура генератора
|
||
|
||
```
|
||
tools/gen_v2/generate_resources_v2.go (~2500 LOC)
|
||
│
|
||
├── loadSpecs() → Парсинг YAML per-service
|
||
│ ├── Instance operations → GenResource
|
||
│ ├── Subresource operations → GenSubresource
|
||
│ └── Action operations → GenAction
|
||
│
|
||
├── writeInstanceResource() → Go template → *_resource.go
|
||
├── writeSubresource() → Go template → *_subresource.go
|
||
├── writeActionResource() → Go template → *_action.go
|
||
└── writeRegistry() → registry.go (список всех ресурсов)
|
||
```
|
||
|
||
### Что генерирует
|
||
|
||
Для каждого сервиса от 1 до 3 файлов:
|
||
|
||
1. **Instance Resource** (`90_postgres_resource.go`):
|
||
- `Schema()` — из YAML params (create + modify)
|
||
- `Create()` → `resources_core.CreateResourceWithTimeout()`
|
||
- `Read()` → `resources_core.RefreshResourceState()`
|
||
- `Update()` → `resources_core.UpdateResourceWithTimeout()` (если есть modify)
|
||
- `Delete()` → `resources_core.DeleteResourceWithTimeout()`
|
||
- `ImportState()` → passthrough ID
|
||
|
||
2. **Subresource** (`90_postgres_user_resource.go`):
|
||
- ForceNew для всех params (если нет modify_user)
|
||
- Create → `RunOperationByCode("create_user")`
|
||
- Delete → `RunOperationByCode("delete_user")`
|
||
|
||
3. **Action** (`90_postgres_restart.go`):
|
||
- Trigger field `run_id` (PlanModifier: UseStateForUnknown)
|
||
- Create → `RunOperationByCode("restart")`
|
||
|
||
### Сильные стороны генератора
|
||
|
||
- ✅ Единый YAML → Go pipeline
|
||
- ✅ Canonical lifecycle flags (`suspend_on_destroy`, `adopt_existing_on_create`)
|
||
- ✅ RefSvc resolution для linked services
|
||
- ✅ ForceNew detection для create-only params
|
||
- ✅ Type mapping (string/bool/int64)
|
||
- ✅ Auto-registry generation
|
||
|
||
### Слабые стороны
|
||
|
||
- ❌ Не генерирует `*_test.go`
|
||
- ❌ Нет go fmt / go vet на generated output
|
||
- ❌ Нет YAML schema validation перед генерацией
|
||
- ❌ Нет diff-отчёта (что изменилось при регенерации)
|
||
- ⚠️ Template embedded inline (не отдельные `.tmpl` файлы) — сложно поддерживать при росте
|
||
|
||
---
|
||
|
||
## 9. Соответствие provider_philosophy.md
|
||
|
||
### Матрица статусов (§7)
|
||
|
||
| Статус инстанса | adopt=false | adopt=true | Реализовано? |
|
||
|-----------------|-------------|------------|--------------|
|
||
| Not found / Deleted | Create | Create | ✅ |
|
||
| Suspended | **Hard error** | Resume + Adopt | ⚠️ Частично |
|
||
| Running | **Hard error** | Adopt (import) | ⚠️ Частично |
|
||
| Not Created | **Hard error** | **Hard error** | ❌ Нет проверки |
|
||
| Creating/Pending | **Hard error** | **Hard error** | ❌ Нет проверки |
|
||
| Failed | **Hard error** | **Hard error** | ❌ Нет проверки |
|
||
|
||
### Destroy behavior (§7)
|
||
|
||
| Флаг | Действие | Реализовано? |
|
||
|------|----------|--------------|
|
||
| `suspend_on_destroy=true` (default) | Suspend | ✅ |
|
||
| `suspend_on_destroy=false` | State-only | ✅ |
|
||
|
||
### Diagnostics format (§8)
|
||
|
||
**Требуется:**
|
||
```
|
||
resource_name: mydb
|
||
service_id: 90
|
||
instance_uid: abc-123
|
||
status: running
|
||
status_raw: Running
|
||
flag: adopt_existing_on_create = false
|
||
decision: Error — instance already exists
|
||
action: Set adopt_existing_on_create = true or rename resource
|
||
```
|
||
|
||
**Реализовано:** `resource_diagnostics.go` реализует multi-line format, но не все поля и не все кейсы.
|
||
|
||
### GAP Analysis
|
||
|
||
| Требование | Статус | Файл |
|
||
|------------|--------|------|
|
||
| Canonical flags in schema | ✅ | gen_v2 templates |
|
||
| Decision matrix on Create | ⚠️ 60% | crud.go |
|
||
| Hard error on "Not Created" | ❌ | crud.go |
|
||
| Hard error on "Creating/Pending/Failed" | ❌ | crud.go |
|
||
| Multi-line diagnostics | ⚠️ 70% | resource_diagnostics.go |
|
||
| Param mismatch check on adopt | ✅ | required_params_compare.go |
|
||
| Plan messages with cloud status | ❌ | Not implemented |
|
||
|
||
---
|
||
|
||
## 10. Тестирование
|
||
|
||
### Текущее состояние
|
||
|
||
**Тестовых файлов:** 0
|
||
**Unit tests:** 0
|
||
**Integration tests:** 0
|
||
**Acceptance tests:** 0
|
||
|
||
### План тестирования
|
||
|
||
#### Фаза 1: Unit Tests для Core (приоритет — P0)
|
||
|
||
| Тест | Файл | Покрытие |
|
||
|------|------|----------|
|
||
| `TestNormalizeUniversalValue` | `core/client_test.go` | Нормализация всех типов |
|
||
| `TestIsInstanceDeleted` | `core/instance_lookup_test.go` | Все статусы |
|
||
| `TestIsStatusSuspended` | `core/crud_test.go` | Edge cases |
|
||
| `TestAdoptLogicMatrix` | `core/crud_test.go` | Все комбинации status × adopt flag |
|
||
| `TestParamsMismatch` | `core/params_compare_test.go` | Сравнение params |
|
||
| `TestRefreshResourceState` | `core/state_refresh_test.go` | Type conversion |
|
||
| `TestOperationTimeoutParsing` | `core/timeouts_test.go` | Config loading |
|
||
| `TestResolveRefSvcParam` | `core/refsvc_test.go` | UUID ↔ display_name |
|
||
|
||
**Оценка:** ~40 test cases, ~800 LOC
|
||
|
||
#### Фаза 2: Integration Tests (приоритет — P1)
|
||
|
||
| Тест | Описание |
|
||
|------|----------|
|
||
| `TestCreateAndDeleteInstance` | Full lifecycle на test stand |
|
||
| `TestAdoptExistingInstance` | Create → suspend → re-create with adopt=true |
|
||
| `TestModifyInstance` | Create → modify → verify params changed |
|
||
| `TestSubresourceLifecycle` | User create → delete |
|
||
| `TestActionExecution` | Restart trigger |
|
||
|
||
**Требуется:** Test stand (dev profile) + test service (dummy/bolvanka)
|
||
|
||
#### Фаза 3: Acceptance Tests (приоритет — P2)
|
||
|
||
```bash
|
||
TF_ACC=1 go test ./internal/... -v -run TestAcc
|
||
```
|
||
|
||
С реальным Terraform CLI: plan → apply → verify → destroy.
|
||
|
||
---
|
||
|
||
## 11. Безопасность
|
||
|
||
### Текущие уязвимости
|
||
|
||
| # | Уязвимость | OWASP | Severity | Где |
|
||
|---|-----------|-------|----------|-----|
|
||
| S1 | InsecureSkipVerify=true | A07:Crypto Failures | CRITICAL | provider.go:103 |
|
||
| S2 | Hardcoded debug log path | A05:Security Misconfig | HIGH | core/client.go:18 |
|
||
| S3 | Нет input validation на API responses | A03:Injection | MEDIUM | core/client.go |
|
||
| S4 | Token в памяти без rotation | A07:Auth Failures | MEDIUM | provider.go |
|
||
| S5 | Нет rate limiting | A04:Insecure Design | LOW | core/client.go |
|
||
| S6 | Secrets в репозитории (secrets/) | A05:Security Misconfig | HIGH | secrets/ |
|
||
|
||
### Рекомендации по безопасности
|
||
|
||
1. **S1:** `insecure` flag в provider schema (default: false), env var `NUBES_INSECURE`
|
||
2. **S2:** Удалить файловый debug log, использовать только `tflog`
|
||
3. **S3:** Валидировать JSON responses на ожидаемые поля
|
||
4. **S6:** Перенести secrets в vault / CI variables, добавить в `.gitignore`
|
||
|
||
---
|
||
|
||
## 12. Дорожная карта (Roadmap)
|
||
|
||
### Фаза 0: Стабилизация (текущая — P0 fixes)
|
||
|
||
| # | Задача | Объём | Зависимости |
|
||
|---|--------|-------|-------------|
|
||
| 0.1 | Сделать InsecureSkipVerify конфигурируемым | 25 LOC | — |
|
||
| 0.2 | Заменить hardcoded debug log на tflog/env var | 15 LOC | — |
|
||
| 0.3 | Пометить V1–V5 CreateGenericInstance deprecated | Комментарии | — |
|
||
| 0.4 | Unit tests для core layer (Фаза 1) | ~800 LOC | — |
|
||
| 0.5 | Добавить secrets/ в .gitignore | 1 строка | — |
|
||
|
||
### Фаза 1: Compliance с provider_philosophy.md
|
||
|
||
| # | Задача | Объём | Зависимости |
|
||
|---|--------|-------|-------------|
|
||
| 1.1 | Полная decision matrix в crud.go | ~100 LOC | 0.4 |
|
||
| 1.2 | Hard error для "Not Created", "Creating", "Failed" | ~50 LOC | 1.1 |
|
||
| 1.3 | Multi-line diagnostics для всех кейсов | ~100 LOC | 1.1 |
|
||
| 1.4 | Plan messages с cloud status | ~80 LOC | 1.1 |
|
||
| 1.5 | Integration test для adopt matrix | ~200 LOC | 1.1 |
|
||
|
||
### Фаза 2: Надёжность
|
||
|
||
| # | Задача | Объём | Зависимости |
|
||
|---|--------|-------|-------------|
|
||
| 2.1 | Retry с exponential backoff для API-вызовов | ~80 LOC | — |
|
||
| 2.2 | Adaptive polling intervals | ~40 LOC | — |
|
||
| 2.3 | Exact match в FindInstanceByDisplayName | ~10 LOC | — |
|
||
| 2.4 | YAML schema validation перед генерацией | ~200 LOC | — |
|
||
| 2.5 | go fmt + go vet в pipeline генерации | ~10 LOC | — |
|
||
|
||
### Фаза 3: Масштабирование
|
||
|
||
| # | Задача | Объём | Зависимости |
|
||
|---|--------|-------|-------------|
|
||
| 3.1 | Генерация *_test.go в gen_v2 | ~500 LOC | 2.4 |
|
||
| 3.2 | Diff-отчёт при регенерации | ~200 LOC | — |
|
||
| 3.3 | Acceptance tests (TF_ACC) | ~500 LOC | 1.5 |
|
||
| 3.4 | Structured logging с trace ID | ~150 LOC | — |
|
||
| 3.5 | CI pipeline (build → test → publish) | Config | 3.1, 3.3 |
|
||
|
||
### Фаза 4: Production Hardening
|
||
|
||
| # | Задача | Объём | Зависимости |
|
||
|---|--------|-------|-------------|
|
||
| 4.1 | Заморозить legacy provider (internal/) | Процесс | 3.5 |
|
||
| 4.2 | Миграция ручных ресурсов в universal_rebuild | Большая | 4.1 |
|
||
| 4.3 | Мониторинг generation stability | Infra | 3.5 |
|
||
| 4.4 | Нагрузочное тестирование (параллельный apply) | ~200 LOC | 3.3 |
|
||
|
||
---
|
||
|
||
## 13. Рекомендации по агенту/модели
|
||
|
||
### Выбор модели для разных задач
|
||
|
||
| Тип задачи | Рекомендуемый агент | Почему |
|
||
|-------------|---------------------|--------|
|
||
| **Архитектурные решения** | Claude Opus 4.6 (текущий) | Глубокий контекст, сложная логика |
|
||
| **Отладка сложных багов** | Claude Opus 4.6 | Лучше держит контекст, видит неочевидные связи |
|
||
| **Анализ codebase, code review** | Claude Opus 4.6 | Качество анализа выше |
|
||
| **Генерация Go-кода по шаблонам** | Claude Sonnet 4.6 | Достаточно для шаблонного кода, экономичнее |
|
||
| **Написание тестов** | Claude Sonnet 4.6 | Шаблонная работа |
|
||
| **Массовые правки в генераторе** | Claude Sonnet 4.6 | Достаточно контекста в одном файле |
|
||
| **Правки shell-скриптов** | Claude Sonnet 4.6 | Простые правки |
|
||
| **Документация** | Claude Sonnet 4.6 | Текстовая генерация |
|
||
| **Lifecycle state machine** | Claude Opus 4.6 | Сложные state transitions |
|
||
| **API reverse-engineering** | Claude Opus 4.6 | Нужен глубокий анализ HAR/JSON |
|
||
|
||
### Стратегия переключения
|
||
|
||
1. **Планирование и design review** → Opus 4.6
|
||
2. **Имплементация запланированного** → Sonnet 4.6
|
||
3. **Баг не воспроизводится / непонятная причина** → Opus 4.6
|
||
4. **Регенерация и routine CI** → Sonnet 4.6
|
||
|
||
### Практический совет
|
||
|
||
Для текущей фазы развития (стабилизация + compliance):
|
||
- **Opus 4.6** для задач 1.1–1.4 (lifecycle decision matrix — сложная логика)
|
||
- **Sonnet 4.6** для задач 0.1–0.5, 2.1–2.5, 3.1 (шаблонные правки, тесты)
|
||
|
||
---
|
||
|
||
## Приложение A: Ключевые файлы для изучения
|
||
|
||
| Приоритет | Файл | Зачем |
|
||
|-----------|------|-------|
|
||
| ★★★ | `docs/60_strategy/provider_philosophy.md` | Канон lifecycle-логики |
|
||
| ★★★ | `universal_rebuild/internal/resources_core/crud.go` | CRUD + adopt-логика |
|
||
| ★★★ | `universal_rebuild/internal/core/client.go` | API V6 flow |
|
||
| ★★☆ | `universal_rebuild/tools/gen_v2/generate_resources_v2.go` | Генератор |
|
||
| ★★☆ | `universal_rebuild/internal/resources_core/state_refresh.go` | State sync |
|
||
| ★★☆ | `universal_rebuild/internal/resources_core/resource_diagnostics.go` | Диагностики |
|
||
| ★☆☆ | `devops/ARCHITECTURE.md` | Build pipeline design |
|
||
| ★☆☆ | `internal/core/client.go` | Legacy reference (V1–V6) |
|
||
|
||
## Приложение B: Команды для быстрого старта
|
||
|
||
```bash
|
||
# Проверка компиляции (universal_rebuild)
|
||
cd universal_rebuild && go build ./...
|
||
|
||
# Проверка компиляции (legacy)
|
||
cd /home/naeel/remote_dev/terraform && go build ./...
|
||
|
||
# Генерация YAML из API
|
||
cd devops && bash 01_generate_yamls.sh
|
||
|
||
# Генерация Go-кода из YAML
|
||
cd devops && bash 02_generate_resources_and_docs_template_v2.sh
|
||
|
||
# Сборка провайдера
|
||
cd devops && bash 03_build_and_upload_provider.sh
|
||
|
||
# Публикация документации
|
||
cd devops && bash 04_build_and_publish_docs.sh
|
||
```
|
||
|
||
---
|
||
|
||
*Документ сформирован автоматически на основе полного анализа кодовой базы. Обновлять при существенных архитектурных изменениях.*
|