9.2 KiB
2026-07-06 — Архитектурный рефакторинг tf_provider
Контекст
После анализа Claude Opus (HISTORY/OPUS/2026-07-06_architectural_analysis.md) выявлены архитектурные проблемы и выполнены исправления.
Выполненные изменения
1. Реструктуризация проекта
Было: Стало:
devops/ TOOLS/scripts/ (все .sh)
devops/profiles/ TOOLS/config/ (profile.env, services_list, timeouts)
devops/ARCHITECTURE.md TOOLS/ARCHITECTURE.md
devops/config/ УДАЛЕНО (дубликат profiles)
provider/resources_yaml/ УДАЛЕНО (сгенерированное → generated/)
provider/internal/resources_gen/ УДАЛЕНО (сгенерированное → generated/)
generated/{test,prod,dev}/ (вывод пайплайна)
2. Независимость генераторов
yaml-generator— требуетNUBES_OUTPUT_DIR, без default вprovider/resource-generator— требуетNUBES_RESOURCES_DIR+NUBES_RESOURCES_GEN_DIRdocs-generator— требует--resources,--docs,--versionфлаги- Удалён
detectVersion()— больше не читаетprovider/main.go - Удалён
detectRoot(),pickPath()— нет хардкод-путей
3. Общая библиотека типов
Создан TOOLS/lib/ — единый YAML-контракт. Модуль: tf-tools/lib.
Подключены:
yaml-generator→ type aliasParamSpec = lib.ParamSpecи др.resource-generator→ type aliasOutputParam,OperationSpec,ParamSpec
НЕ подключён:
docs-generator— будет заменён на LLM-генератор, не трогаем
При добавлении поля в YAML — править lib/types.go, несогласованность ловится компилятором.
4. Синхронизация версий
provider/main.go: 5.0.75 → 5.0.60 (соответствует последней сборке)profile.env: три переменные → однаVERSION03_build,04_publish:${PROVIDER_VERSION:-${RELEASE_VERSION:-}}→${VERSION}
5. Автосборка бинарников
01_generate_yamls.sh: если исходники новее бинарника — пересборка.
6. Удалённый мусор
devops/config/— дубликат profiles02_generate_resources_and_docs.sh+_template.sh— legacy, заменены v2cloud-dashboard/,tools/(root),internal/(root),universal_rebuild/- 18 одноразовых файлов (check_ops.py, s.sh, ...)
7. Слияние ops-generator → docs-generator
--ops флаг. Три генератора вместо четырёх.
8. Документация LLM
docs/LLM_DOCS_GENERATION.md — подход, промпт, тест на Postgres (gpt-oss-120b, 9/10).
Текущее состояние
tf_provider/
├── TOOLS/ — всё для генерации (код + скрипты + настройки)
│ ├── yaml-generator/
│ ├── resource-generator/
│ ├── docs-generator/
│ ├── lib/ — общие YAML-типы
│ ├── scripts/
│ ├── config/{test,prod,dev}/
│ └── ARCHITECTURE.md
├── provider/ — только исходники
├── generated/ — вывод пайплайна (gitignored)
└── docs/ — документация
Осталось
- yaml-generator → lib
- resource-generator → lib
- docs-generator → lib
⚠️ BUG: modify падает с 500 — GET ?fields=cfsParams вызывает getResourceRealmConfig
Симптом: terraform apply при modify возвращает:
не удалось получить детали операции: ошибка API 500: Invalid call of the function [getResourceRealmConfig], first Argument [resourceRealm] is of invalid type, Cannot cast Object type [Struct] to a value of type [string]
Причина: RunInstanceOperationUniversalWithDefaults (client.go:384) делает GET /instanceOperations/{opUid}?fields=cfsParams. Бэкенд (ColdFusion) при вычислении cfsParams вызывает getResourceRealmConfig через expression_parser.cfc:184. Если resourceRealm в контексте инстанса — Struct (объект), а не string, функция падает.
Где проявляется:
client.go:420—RunInstanceOperationUniversalWithDefaults(modify/create/delete с дефолтами)client.go:1399—RunInstanceOperationUniversalByCode(операции по code)client.go:224—CreateGenericInstanceUniversalV6(CREATE flow) — работает на новых инстансах
Почему на одних инстансах падает, на других нет:
- Новые инстансы:
resourceRealm= string → OK - Старые/модифицированные:
resourceRealm= Struct → 500
Исправление (v5.0.62):
crud.go:58:UpdateResourceWithTimeout→RunInstanceOperationUniversal(без GET)- GET не нужен для modify — все параметры уже известны из конфига
Статус: ✅ FIXED v5.0.62 Файлы:
/home/naeel/tf_provider/provider/internal/resources_core/crud.go:58/home/naeel/tf_provider/provider/internal/core/client.go:384(WithDefaults — не используется в modify)
Тесты (v5.0.62):
- ✅ CREATE postgres — OK
- ✅ MODIFY postgres (replicas, backup_config, access_config) — OK
- ✅ CREATE/DELETE user — OK
- ✅ CREATE/DELETE database — OK
- ✅ Invalid role → 400 c понятным сообщением — OK
- ✅ No-change plan (идемпотентность) — OK
Остаётся риск:
RunInstanceOperationUniversalByCode(client.go:1399) всё ещё делает GET — может упасть для service_operation_resource на проблемных инстансахCreateGenericInstanceUniversalV6(client.go:224) — CREATE на инстансах где resourceRealm = Struct может упасть
⚠️ BUG: Параллельные операции на одном инстансе ломаются
Симптом: При создании нескольких subresource'ов (user, database) на одном postgres-инстансе:
ошибка API 500: Cannot connect to the orchestrator— бэкенд не справляется с параллельными запросамиоперация завершилась успешно, но объект не найден в state_out— user создался, но RefreshResourceState не видит егоэкземпляр не готов: операция в ожидании— инстанс занят предыдущей операцией
Причина: Terraform по умолчанию параллелит до 10 ресурсов (-parallelism=10). Все операции на одном инстансе (5 user'ов + 7 database'ов) стартуют одновременно → гонка на бэкенде.
Пример: 2026-07-07 на инстансе 5111108D:
- 5 user'ов создавались параллельно: user_2 ok, user_1+user_3 — orchestrator error, user_4+user_5 — state_out не найден
- 7 database'ов упали: инстанс не готов
План исправления: mutex map в провайдере (стандартный подход как в AWS/GCP провайдерах):
// client.go — глобальная карта мьютексов
var instanceMutexes sync.Map // key: instanceUid
func (c *UniversalClient) lockInstance(instanceUid string) func() {
mu, _ := c.instanceMutexes.LoadOrStore(instanceUid, &sync.Mutex{})
mu.(*sync.Mutex).Lock()
return func() { mu.(*sync.Mutex).Unlock() }
}
Вызывать в каждом CRUD:
unlock := client.lockInstance(instanceID)
defer unlock()
Альтернативы (хуже):
depends_onцепочкой в конфиге — неудобно, требует ручной правки .tf-parallelism=1— замедляет ВСЕ ресурсы, не только subresource'ы
Затрагивает:
- Все subresource-операции (postgres_user, postgres_database, mariadb_user, clickhouse_user, etc.)
- Modify + delete на одном инстансе тоже могут столкнуться
Статус: ⚠️ OPEN — не исправлено Файлы для правки:
/home/naeel/tf_provider/provider/internal/core/client.go— добавить mutex map + lockInstance/home/naeel/tf_provider/provider/internal/resources_core/crud.go— добавить lock/unlock в Create/Update/Delete/home/naeel/tf_provider/provider/internal/resources_core/service_operation_resource.go— добавить lock/unlock