From 6e2418b15705b4391e5392074d5186cb43ceebe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Thu, 30 Jul 2026 14:32:31 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20agent=20analysis=20request=20=E2=80=94?= =?UTF-8?q?=20full=20project=20overview=20for=20new=20chat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCS/agent-analysis-request.md | 318 +++++++++++++++++++++++++++++++++ DOCS/sol-scenario-editor.md | 48 +++++ TASKS/SOLdescribe.md | 79 ++++++++ 3 files changed, 445 insertions(+) create mode 100644 DOCS/agent-analysis-request.md create mode 100644 DOCS/sol-scenario-editor.md create mode 100644 TASKS/SOLdescribe.md diff --git a/DOCS/agent-analysis-request.md b/DOCS/agent-analysis-request.md new file mode 100644 index 0000000..7aecbd8 --- /dev/null +++ b/DOCS/agent-analysis-request.md @@ -0,0 +1,318 @@ +# Запрос на полный анализ autotest — для нового чата с агентом + +Дата: 2026-07-30 +Версия: v1.1.48 + +--- + +## 1. ЧТО ЭТО ЗА ПРОЕКТ + +**autotest** — веб-приложение для автоматизированного тестирования сервисов платформы Nubes (Cloud Director). Позволяет запускать операции (create/modify/delete/suspend/resume/redeploy) над инстансами сервисов через Nubes REST API, отслеживать статус, вести историю запусков. + +Приложение запущено на тестовом стенде: `atest.pythonk8s.dev.nubes.ru` + +**Стек:** +- Backend: Flask 3.0 + gunicorn (multi-worker) +- DB: PostgreSQL 17 (Zalando Operator), схемы: `runs`, `scenario_runs`, `scenario_definitions` (pending) +- Frontend: ванильный JS (один файл `app.js`, 550 строк), Jinja2-шаблон +- Nubes REST API: `https://lk-api-gateway-test.ngcloud.ru/api/v1/svc` +- Аутентификация: JWT-токен (cookie или env), автоопределение стенда (dev/test) +- Деплой: Nubes pythonk8s, кластер iot-naeel + +**Автор:** naeel (tazetdinovn@gmail.com, WZ03709) +**Репозитории:** +- `https://gitea.services.ngcloud.ru/forcloud/app-autotest` — код приложения +- `https://gitea.services.ngcloud.ru/forcloud/autotest` — документация, YAML-описания сервисов + +--- + +## 2. АРХИТЕКТУРА — ФАЙЛЫ И ИХ РОЛИ + +### site/app.py — точка входа +Flask-приложение, регистрирует blueprint'ы: +- `main_bp` — главная страница, токен, инфраструктура +- `api_test_bp` — основной API (run/params/status/log/history) +- `api_scenario_bp` — API сценариев (run/status/CRUD — pending) +- `api_bp` — **УДАЛЁН в v1.1.45** (legacy: /api/run, /api/status, /api/config) +- VERSION — меняется при КАЖДОМ изменении + +### site/api/http_client.py — HTTP-клиент +- `HttpClient` — обёртка над requests.Session +- GET: `raise_for_status()` → `.json()`, пустой ответ → `{}` +- POST: `json=data`, извлекает Location-заголовок → `_location` в ответе +- `raw_delete(url)` — DELETE без auth (для CMDB API) +- `detect_endpoint(token)` — автоопределение стенда (dev→test) +- `stand_name(endpoint)` — "dev"/"test" по URL + +### site/api/auth.py — аутентификация +- `get_token()` — из cookie или env +- `get_client()` — HttpClient с автостендом +- `get_client_id()` — ClientID из JWT +- `get_stand()` — "dev"/"test" +- `get_token_info()` — {email, company, client_id} + +### site/routes/main.py — главная страница +- `GET/POST /` — Jinja2-рендер: организация, инфраструктура, сервисы, форма токена +- `GET /api/operations/` — cloud-first инстансы + tracked-fallback +- `_resolve_instance_status()` — explainedStatus из облака или "creating" из трекера + +### site/routes/api_test.py — ОСНОВНОЙ API (400 строк) +Эндпоинты: +- `GET /api/services` — список сервисов +- `GET /api/instances/list` — все инстансы +- `GET /api/params/[?instanceUid=xxx]` — параметры операции (текущие или шаблон) +- `POST /api/test` — запуск операции (CREATE или non-CREATE) +- `GET /api/test/status/` — поллинг +- `GET /api/log` — логи +- `GET /api/history` — история из БД + +Ключевые функции: +- `_send_params_terraform()` — шаги 3-7 Terraform (cfsParams → resolveRefSvc → send → validate) +- `_normalize_value()` — normalizeUniversalValueV6 (Terraform-equivalent) +- `_resolve_ref_svc()` — автоподстановка UUID инстанса для refSvcId-параметров +- `_finish_op()` — фоновый поллинг до dtFinish, сохранение в БД +- `_redact_params()` — замена secret/password/token на *** +- `_unique_display_name()` — проверка на дубликат + суффикс +- `_find_uid(resp)` — извлечение UUID из вложенных dict +- `_uid_from_location(loc)` — извлечение UUID из Location-заголовка + +### site/routes/api_scenario.py — API СЦЕНАРИЕВ (90 строк) +- `GET /api/scenarios` — список из config.yaml (должен быть переключён на БД) +- `POST /api/scenario/run` — запуск (создаёт запись ДО потока, возвращает run_id + 202) +- `GET /api/scenario/run/` — статус конкретного запуска +- `GET /api/scenario/status` — последние 10 запусков (legacy, должен уйти) + +### site/operations/scenario.py — ЯДРО СЦЕНАРИЕВ (290 строк) +- `run_scenario()` — главный исполнитель: + 1. service имя → svc_id (из config.yaml services) + 2. operation имя → svcOperationId (GET /services/{id}) + 3. param коды → numeric IDs (GET /instanceOperations/default/{opId}) + 4. create: новый инстанс; остальные: переиспользовать instance_map + 5. POST /instances → POST /instanceOperations → _send_params_terraform → run → poll + 6. Сохранить в runs (RUNNING до API, финальный после) + scenario_runs +- `_resolve_service()` — поиск svc_id по символическому имени +- `_resolve_params()` — symbolic codes → numeric IDs +- `_find_uid()`, `_uid_from_location()` — ДУБЛИКАТЫ из api_test.py (!) +- `_save_scenario_run()` — UPDATE scenario_runs +- `_create_scenario_run()` — INSERT scenario_runs + +### site/operations/get_params.py — параметры с текущими значениями +- `get_params_with_current_values()` — смержить state.params инстанса с шаблоном операции +- `_normalize_value_list()` — CSV-строка/массив → list + +### site/operations/get_services.py — сервисы +- `get_services()` — GET /services → все сервисы +- `get_service_detail()` — GET /services/{id} → детали + операции + +### site/operations/get_instances.py — инстансы +- `get_organization()` — инстанс с serviceId=19 +- `get_instances()` — GET /instances?pageSize=500 → все инстансы + +### site/operations/service_list.py — разрешённые сервисы +- `load_service_ids(stand)` — чтение `config/services_{stand}.txt` + +### site/operations/tracker.py — трекер инстансов (файловый) +- JSON-файлы в /tmp/: `instances-{clientId}-{stand}.json` +- fcntl.flock для multi-worker safety +- Используется как КРАТКОСРОЧНЫЙ fallback (инстанс создан, но облако ещё не показывает) + +### site/db/pool.py — connection pool +- Lazy-init ThreadedConnectionPool (1-5) +- `_ensure_schema()` → `init_db()` после успешного коннекта +- ENV: DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD, DB_SSLMODE + +### site/db/init_db.py — схема БД +- Таблица `runs` — история операций (id, client_id, stand, svc_id, op_name, status, duration, params JSONB, stages JSONB, scenario_run_id, step_number) +- Таблица `scenario_runs` — запуски сценариев (id, scenario_name, status, current_step, total_steps, duration, error_log) +- Миграции: ALTER TABLE ADD COLUMN IF NOT EXISTS +- **НЕТ** таблицы `scenario_definitions` — её ещё предстоит создать + +### site/db/save_run.py — сохранение в БД +- `save_run()` — INSERT в runs +- Принимает опциональные `scenario_run_id` + `step_number` (добавлены в v1.1.48) + +### site/runner.py — LEGACY (будет удалён) +- Старый механизм запуска тестов из config.yaml +- Используется только `load_config()` из него + +### site/static/app.js — ФРОНТЕНД (550 строк) +- Глобальное состояние: svcInstances, selectedInst, selectedOp, pollTimer, currentSvcId, busy, AUTOTEST_PREFIX +- selectService(), toggleInstance(), startCreate(), runOp(), showParams(), executeOp() +- Поллинг: setFinishedState(), showStages(), stopPoll(), refreshInstances() +- История: toggleHistory(), loadHistory() +- Сценарии: toggleScenario(), loadScenarios(), runScenario(), stopScenarioPoll() +- Хелперы: _esc() (HTML-escape), validateJson() +- Логи: toggleLog(), startLogPoll() + +### site/static/style.css — стили +### site/templates/index.html — Jinja2-шаблон +- Три колонки: инфраструктура | сервисы | инстансы+операции+параметры +- Секции: история (сворачиваемая), сценарии (сворачиваемая) +- window.APP: version, stand, hasUserToken, firstServiceId + +### site/config.yaml — конфигурация +- services: маппинг name → service_id +- scenarios: один сценарий dummy_test (create → delete) +- **Проблема:** сценарии в контейнере, требуют redeploy для изменения + +### STANDS/dev/resources_yaml/ — YAML-описания сервисов (50+ файлов) +- Полные описания: name, service_id, outputs, operations с параметрами (коды, типы, valueList, sub_params) +- Используются ТОЛЬКО как документация, код их не читает + +### DOCS/ — документация +- ARCHITECTURE-FULL.md — полный обзор +- sol-answers.md — 14 ответов Sol (MVP-план) +- sol-scenario-editor.md — ответы Sol по редактору сценариев + +--- + +## 3. ПОТОК ОПЕРАЦИИ CREATE (Terraform parity) + +1. POST /instances → `instance_uid` из Location-заголовка `./UUID` +2. POST /instanceOperations → `op_uid` из Location-заголовка +3. GET /instanceOperations/{op_uid}?fields=cfsParams → шаблон параметров +4. _resolve_ref_svc → автоподстановка UUID для refSvcId-параметров +5. POST /instanceOperationCfsParams → отправить пользовательские параметры +6. POST /instanceOperationCfsParams → дослать неотправленные (с normalize) +7. GET /instanceOperations/{op_uid}/validate-cfs → валидация +8. POST /instanceOperations/{op_uid}/run → запуск +9. Поллинг GET /instanceOperations/{op_uid}?fields=dtFinish,... → dtFinish + +--- + +## 4. ТЕКУЩЕЕ СОСТОЯНИЕ (v1.1.48) + +### Работает: +- ✅ Ручной запуск операций (create/modify/delete/suspend/resume/redeploy) +- ✅ Terraform-совместимая отправка параметров (9 шагов) +- ✅ Поллинг с этапами (⏳/✅/❌) +- ✅ История в БД (runs) +- ✅ Лог-панель (fcntl.flock, ротация) +- ✅ HTML-escape (statusError, d.error, логи, currentSvcName) +- ✅ Redact secrets перед сохранением +- ✅ Валидация входов (UUID, int, dict) +- ✅ refSvcId — верхнеуровневый + в dataDescriptor +- ✅ Убран legacy api_bp + +### Частично работает: +- ⚠️ Сценарии — запуск есть, но источник = config.yaml (redeploy для правки) +- ⚠️ save_run пишет scenario_run_id + step_number (v1.1.48), но не протестировано +- ⚠️ run_id возвращается клиенту (v1.1.48), поллинг по конкретному запуску + +### Не работает / pending: +- ❌ Редактор сценариев в UI (нужна таблица scenario_definitions + CRUD API + UI) +- ❌ Сценарии требуют redeploy для изменения (запечены в config.yaml) +- ❌ Дубликаты _find_uid / _uid_from_location в scenario.py и api_test.py +- ❌ scenario.py не протестирован на полный цикл create→delete +- ❌ seed из config.yaml в БД при первом старте не реализован +- ❌ Нет сервисных токенов (runner использует персональный токен) +- ❌ Нет блокировки параллельных запусков сценариев + +--- + +## 5. КЛЮЧЕВЫЕ НАХОДКИ ИЗ HAR-ТРАССИРОВКИ + +POST /instances: +- Request: `{"serviceId":1,"displayName":"dummy-11255555","descr":""}` +- Response: status 201, body `{}`, Location: `./CDEBB216-E5EB-4C09-8736-7E5F01A4EE12` +- **UUID ТОЛЬКО в Location-заголовке**, тело ответа — пустой объект `{}` + +POST /instanceOperations: +- Request: `{"instanceUid":"...","operation":"create"}` +- Response: также Location-заголовок с opUid + +**Следствие:** `_find_uid(resp)` никогда не найдёт UUID в теле ответа (тело пустое). UUID всегда в Location. `_uid_from_location(resp.get("_location",""))` — ЕДИНСТВЕННЫЙ работающий метод извлечения. + +**Но:** `_find_uid` нужен для других ответов API (get instanceOperation), где UUID внутри `instanceOperation.instanceOperationUid`. + +--- + +## 6. РЕКОМЕНДАЦИИ SOL (2026-07-30) + +### По редактору сценариев (sol-scenario-editor.md): + +1. **Структура steps:** JSONB, поле `resource` для связи create→modify→delete одного инстанса +2. **Параметры:** выпадающие списки из живого API (сервис→операции→коды), кеш на время сессии +3. **Seed:** marker `scenario_seed_v1=completed`, `INSERT ON CONFLICT DO NOTHING`, отдельный `scenario_seed.yaml` +4. **UI:** модальное окно, кнопки вверх/вниз, мягкое удаление (is_active=false) +5. **Валидация:** при сохранении + при запуске, невалидный не запускать +6. **Критические дыры:** + - run_id до потока (✅ исправлено v1.1.48) + - GET /api/scenario/run/ (✅ добавлен v1.1.48) + - save_run пишет scenario_run_id/step_number (✅ исправлено v1.1.48) + - TIMEOUT: op_data инициализировать (✅ исправлено v1.1.48) + - RUNNING до API (✅ исправлено v1.1.48) + - Блокировка параллельных запусков (pending) + - version в definitions для optimistic locking (pending) + - Сервисные токены (pending) + +--- + +## 7. ЧТО НУЖНО ОТ АГЕНТА + +### Проанализировать и ответить: + +1. **Общая архитектура** — оценить, найти слабые места, предложить улучшения + +2. **Дублирование кода** — `_find_uid` и `_uid_from_location` есть и в api_test.py и в scenario.py. Вынести в общий модуль? Куда? + +3. **scenario_definitions** — спроектировать таблицу: + - Поля: id, client_id, stand, name, steps JSONB, version, is_active, created_at, updated_at, updated_by + - Индексы: UNIQUE(client_id, stand, lower(name)) + - API CRUD: какие именно эндпоинты, какие проверки + - Seed: как именно импортировать из scenario_seed.yaml при первом старте + +4. **UI редактора сценариев:** + - Модальное окно: структура HTML + - JS-логика: загрузка списка, создание/редактирование/удаление + - Выпадающие списки: сервисы из GET /api/services, операции из GET /api/operations/{svcId}, параметры из GET /api/params/{opId} + - Валидация на фронте перед отправкой + +5. **Runner** — нужно ли что-то менять в `run_scenario()`? Он сейчас берёт шаги из config.yaml, должен из БД. Также нужно сохранять snapshot шагов в scenario_runs. + +6. **Безопасность:** + - CRUD сценариев: проверка client_id+stand + - Optimistic locking (version) + - Блокировка параллельных запусков (HTTP 409) + +7. **Что ещё критично упущено?** — любые дыры, которые не покрыты текущим планом + +8. **Приоритетный порядок реализации:** + - Что делать сначала, что потом + - Что можно выпустить в v1.1.49, что отложить + +### НЕ ДЕЛАТЬ: +- Не писать код (только анализ и план) +- Не трогать git +- Не менять файлы + +--- + +## 8. ФАЙЛЫ ДЛЯ АНАЛИЗА (читать в этом порядке) + +1. `app-autotest/site/app.py` +2. `app-autotest/site/api/http_client.py` +3. `app-autotest/site/api/auth.py` +4. `app-autotest/site/routes/main.py` +5. `app-autotest/site/routes/api_test.py` (самый важный) +6. `app-autotest/site/routes/api_scenario.py` +7. `app-autotest/site/operations/scenario.py` +8. `app-autotest/site/operations/get_params.py` +9. `app-autotest/site/operations/get_services.py` +10. `app-autotest/site/operations/get_instances.py` +11. `app-autotest/site/operations/tracker.py` +12. `app-autotest/site/operations/service_list.py` +13. `app-autotest/site/db/pool.py` +14. `app-autotest/site/db/init_db.py` +15. `app-autotest/site/db/save_run.py` +16. `app-autotest/site/runner.py` +17. `app-autotest/site/config.yaml` +18. `app-autotest/site/static/app.js` +19. `app-autotest/site/templates/index.html` +20. `app-autotest/site/static/style.css` +21. `development/dummycreate.har` (HAR-трассировка CREATE) +22. `DOCS/ARCHITECTURE-FULL.md` +23. `DOCS/sol-answers.md` +24. `DOCS/sol-scenario-editor.md` +25. `app-autotest/site/config/services_test.txt` +26. Любой YAML из `STANDS/dev/resources_yaml/` (например `1_dummy.yaml`, `115_mariadb.yaml`) diff --git a/DOCS/sol-scenario-editor.md b/DOCS/sol-scenario-editor.md new file mode 100644 index 0000000..77f2d92 --- /dev/null +++ b/DOCS/sol-scenario-editor.md @@ -0,0 +1,48 @@ +# Sol — ответы по редактору сценариев + +Дата: 2026-07-30 + +## 1. Структура `steps` +- JSONB массив, отдельная таблица не нужна +- Обязательно поле `resource` — идентификатор инстанса внутри сценария (для связи create→modify→delete) +- `scenario_definitions`: + `version INTEGER`, `updated_by`, `is_active`/`deleted_at`, уникальность имени case-insensitive +- `scenario_runs`: + `definition_id`, `definition_version`, `steps_snapshot` +- Runner работает со snapshot, не перечитывает определение + +## 2. Параметры в редакторе +- Из Nubes API: сервис→операции→`/instanceOperations/default/{opId}`→коды +- Выпадающий список с типом, обязательностью, default +- Map/array — JSON-строка с валидацией +- Кеш: браузерный на время сессии редактора ИЛИ серверный (stand+opId, TTL 5 мин) +- Свободный ввод кода не нужен + +## 3. Seed из config.yaml +- Не импортировать при каждом пустом старте +- Схема: marker импорта → `INSERT ON CONFLICT DO NOTHING` → marker `scenario_seed_v1=completed` +- YAML вынести в `scenario_seed.yaml`, после rollout удалить +- Остальной config.yaml не трогать + +## 4. UI редактор +- Модальное окно или боковая панель (не inline) +- Имя, список шагов, сервис, операция, параметры +- Кнопки добавить/удалить/вверх/вниз +- Drag-and-drop не нужен +- Мягкое удаление: `is_active=false` + +## 5. Валидация +- При сохранении: структура, существование сервиса, доступность операции, коды параметров, типы, уникальность resource, порядок (create→modify→delete, после delete ничего) +- При запуске: повторить по актуальному API +- Невалидный сценарий не запускать частично + +## 6. Критически упущенное + +1. `POST /api/scenario/run` не возвращает run ID — гонка при двух запусках. Создавать запись ДО thread, вернуть HTTP 202 + run_id +2. Нужен `GET /api/scenario/runs/` — поллинг конкретного запуска +3. `save_run()` не пишет `scenario_run_id` и `step_number` — шаги не связаны со сценарием +4. TIMEOUT: `op_data` может быть неинициализирована +5. Шаг нужно создавать в `runs` со статусом RUNNING ДО обращения к API, потом обновлять +6. Блокировка параллельных запусков: HTTP 409 для одного client_id+stand +7. CRUD: проверять `client_id+stand` при всех операциях +8. `version` в definitions: PUT с текущей version, 409 при конфликте +9. Runner использует персональный токен — нужен сервисный токен/клиент по stand +10. Имя не идентификатор: API запуска принимает `definition_id`, имя — редактируемое поле diff --git a/TASKS/SOLdescribe.md b/TASKS/SOLdescribe.md new file mode 100644 index 0000000..84b4ab0 --- /dev/null +++ b/TASKS/SOLdescribe.md @@ -0,0 +1,79 @@ +Список задач обновлен + +# Что получится из Autotest + +**Autotest** станет веб-приложением для автоматической проверки операций облачных сервисов Nubes. + +Сейчас приложение позволяет вручную создавать, изменять и удалять инстансы. Следующий этап — запуск готовых автоматических сценариев, например: + +```text +Создать PostgreSQL → изменить параметры → проверить результат → удалить +``` + +## Как это будет работать + +1. В конфигурационном YAML-файле задаётся: + - какие сервисы проверять; + - какие операции выполнять; + - в какой последовательности; + - какие параметры использовать; + - нужно ли удалять созданный инстанс. + +2. Пользователь открывает приложение, выбирает сценарий и стенд, нажимает **«Запустить»**. + +3. Приложение последовательно выполняет операции и показывает: + - текущий шаг; + - созданный инстанс; + - продолжительность; + - успешный или неуспешный результат; + - причину ошибки. + +4. Результаты сохраняются в PostgreSQL и доступны всем тестировщикам в общей истории. + +## Архитектура + +```text +YAML-сценарии в Git + ↓ +Flask-приложение + ↓ +Исполнитель сценариев + ↓ +Nubes API + ↓ +PostgreSQL: запуски, шаги, результаты и ошибки +``` + +Ручные операции и автоматические сценарии будут использовать один и тот же механизм работы с Nubes API. Благодаря этому автоматический тест будет выполнять операцию так же, как текущий ручной интерфейс и UI облака. + +Для каждого стенда используется отдельный технический токен. Токен пользователя нужен только для ручных операций. + +## Первый рабочий релиз + +В MVP войдут: + +- YAML-сценарии, хранящиеся и проверяемые через Git; +- ручной запуск сценария из веб-интерфейса; +- последовательное выполнение операций; +- поддержка dev и test; +- сценарии с временными и постоянными тестовыми инстансами; +- отображение выполнения по шагам; +- общая история всех запусков; +- сохранение результатов и ошибок в PostgreSQL; +- защита от одновременного запуска нескольких сценариев на одном стенде. + +Prod на первом этапе будет заблокирован. После проверки на dev и test добавим отдельные правила безопасности для тестовой организации, карантина и разрешённых операций. + +## Дальнейшее развитие + +После MVP можно добавить: + +- запуск по расписанию; +- уведомления о падениях; +- регулярные проверки выбранных сервисов; +- статистику успешности и длительности операций; +- безопасный запуск на prod; +- настройку сценариев через веб-интерфейс; +- impersonation и проверку операций от разных пользователей. + +**Итог:** это будет не копия UI облака, а централизованный инструмент для регулярной проверки работоспособности операций Nubes: с настраиваемыми сценариями, общими результатами и контролем безопасности. \ No newline at end of file