1. Version sync: provider/main.go = profile.env = 5.0.60 2. docs-generator: removed detectVersion() — no more dependency on provider/ 3. docs-generator: removed detectRoot(), pickPath() — all paths via flags/env 4. docs-generator: require --version, --resources, --docs flags 5. Auto-rebuild: yaml-generator rebuilds if sources newer than binary 6. Three version vars → one VERSION in profile.env 7. Created TOOLS/lib/ — shared YAML contract types (not yet integrated)
9.8 KiB
Архитектурный анализ tf_provider — 2026-07-06
Кто делал: Claude Opus (по запросу пользователя) Метод: Анализ реальной файловой структуры репозитория (не только промпт) Выводы: Без предложений по рефакторингу, без кода
1. Разделение ответственности TOOLS / generated / provider
Разделение проведено чисто и последовательно. Три вершины треугольника не смешиваются: TOOLS — только инструменты сборки, generated — только продукт (полностью в .gitignore), provider — только исходники универсального ядра. Границы соблюдаются на уровне файловой системы, а не договорённостей, что делает их устойчивыми.
Ключевое наблюдение: provider не является самодостаточным Go-модулем. internal/resources_core/*.go на этапе компиляции импортируют пакеты terraform-provider-nubes/resources_yaml и internal/resources_gen, а provider.go вызывает resources_gen.AllResources(). Обе директории gitignored и физически отсутствуют в репозитории — они появляются только при сборке. Следствие: provider в чистом виде не собирается и не проходит go build/go test без предварительного прогона генераторов. Ядро формально отделено от сгенерированного кода, но связано с ним жёсткой компиляционной зависимостью через импорты пакетов, а не через интерфейс.
2. Пайплайн
Пайплайн линейный и предсказуемый (API → YAML → Go/docs → build → S3). Узкие места:
- Двойное копирование через temp-директории. И
02_...(resource-generator пишет в temp, потом копирует вgenerated/{stand}/go/), и03_...(весь provider копируется вmktemp -d, сверху накладываются YAML и Go) используют промежуточные каталоги. Для03это оправдано изоляцией по стендам, для02— лишний слой. - Предсобранные бинарники в bin. Скрипты вызывают готовые
yaml-generator/resource-generator/docs-generator, но большинство скриптов их не пересобирают. Это тихий источник рассинхрона: правкаmain.goгенератора не влияет на результат, пока бинарник не пересобран вручную. - Разросшийся набор скриптов. Помимо основных 01–04 есть
template_v2,10–13, стабилизационные прогоны. Нумерация уже не отражает реальный порядок, часть скриптов дублирует функциональность (02_...v2vs02_...template_v2).
3. Конфигурация стендов
profile.env содержит ~14 переменных, смешивая три разных класса:
- (а) параметры окружения (endpoint, namespace, registry host)
- (б) версии (
RELEASE_VERSION=PROVIDER_VERSION=DOCS_VERSION— три идентичных значения) - (в) пути к секретам (GPG-ключи, S3-конфиг, token-файл)
Смешение секретов и конфигурации в одном env-файле — главный риск этого узла: легко утечь при копировании, трудно ротировать. Дублирование версии в трёх переменных — источник рассинхрона (плюс версия ещё и захардкожена в main.go = 5.0.75, при том что test/profile.env = 5.0.60; фактически версия живёт в двух местах и они уже разошлись).
4. Сборка provider через temp-копирование vs go:embed
Текущая модель — физическое копирование provider в temp + наложение generated сверху. go:embed используется только для operation_timeouts.json.
Наблюдения:
- Для сгенерированного Go-кода
go:embedв принципе неприменим — это компилируемые пакеты, а не данные; их нельзя «встроить», только скомпилировать. Так что альтернативы копированию здесь по сути нет, вопрос лишь в том, копировать в temp или прямо вprovider/internal/resources_gen/. - Для YAML-спеков, которые читаются в рантайме (
resources_coreподгружает метаданные из пакетаresources_yaml), уже применяется гибрид: вgenerated/{stand}/resources_yaml/лежитembed.go. То есть YAML встраивается в бинарник через embed на стороне генерируемого пакета — это консистентно. - Плата за temp-подход: невозможность запустить IDE/линтер/тесты на «настоящем» дереве, потому что рабочее дерево неполно. Отладка идёт по эфемерной копии.
5. Генераторы — дублирование
Три генератора — три независимых Go-модуля, каждый со своим go.mod и единственной зависимостью gopkg.in/yaml.v3. Структуры ServiceSpec, OperationSpec, ParamSpec, OutputParam продублированы в трёх отдельных internal/types/. Общей библиотеки нет.
Это самый явный архитектурный долг: YAML — это фактический контракт между генераторами, но контракт не выражен единым типом. Добавление поля в спеку требует синхронной правки трёх файлов; расхождение проявится только в рантайме или в кривом выводе, без ошибки компиляции. Функционально генераторы не пересекаются (у каждого своя роль), пересекаются именно модели данных.
Дополнительно: docs-generator (самый крупный, ~316 строк) имеет второй режим --ops с отдельным входом resources_ops_yaml/ — то есть в нём живут фактически два генератора с разными источниками, что размывает его единую ответственность.
6. Архитектурные риски — что сломается первым
- Дрейф YAML-контракта между генераторами — самое вероятное первое место поломки. Дублированные структуры разойдутся при любой эволюции схемы.
- Рассинхрон версии — уже произошёл (
main.go5.0.75 vsprofile.env5.0.60). Версия определена в нескольких местах без единого источника. - Устаревшие бинарники в bin — правка исходников генератора не даёт эффекта без ручной пересборки; ошибка молчаливая.
- Хрупкость provider как модуля — нельзя собрать/протестировать без прогона всего пайплайна; CI и локальная разработка вынуждены проходить полный цикл, чтобы получить компилируемое дерево.
- Смена API (
deck-api→lk-api-gateway) локализована вyaml-generator(авто-детект поindex.cfmв URL) — это хорошо изолировано и риск здесь низкий; но тот же эндпоинт продублирован дефолтом вdocs-generator, то есть точка знания об API размазана по двум генераторам. - Секреты в
profile.env— операционный риск утечки при копировании конфигов между стендами.
Итог: структура сильна по вертикальному разделению (инструменты/продукт/исходники) и слаба по горизонтальным контрактам между компонентами — модель данных YAML, версия и знание об API-эндпоинте не имеют единого источника и продублированы в нескольких местах. Первым сломается именно то, что продублировано.