From 1739120a98b66997839515cddc4c10dd7bd29666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Tue, 30 Jun 2026 18:08:19 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20Opus=20analysis=20round=202=20=E2=80=94?= =?UTF-8?q?=20full=20audit=20of=20generation=20scripts=20(bash=20+=20Go=20?= =?UTF-8?q?tools=20+=20CI=20+=20profiles)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HISTORY/OPUS/3006_2_scripts_analysis.md | 137 ++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 HISTORY/OPUS/3006_2_scripts_analysis.md diff --git a/HISTORY/OPUS/3006_2_scripts_analysis.md b/HISTORY/OPUS/3006_2_scripts_analysis.md new file mode 100644 index 0000000..7d1fefd --- /dev/null +++ b/HISTORY/OPUS/3006_2_scripts_analysis.md @@ -0,0 +1,137 @@ +# Анализ генерационных скриптов — 30.06.2026 (сессия 2) + +**Исполнитель:** Opus 4.8 +**Задача:** аудит 4 bash-скриптов, 6 Go-тулов, профилей, CI — как API-данные превращаются в YAML, Go-код и документацию + +--- + +## Вопрос 1: Bash-скрипты — аудит 4 файлов + +**Прочитал:** все 4 скрипта полностью. + +| Аспект | 01_yamls | 02_docs_v2 | 03_build | 04_publish | +|--------|---------|-----------|---------|-----------| +| `set -euo pipefail` | ✅ | ✅ | ✅ | ✅ | +| `trap` cleanup | ❌ | ✅ | ✅ | ✅ | +| API error handling | 🔴 НЕТ | — | — | — | +| User-Agent в urllib | 🔴 НЕТ | — | — | — | +| Проверка зависимостей (`command -v`) | ❌ | ❌ | ❌ | ✅ | +| Идемпотентность (`rm` старого) | ✅ | ✅ | ✅ | ✅ | +| Lock-файлы (параллельный запуск) | ❌ | ❌ | ❌ | ❌ | +| Профиль обязателен | ✅ | ✅ | ✅ | ❌ | + +**Проблемы:** +- 🔴 **01_generate_yamls.sh** — python `urllib` ставит только `Authorization`, без User-Agent → дефолтный `Python-urllib/3.x` → DDoS-Guard зарежет. **P0** +- 🔴 **01_generate_yamls.sh** — нет обработки 500/битый JSON/пустой ответ → необработанный Python traceback вместо retry. **P0** +- 🟠 Пустой `services_list.txt` не ловится — 01_generate_yamls.sh проверяет только существование файла → «успех» без генерации. **P1** +- 🟠 Нет `command -v go/python3` ни в 01/02/03 → непонятная ошибка если инструмента нет. **P1** +- 🟠 Нет lock-файлов нигде → два параллельных прогона на один `PROFILE_DIR` затрут друг друга. **P1** +- 🟡 04_build_and_publish_docs.sh — профиль НЕ обязателен (в отличие от 01-03). **P2** + +**Предложение:** добавить UA в urllib + retry-обёртку (3 попытки, backoff); guard на непустой список; `command -v` проверки; lock через `flock` на `PROFILE_DIR`. + +**Хорошо:** 03_build_and_upload_provider.sh — сильная валидация полноты registry перед сборкой; 04_build_and_publish_docs.sh — лучший fallback (docker → venv → system mkdocs). + +--- + +## Вопрос 2: service_spec_gen (API → YAML) + +**Прочитал:** generate_service_spec.go полностью. + +- **HTTP-клиент:** ✅ кастомный клиент с `Timeout: 30s`; ✅ User-Agent уже есть. 🔴 **Retry отсутствует** — любой 429/503/сетевой сбой → ошибка → panic в main. **P1** +- **Парсинг API:** ✅ структуры полные — `cfsParam` маппит все 19 полей. Потери только в edge-case. Неожиданный формат → `json.Unmarshal` error → panic, без graceful degradation. **P2** +- **classifyOperation:** покрыты `create/modify/delete/suspend/resume` → instance, `create_*/modify_*/delete_*` → subresource, остальное → action. 🟠 **Новые префиксы (`restart_*`, `pause_*`, `enable_*`) попадут в action**, а не subresource. **P1** +- **Constraints:** ✅ всё сохраняется — `maxLength/minLength/regex/uniqueScope/dependsOn`. 🟡 `normalizeValueList` делает `fmt.Sprintf("%v")` — для вложенных объектов теряет структуру. **P2** +- **YAML:** ✅ `yaml.Marshal` с `omitempty`, вложенные структуры корректны. Имя файла через `normalizeIdentifier` — Unicode схлопывается в `_`. **P2** + +**Предложение:** добавить retry с backoff в `getViaProxy`; расширить `classifyOperation` карту префиксов или сделать её конфигурируемой. + +--- + +## Вопрос 3: gen_v2 (YAML → Go) + +**Прочитал:** generate_resources_v2.go. + +- 🟠 **`format.Source` fallback:** при ошибке форматирования пишет `buf.Bytes()` (неотформатированный, возможно невалидный Go) **без warning**. Ошибка всплывёт только на компиляции. **P1** +- **computeCreateOnly:** «param в create но не в modify → ForceNew». При отсутствии modify-операции ВСЕ create-параметры → CreateOnly → корректно для immutable subresource. ✅ +- 🟠 **Subresource identity:** `DeleteParams` помечаются ForceNew, но `computeCreateOnly` их не учитывает → если delete-параметр не входит в create, возможен некорректный план. **P1** +- 🟡 **JSON:** `data_type: json → IsJson + JsonNormalize` работает для object/array, но нет валидации что значение реально валидный JSON. **P2** + +**Предложение:** не молчать на ошибке `format.Source` — логировать warning (или fail при невалидном Go); проверить пересечение DeleteParams ∩ CreateParams. + +--- + +## Вопрос 4: docs_template_gen_v2 + +**Прочитал:** docs_template_gen_v2/main.go. + +- **Генерируется 7 MD-файлов на ресурс:** `.md`, `_example.md`, `_params_create.md`, `_params_modify.md`, `_outputs.md`, `_ops.md`, `_params.md`. Формат — Markdown для mkdocs. ✅ +- **Покрытие:** ✅ subresources и actions, есть index. Все YAML-поля используются. ✅ +- **HCL-примеры:** из create-операции, required без default → в HCL, опциональные закомментированы. ✅ +- 🟠 **Ошибки:** битый YAML → panic, пустые операции — молча пропускаются. **P1** +- 🟡 **`-exclude clickhouse`** — дефолт флага + дублирован в 02_..._v2.sh. Хардкод, без объяснения причины. **P2** — вынести в config/комментарий. + +--- + +## Вопрос 5: service_ops_gen / service_params_gen — нужны? + +**Прочитал:** оба тула + grep по devops. + +- ❌ **Нигде не вызываются** в bash-скриптах — мёртвый код старой v1-архитектуры. +- ✅ **Заменены `service_spec_gen`** (единый YAML на сервис). +- **`tools/gen/`** — только placeholder-README, функциональность не реализована. + +**Предложение:** удалить `service_ops_gen`, `service_params_gen`, `tools/gen/` — **но только по явной команде**. **P2** + +--- + +## Вопрос 6: embed.go и resources_yaml + +- `//go:embed` встраивает все `*.yaml` в бинарник. **Зачем:** провайдер при старте один раз читает YAML и строит lookup-карты, без зависимости от внешних файлов. +- **Используется в 4 местах** resources_core: params_mapping.go, params_validation_mapping.go, required_params.go, params_ref_mapping.go. +- **Почему генерируется скриптом:** шаблонный файл без логики, генерируется если отсутствует. +- ⚠️ **`devops/profiles/*/generated/resources_yaml/embed.go` — не существует** (per-profile embed не реализован). + +--- + +## Вопрос 7: Профили и CI + +- **Профили test/prod/dev** идентичны по структуре, различаются `profile.env` (API endpoint, token-файл, версии). +- **CI = GitLab CI** (pipeline.yaml), 4 стадии: test → build → sign → publish. Запуск `only: tags`. +- ❌ **Автогенерации YAML в CI НЕТ** — YAML генерируются локально/вручную и коммитятся; CI только собирает и публикует. **P1** +- **Деплой:** Docker-образ `registry-operator:${TAG}` пушится в Harbor → управляется K8s-оператором. +- **Скрипты 10-13:** `13 clean` → `12 latest` → `11 alias` → `10 stability` (N раз — тест стабильности). + +--- + +## Вопрос 8: Практическая проверка покрытия + +- ✅ **Покрытие 100%:** все 41 активный сервис имеют YAML; исключённый `24 vc_nat` (DEPRECATED) YAML не имеет. Лишних YAML нет. +- 🔴 **Ключевая проблема — свежесть содержимого.** 90_postgres.yaml содержит 11 операций, но **`backup`/`reconcile` НЕТ** — API их уже отдаёт, а YAML устарел. + +**Вывод:** проверка «список vs файлы» зелёная, но **не ловит устаревшее содержимое**. + +**Предложение (P1):** добавить в CI шаг diff — перегенерировать YAML и сравнить с закоммиченными; при расхождении — фейлить. + +--- + +## Сводка приоритетов + +### P0 (блокеры) +1. urllib без User-Agent в 01_generate_yamls.sh → DDoS-Guard +2. urllib без обработки ошибок API (500/битый JSON/пусто) + +### P1 (важно) +- Нет retry в generate_service_spec.go +- `classifyOperation` не знает новые префиксы +- `format.Source` молча пишет невалидный Go в gen_v2 +- DeleteParams ∩ CreateParams в subresource identity +- Нет CI-диффа «API vs закоммиченный YAML» +- Нет lock-файлов, нет `command -v`, пустой список не ловится + +### P2 (доработки) +- Удалить legacy-тулы (по команде) +- `-exclude clickhouse` в config +- JSON-валидация +- Unicode в именах +- panic на битом YAML в docs-gen