From cbd559d7678f8fdea72bb272469c5fcf16e06956 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Wed, 30 Sep 2026 09:39:26 +0300 Subject: [PATCH] =?UTF-8?q?docs(tools):=20=D0=BA=D0=B0=D0=BD=D0=BE=D0=BD?= =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20=D0=BF=D0=B0=D0=B9?= =?UTF-8?q?=D0=BF=D0=BB=D0=B0=D0=B9=D0=BD=20+=20=D0=B8=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=8F=20=D1=83=D0=B6=D0=B5=D1=81=D1=82=D0=BE=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20YAML?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TOOLS/README.md: раздел «Канонический пайплайн (порядок шагов)» и описание безопасной генерации (staging → атомарная замена, бэкапы, маркер .stand); - TOOLS/ARCHITECTURE.md: ссылки devops/… → TOOLS/config//…; - HISTORY/2026-09-30_yaml_pipeline_hardening.md: полная история изменений (что было не так, что сделано, прогон по стендам, коммиты, проверки). --- HISTORY/2026-09-30_yaml_pipeline_hardening.md | 131 ++++++++++++++++++ TOOLS/ARCHITECTURE.md | 7 +- TOOLS/README.md | 39 ++++++ 3 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 HISTORY/2026-09-30_yaml_pipeline_hardening.md diff --git a/HISTORY/2026-09-30_yaml_pipeline_hardening.md b/HISTORY/2026-09-30_yaml_pipeline_hardening.md new file mode 100644 index 0000000..cd6a927 --- /dev/null +++ b/HISTORY/2026-09-30_yaml_pipeline_hardening.md @@ -0,0 +1,131 @@ +# 2026-09-30 — Ужесточение пайплайна генерации YAML (безопасная замена, чистка легаси) + +> Связанные материалы: +> `TOOLS/README.md` (канонический пайплайн, порядок шагов), +> `TOOLS/ARCHITECTURE.md` (спецификация), +> память репозитория: `pipeline-legacy.md`. + +## Задача + +1. Разобрать, что в генерации YAML устарело. +2. Перегенерировать YAML по всем стендам так, чтобы **старое удалялось безопасно**, + а новое создавалось атомарно. +3. Задокументировать всё, чтобы история изменений прослеживалась. + +Команда пользователя: «делай как ПОЛОЖЕНО, как в best practices». + +## Что было не так (до правок) + +### `TOOLS/scripts/01_generate_yamls.sh` + +| Место (до) | Проблема | +|---|---| +| стр. 230 `rm -f "$output_glob"` | старый YAML удалялся **до** генерации → при сбое API файл исчезал, новый не создавался (неатомарно per-service) | +| стр. 122 «Полной очистки нет» | YAML исключённого сервиса оставался в каталоге и попадал в сборку | +| стр. 91 `ls -t "${ROOT_DIR}"/*.token` | легаси-фолбэк токена: в корне токенов нет; поиск «последнего» мог подхватить чужой токен | +| стр. 109 `API_ENDPOINT="${NUBES_API_ENDPOINT:-https://lk-api-gateway.ngcloud.ru/...}"` | молчаливый уход в **PROD**, если в профиле нет endpoint | +| стр. 167 `svc_name=""` | имя всегда пустое, хотя шапка обещала парсинг из списка → лишний HTTP-запрос на каждый сервис (2 запроса вместо 1) | +| стр. 46–50 | дубль `SERVICES_FILE_DEFAULT` (одинаковое присваивание в `if`) | +| шапка vs код | «REQUEST_DELAY по умолчанию 0.2», в коде 0.5; путь вывода указан как `provider/resources_yaml` (устарел) | + +### `TOOLS/yaml-generator/internal/config/config.go` + +| Место (до) | Проблема | +|---|---| +| `Load()` стр. 33 | свой дефолт endpoint = **PROD** gateway | +| `loadToken()` + `findLatestToken()` | легаси-фолбэк «последний `*.token` в корне репо» | +| `Load()` стр. 60 | путь `filepath.Join(repoRoot, "devops", "config", "services_list.txt")`, причём `FindRepoRoot()` возвращает каталог `provider/` → путь заведомо не существовал | + +### Легаси-скрипты + +`10_yaml_stability_run.sh`, `11_yaml_stability_run_latest.sh`, +`12_generate_yamls_latest.sh`, `13_generate_yamls_clean.sh`, +`02_generate_resources_and_docs_template_v2.sh` — **мертвы**: зовут `01` без +`--profile` (→ `exit 2`), ищут `*.token` в корне репо, а `13` вдобавок делал +`rm -f provider/resources_yaml/*.yaml`. Ни один рабочий скрипт их не вызывает +(ссылки есть только в исторических `HISTORY/`, `NOTES/`). + +## Что сделано + +### 1. `01_generate_yamls.sh` — безопасная запись по принципу staging → атомарная замена + +Новый алгоритм: + +``` +staging = generated//resources_yaml.staging. + ↓ генерация всех сервисов пачкой per-service в staging + ↓ при пустом failures: + mv resources_yaml → resources_yaml.bak- (бэкап, ротация KEEP_BACKUPS=5) + mv staging → resources_yaml (атомарный rename в том же FS) + ↓ при непустом failures: + замена ОТМЕНЯЕТСЯ, рабочий каталог не тронут, staging оставлен для разбора, exit 1 +``` + +Прочие изменения: + +- каталог помечается маркером `.stand`; генерация в каталог чужого стенда запрещена (`exit 2`); +- `embed.go` создаётся теперь в staging (обязательный `go:embed *.yaml`); +- `NUBES_API_ENDPOINT` обязателен, иначе `exit 2`; +- токен берётся только из `NUBES_API_TOKEN`/`TOKEN_FILE`; легаси-поиск удалён; +- имя сервиса — из 2-го поля `services_list.txt`; лишний python-запрос удалён; +- удалён дубль `SERVICES_FILE_DEFAULT`; синхронизированы комментарии. + +### 2. `yaml-generator/internal/config/config.go` + +- `NUBES_API_ENDPOINT` обязателен (нет PROD-дефолта); +- `loadToken()` больше не ищет `*.token` в корне репо; `findLatestToken` и `getenvDefault` удалены как мёртвые; +- при отсутствии `NUBES_SERVICE_ID` требуется явный `NUBES_SERVICES_FILE` (угадывание пути удалено). + +### 3. Легаси-скрипты отключены (fail-fast) + +В начало каждого добавлен guard: сообщение `DEPRECATED` + `exit 2`. Файлы **не удалены** +(удаление — отдельное решение владельца), но теперь они не могут сделать ничего вредного. + +### 4. Документация + +- `TOOLS/README.md` — добавлен раздел «Канонический пайплайн (порядок шагов)» и описание безопасной генерации; +- `TOOLS/ARCHITECTURE.md` — ссылки `devops/…` заменены на `TOOLS/config//…`; +- память репозитория — `pipeline-legacy.md` уточнена. + +## Прогон по всем стендам (результат) + +Токены проверены прямыми запросами к API (с браузерным `User-Agent`, иначе DDoS-Guard отдаёт 403): + +| Стенд | Endpoint | HTTP | YAML после генерации | Stale | Failures | +|---|---|---|---|---|---| +| dev | `lk-api-gateway-dev.ngcloud.ru` | 200 | 40 | нет | нет | +| test | `lk-api-gateway-test.ngcloud.ru` | 200 | 36 | нет | нет | +| prod | `lk-api-gateway.ngcloud.ru` | 200 | 35 | нет | нет | + +Команды: + +```bash +./TOOLS/scripts/01_generate_yamls.sh --profile TOOLS/config/dev +./TOOLS/scripts/01_generate_yamls.sh --profile TOOLS/config/test +./TOOLS/scripts/01_generate_yamls.sh --profile TOOLS/config/prod +``` + +Проверка целостности: `diff -rq` нового каталога dev с бэкапом даёт различия только +в случайных `default`-суффиксах, которые API генерирует при каждом запросе +(`db-ievgpdvu` → `db-ujama5rb`, `flask-seqtiq3t` → `flask-xwfdxdqh` и т.п.) — +структурной регрессии нет. Это же объясняет, почему побайтовое сравнение двух +прогонов не может быть использовано как «детектор дрейфа». + +## Коммиты + +- `12b3932` — `fix(tools): безопасная генерация YAML — staging + атомарная замена, без легаси-фолбэков` +- `ad4daab` — `chore(tools): легаси-скрипты генерации отключены (fail-fast DEPRECATED)` + +## Проверки + +- `bash -n` для `01_generate_yamls.sh` и всех guard-скриптов — OK; +- `go vet ./...` + `go build` для `yaml-generator` — OK; +- guard отдаёт `exit 2`; +- прогон dev/test/prod — 0 failures, stale отсутствует, staging не остаётся; +- бэкапы создаются: `generated/dev/resources_yaml.bak-20260930T063152Z` и т.д. + +## Открытые вопросы (на решение владельца) + +1. Удалять ли отключённые легаси-скрипты (`10/11/12/13`, `02_..._template_v2`) физически? +2. `TOOLS/config/services_list.txt` (общий, «объединение») не используется ни одним профилем — удалять? +3. Нужна ли поддержка легаси-прокси `index.cfm` в `01` и `yaml-generator` (сейчас сохранена как совместимость)? diff --git a/TOOLS/ARCHITECTURE.md b/TOOLS/ARCHITECTURE.md index 2fce171..dbae4d8 100644 --- a/TOOLS/ARCHITECTURE.md +++ b/TOOLS/ARCHITECTURE.md @@ -14,13 +14,14 @@ reflected here FIRST, then implemented in `gen_v2` and other tools. 4) Documentation is generated from the same YAML. 5) Build artifacts for 3 OS targets are published to the registry, and docs are published to the website. -6) `devops/ARCHITECTURE.md` (this file) is the primary spec. Code follows. +6) `TOOLS/ARCHITECTURE.md` (this file) is the primary spec. Code follows. ## Service Selection -- The inclusion list is defined by: `devops/config/services_list.txt` (repo-relative path) +- The inclusion list is defined by: `TOOLS/config//services_list.txt` + (по одному списку на стенд; repo-relative path) - Each line starts with service_id, followed by service name/alias. -- Operation timeouts source is defined by: `devops/config/operation_timeouts.json`. +- Operation timeouts source is defined by: `TOOLS/config//operation_timeouts.json`. ## API Endpoint diff --git a/TOOLS/README.md b/TOOLS/README.md index cbe9a14..fe3eab8 100644 --- a/TOOLS/README.md +++ b/TOOLS/README.md @@ -2,6 +2,45 @@ Каждый инструмент — независимый Go-модуль. +## Канонический пайплайн (порядок шагов) + +```bash +# 1) YAML-спеки сервисов из API (per-stand!) +./TOOLS/scripts/01_generate_yamls.sh --profile TOOLS/config/dev + +# 2) Go-ресурсы + документация из этих YAML +./TOOLS/scripts/02_generate_resources_and_docs_v2.sh --profile TOOLS/config/dev + +# 3) (релиз) сборка 3 платформ + публикация в реестр +./TOOLS/scripts/03_build_and_upload_provider.sh --profile TOOLS/config/dev +``` + +`--profile` обязателен: без него скрипты выходят с кодом 2 (никаких дефолтов). + +### Шаг 1 — безопасная генерация YAML + +`01_generate_yamls.sh` работает по принципу «сначала во временное, потом атомарная замена»: + +- генерация идёт в staging-каталог `generated//resources_yaml.staging./`; +- рабочий `generated//resources_yaml/` **не** удаляется и **не** модифицируется до полного успеха; +- при полном успехе старый каталог уезжает в бэкап `resources_yaml.bak-`, + а staging встаёт на его место (атомарный `mv` в пределах одного FS), + хранятся последние `KEEP_BACKUPS` (по умолчанию 5); +- при любой ошибке замена **отменяется**: старый каталог цел, частичный результат лежит в staging для разбора, скрипт выходит с кодом 1; +- в каталоге лежит маркер `.stand`, защищающий от генерации не в тот стенд. + +Перегенерировать все стенды подряд: + +```bash +for s in dev test prod; do + ./TOOLS/scripts/01_generate_yamls.sh --profile TOOLS/config/$s || break +done +``` + +> Примечание: часть параметров API отдаёт со случайным `default`-суффиксом +> (`db-ievgpdvu` → `db-ujama5rb` и т.п.), поэтому побайтовое сравнение двух +> прогонов даёт различия в этих строках — это не регрессия. + ## yaml-generator API Nubes → `resources_yaml/*.yaml`