Зафиксирована методика: истина = GET /services?isProductionReady=true (без фильтра API отдаёт все сервисы платформы, включая DEPRECATED). Результаты по dev/test/prod и исправление prod (Vault).
196 lines
13 KiB
Markdown
196 lines
13 KiB
Markdown
# 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/<stand>/resources_yaml.staging.<pid>
|
||
↓ генерация всех сервисов пачкой per-service в staging
|
||
↓ при пустом failures:
|
||
mv resources_yaml → resources_yaml.bak-<UTC> (бэкап, ротация 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/<stand>/…`;
|
||
- память репозитория — `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` и т.д.
|
||
|
||
## Этап 2 — удаление мёртвого (по команде «удаляй всё старое, аккуратно»)
|
||
|
||
**Удалено (`1e796c8`)** — 100% мёртвый код/данные, ничего их не вызывает:
|
||
|
||
| Файл | Почему удалён |
|
||
|---|---|
|
||
| `TOOLS/scripts/10_yaml_stability_run.sh` | зовёт `01` без `--profile` (exit 2), ищет `*.token` в корне |
|
||
| `TOOLS/scripts/11_yaml_stability_run_latest.sh` | цепочка на `10`, та же поломка |
|
||
| `TOOLS/scripts/12_generate_yamls_latest.sh` | зовёт `01` без `--profile`, ищет `*.token` в корне |
|
||
| `TOOLS/scripts/13_generate_yamls_clean.sh` | цепочка на `12` + делал `rm -f provider/resources_yaml/*.yaml` |
|
||
| `TOOLS/scripts/02_generate_resources_and_docs_template_v2.sh` | легаси-дубль канонического `02_generate_resources_and_docs_v2.sh` |
|
||
| `TOOLS/config/services_list.txt` (общий) | код его не читает; как «объединение» устарел: активный `27` (в test/prod — «нет в UI»), нет `87/88/97/153`, которые есть в dev |
|
||
|
||
Проверка «ничего не вызывает»: `grep` по всему репо находил ссылки только в
|
||
исторических `HISTORY/`, `NOTES/`, `docs/` (не исполняются).
|
||
|
||
**Правки ссылок (`c822ae2`)**: `README.md`, `HOW_TO/README.md`,
|
||
`HOW_TO/DEVOPS_BUILD_PIPELINE.md`, `HOW_TO/HOWTO_ADD_NEW_SERVICE.md` (включая
|
||
переписанный блок «Быстрый старт» с `devops/` на `./TOOLS/scripts/*`),
|
||
`DOCS_PIPELINE/README.md`, `scripts/publish-doc-page.sh`, `.gitignore`.
|
||
|
||
**Проверка после удаления**: `bash -n` для всех `TOOLS/scripts/*.sh` и
|
||
`scripts/publish-doc-page.sh` — OK; smoke-прогон `01 --profile TOOLS/config/dev` —
|
||
40 YAML, замена атомарная, бэкап создан.
|
||
|
||
**Не удалено (осознанно):**
|
||
|
||
- поддержка легаси-прокси `index.cfm` в `01` и `yaml-generator` — это совместимость
|
||
с работающими пользователями старого API (провайдер v5.0.75, `secrets/stands.md`);
|
||
- `DOCS_PIPELINE/publish-docs.sh` — сам файл помечен «справочная копия, не подменяет пайплайн»;
|
||
- `HISTORY/`, `NOTES/`, `docs/` — исторические документы (в них `devops/` и легаси-скрипты
|
||
упоминаются как история, это нормально);
|
||
- `scripts/*.py` и `s3_notification_example.sh` — ручные утилиты, вызываются вручную.
|
||
|
||
## Этап 3 — сверка списков стендов с облачным каталогом (источник истины)
|
||
|
||
Принято: **истина — то, что перечислено в облаке**. Определяется эндпоинтом каталога:
|
||
|
||
```bash
|
||
# «перечислено в облаке» (продакшен-готовые сервисы стенда)
|
||
GET {NUBES_API_ENDPOINT}/services?limit=200&isProductionReady=true
|
||
# для сравнения: без фильтра отдаются ВСЕ сервисы платформы, включая
|
||
# DEPRECATED и не заявленные в каталоге (48 у prod, 49 у test, 60 у dev)
|
||
```
|
||
|
||
Требуется браузерный `User-Agent` (иначе DDoS-Guard отдаёт 403) и `Referer`.
|
||
|
||
Результат на 2026-09-30:
|
||
|
||
| Стенд | Облако (`isProductionReady=true`) | Активных в `services_list.txt` | Лишние в файле | Не хватало |
|
||
|---|---|---|---|---|
|
||
| dev | 40 | 40 | нет | нет |
|
||
| test | 36 | 36 | нет | нет |
|
||
| prod | 36 | 35 → **36** | нет | **`151 k8sOpenbao` (Vault)** |
|
||
|
||
У остальных 12 закомментированных prod-сервисов, присутствующих в API, `isProductionReady=false` —
|
||
они закомментированы обоснованно. Четыре id в файле отсутствуют в каталоге prod вовсе
|
||
(`32 vmpostgre`, `87 k8svalkey`, `153 nifi`, `175 k8sGo`).
|
||
|
||
Исправлено коммитом `a68a36a`: `151 k8sOpenbao` раскомментирован (комментарий «нет в PROD UI»
|
||
устарел), prod перегенерирован — 36 YAML, ровно как в облаке.
|
||
|
||
## Открытые вопросы (на решение владельца)
|
||
|
||
1. Поддержка легаси-прокси `index.cfm`: оставляем или выпиливаем (README уже помечает
|
||
закрытые API как «не использовать»)?
|
||
2. Прочие `.gitignore`-паттерны мёртвых каталогов (`universal_rebuild/*`, `provider/generated/`)
|
||
— чистить?
|
||
|