# Полный анализ кодовой базы и план развития **Дата:** 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<