# 2026-07-02 — Миграция с deck-api на API Gateway (lk-api-gateway) ## Контекст Старый API: `https://deck-api-{stand}.ngcloud.ru/api/v1/index.cfm?endpoint=/services/123` Новый API Gateway: `https://lk-api-gateway-{stand}.ngcloud.ru/api/v1/svc/services/123` Ответы JSON идентичны. Различается только формат URL: - Старый: proxy через `index.cfm?endpoint=` - Новый: прямые REST-пути Цель: перевести TEST-стенд на новый Gateway, сохранив совместимость со старым для dev/prod. ## Архитектурное решение Авто-детект режима по наличию `index.cfm` в URL: - Есть `index.cfm` → старый proxy (`?endpoint=`) - Нет `index.cfm` → новый REST (прямая конкатенация пути) Один env-параметр `NUBES_API_ENDPOINT` управляет всем. ## Изменения (11 файлов) ### 1. Генератор YAML: `universal_rebuild/tools/service_spec_gen/generate_service_spec.go` - `normalizeAPIEndpoint()` — убрано принудительное добавление `/index.cfm`, теперь только trim trailing slash - `getViaProxy()` → `callAPI()` — авто-детект: если `index.cfm` в URL → `?endpoint=`, иначе → прямая конкатенация `{base}{path}` - Добавлен метод `isProxyAPI()` для детекта - Обновлён комментарий с документированием двух режимов ### 2. Ядро провайдера: `universal_rebuild/internal/core/client.go` - Добавлены `isProxyAPI()` и `buildURL(path string) string` — единая точка конструирования URL - Заменены все 4 места с хардкодом `?endpoint=`: - `FindExistingInstances` (пагинированный поиск, строка ~515) - `GetInstanceState` (строка ~590) - `GetInstanceStateRaw` (строка ~637) - `doRequest` (POST/PUT/GET, строки ~838-853) ### 3. Оркестратор YAML: `devops/01_generate_yamls.sh` - Убрана принудительная нормализация `if [[ "$API_ENDPOINT" != */index.cfm ]]` → автоматическая - Python-скрипт: авто-детект `"index.cfm" in endpoint` → `?endpoint=` vs прямой путь ### 4. Генератор документации: `devops/02_generate_resources_and_docs_v2.sh` - Добавлена передача `-api-endpoint "$DOCS_API_ENDPOINT"` в `docs_template_gen_v2` - Нормализация: если нет ни `index.cfm`, ни `/svc` → дописать `/index.cfm` (обратная совместимость) ### 5. Публикация доков: `devops/04_build_and_publish_docs.sh` - `normalize_api_endpoint()` — убрано принудительное `/index.cfm`, только trim ### 6. Корневой скрипт: `01_generate_yamls.sh` (корень) - Python-скрипт: такой же авто-детект, как в devops/01 ### 7-8. Шаблоны документации: `docs_template_gen_v2/main.go` + `docs_template_gen/main.go` - Добавлен флаг `-api-endpoint` (default: старый deck-api) - Все хардкоды `api_endpoint = "https://deck-api...index.cfm"` заменены на `fmt.Sprintf` - Проброшено через `writeResourceDocs` → `buildExamplePage` → `exampleBlock` → `buildSubresourceExamplePage` ### 9-10. Провайдеры: `internal/provider/provider.go` + `universal_rebuild/internal/provider/provider.go` - Добавлен `TODO(api-gateway)` комментарий над дефолтным `apiEndpoint` - Сам дефолт не менялся (runtime провайдера теперь использует `core.buildURL()`) ### 11. Профиль TEST: `devops/profiles/test/profile.env` - `NUBES_API_ENDPOINT` → `https://lk-api-gateway-test.ngcloud.ru/api/v1/svc` ### Бонус: версия в бинарник - `devops/build-provider.sh`: `go build` теперь с `-ldflags "-X main.version=${VERSION}"` — версия из профиля вшивается в бинарник (раньше всегда была из main.go) ## Анализ пайплайна (попутно) Полный пайплайн: `services_list.txt` → `01_generate_yamls.sh` → `02_generate_resources_and_docs_v2.sh` → `03_build_and_upload_provider.sh` → `04_build_and_publish_docs.sh`. Найденные проблемы (не исправлялись, зафиксированы): - `main.go` Address = `nubes-test` (только для test, для prod нужно `nubes`) - Нет сборки под `darwin/arm64` (Apple Silicon) - Корневой `01_generate_yamls.sh` ссылается на несуществующий `service_params_gen` - Кросс-стадийная валидация отсутствует (сбои 01 не видны в 02) ## Оставшиеся `deck-api` в коде Только как **значения по умолчанию** (переопределяются через `NUBES_API_ENDPOINT`): - `service_spec_gen/generate_service_spec.go:150` — `getenvDefault("NUBES_API_ENDPOINT", "https://deck-api...")` - `devops/01_generate_yamls.sh:108` — `${NUBES_API_ENDPOINT:-https://deck-api...}` - `devops/02_generate_resources_and_docs_v2.sh:95` — аналогично - `devops/04_build_and_publish_docs.sh:13,87` — аналогично - `docs_template_gen_v2/main.go:91` — flag default - `docs_template_gen/main.go:81` — flag default - `internal/provider/provider.go:105` + `universal_rebuild/...` — с TODO Хардкодов в теле функций/примеров больше нет. ## Для перехода dev/prod Достаточно поменять одну строку в `profile.env`: ``` NUBES_API_ENDPOINT="https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc" # dev NUBES_API_ENDPOINT="https://lk-api-gateway.ngcloud.ru/api/v1/svc" # prod ``` Всё остальное — авто-детект. --- ## Доступ к СТАРОМУ deck-api (DDoS-Guard 403) Старый API **жив**, но DDoS-Guard усилил фильтрацию. Просто `User-Agent: Mozilla/5.0` уже недостаточно. ### Рабочие заголовки для curl: ```bash curl -H "Authorization: Bearer $TOKEN" \ -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" \ -H "Referer: https://deck-test.ngcloud.ru/" \ "https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/services/90" ``` **Ключевое**: `Referer` с доменом того же стенда. Без него — 403. ### Без токена (публичные эндпоинты): ```bash curl -H "User-Agent: Mozilla/5.0" \ "https://deck-api-test.ngcloud.ru/api/v1" # → 200 (OK) ``` ### Что изменилось с июля 2026 DDoS-Guard ужесточил правила: - Старый `User-Agent: Mozilla/5.0` + `Accept: */*` → 403 - Новый: нужен полный браузерный User-Agent + Referer - Провайдер (v5.0.75) использовал старые заголовки — при следующем билде надо обновить - Новый Gateway (`lk-api-gateway`) — 403 не выдаёт, работает с любым User-Agent --- ## Проблема map-fixed параметров и dataDescriptor ### Суть Новый Gateway группирует плоские параметры в map-fixed JSON-блоки. Sub-поля (`dataDescriptor`) не видны в `/serviceOperation/{id}` — появляются только в ответе уже выполненной операции `/instanceOperations/{uid}`. ### Как получить sub-поля (на примере postgres) ```bash # 1. Найти любой успешный инстанс postgres curl ... "https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/instances?serviceId=90&page=1&size=1" # 2. Взять instanceUid → запросить операции → взять create-операцию curl ... "https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/instances/{uid}" # 3. Запросить операцию — в cfsParams будет dataDescriptor с sub-полями curl ... "https://deck-api-test.ngcloud.ru/api/v1/index.cfm?endpoint=/instanceOperations/{opUid}" ``` ### Правильные JSON-ключи для postgres (из dataDescriptor) | Блок | Поля | |---|---| | `startupConfiguration` | `resourceRealm` | | `clusterConfiguration` | `cpu`, `memory`, `replicas`, `disk` | | `accessConfiguration` | `masterIpSpace`, `masterAccessList`, `slaveIpSpace`, `slaveAccessList` | | `postgresConfiguration` | `version`, `sslRequired`, `poolerMaster`, `poolerSlave` | | `postgresConf` | `paramName`, `paramValue` (массив) | | `backupConfiguration` | `s3Uid`, `retain`, `schedule` | | `autoscaleConfiguration` | `enabled`, `schedule`, `quota`, `percent` | ### Обсуждение с девопсами (02.07.2026) - Плоские параметры **не вернутся** — map-fixed остаётся (нужно для групп ключей, нод, учёток) - Структуру блоков обещают давать в API, но пока не придумали формат - Пока единственный источник структуры — Jenkins-конфиги ### CMDB backend bug При run операции бэкенд `/app/cmdb` падает с `ValidationError: InstanceState: version, instanceUid, dtState, isTest, instanceOperationUid — can't be blank`. Это баг в Gateway→CMDB, не в провайдере.