diff --git a/doc/progress.md b/doc/progress.md index a0529d0..fa57679 100644 --- a/doc/progress.md +++ b/doc/progress.md @@ -17,12 +17,180 @@ - UI: формы создания по аналогии с cron, счётчики на главной ### Прочий полезный функционал +- ~~Клонировать функцию (копия с новым именем)~~ ✅ v1.3.80 +- ~~Переменные окружения (env vars) через UI~~ ✅ v1.3.78 - Метрики на главной странице (данные уже есть в metrics-collector) - Автообновление логов (polling каждые 3-5 сек) - Копировать маршрут одной кнопкой (📋 рядом с маршрутом) -- Статус функции (Ready/NotReady/Error) в таблице -- Клонировать функцию (копия с новым именем) -- Переменные окружения (env vars) через UI + +--- + +## 2026-05-09 — 2026-05-10 + +### Ветка: `feat/function-status-clone-envvars` / `feat/clone-function` + +--- + +#### v1.3.78 — Переменные окружения: патч Deployment напрямую + +**Проблема:** Fission newdeploy executor игнорирует `fn.Spec.PodSpec` при построении +Deployment — применяет только `env.Spec.Runtime.Container`. Сохранение env vars в +Function CRD через UI не приводило к попаданию переменных в pod. + +**Решение:** После обновления Function CRD — дополнительно патчить Deployment +напрямую через Kubernetes API (`StrategicMergePatch`). + +- Файл: `console/internal/api/function_crud.go` +- Новая функция `patchDeploymentEnvVars(ctx, ns, fnName, envContainerName, envVars)` +- Поиск Deployment по labels: `functionName=,functionNamespace=,executorType=newdeploy` +- Patch: `StrategicMergePatch` с `containers[{name: envContainerName, env: [...]}]` +- Импорт добавлен: `k8stypes "k8s.io/apimachinery/pkg/types"` +- Образ: `naeel/fission-console:v1.3.78` + +--- + +#### v1.3.79 — LLM: убрано ограничение тем чата + сброс кэша роутера + +**Проблема 1:** LLM ассистент отказывался отвечать на вопросы не по теме Fission Console. + +**Решение:** Удалён блок `## Чем НЕ занимаешься` из `buildChatSystemPrompt()` в +`console/internal/api/ai_prompts.go`. + +**Проблема 2:** Env vars всё ещё не работали после v1.3.78 — роутер закешировал +старый poolmgr адрес (funcSvc cache). + +**Решение:** `kubectl rollout restart deployment/router -n fission` — сбросил кэш. +После перезапуска env vars начали попадать в поды. + +- Образ: `naeel/fission-console:v1.3.79` + +--- + +#### v1.3.80 — Клонирование функции (полная реализация) + +**Фича:** `POST /functions/:name/clone` — создаёт полную копию функции с новым именем. + +**Backend** (`console/internal/api/function_clone.go`, новый файл): +1. Валидирует `new_name` (regex `^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`, ≤57 символов) +2. Скачивает архив из storagesvc (type:url) или base64 (type:literal) +3. Заливает как новый архив в storagesvc (новый S3-объект — удаление оригинала не ломает клон) +4. Создаёт новый Package с именем `-` +5. Копирует аннотации: `language`, `source-type`, `env-vars`, `archive-filename`, добавляет `cloned-from` +6. Копирует entrypoint, timeout, InvokeStrategy, podspec +7. Создаёт Function CRD +8. Копирует HTTP методы из оригинального триггера, создаёт HTTPTrigger +9. При ошибке Function/Trigger — откатывает созданные Package/Function + +**Route** (`console/internal/api/handlers.go`): +``` +POST /functions/:name/clone +``` + +**Frontend** (`console/ui/index.html`, `console/ui/js/functions.js`): +- Кнопка **📋 Клон** в нижней панели edit modal +- Inline форма: поле имени, кнопки «Клонировать» / «✕» +- Предзаполнение именем `-copy` +- Валидация на клиенте (тот же regex) +- При успехе: закрытие модалки + polling до появления в таблице + +**Тест результат:** +``` +POST /console/api/functions/clone-src/clone {"new_name":"clone-src-copy"} +→ 201 {"cloned_from":"clone-src","name":"clone-src-copy","package":"clone-src-copy-20260509162619","route":"/47b6ef5e8225/clone-src-copy"} +kubectl get function clone-src-copy ✅ +kubectl get package clone-src-copy-... ✅ type:url storagesvc +kubectl get httptrigger clone-src-copy-route ✅ methods=["GET"] +annotation: fission-console/cloned-from=clone-src ✅ +``` + +- Образ: `naeel/fission-console:v1.3.80` + +--- + +#### v1.3.81 — Fix: clone не обновлял таблицу (`loadFunctions` → `reloadAll`) + +**Проблема:** После клонирования таблица не обновлялась — функция `loadFunctions()` +не существует, правильное название `reloadAll()`. + +**Fix:** `console/ui/js/functions.js` — замена вызова. + +- Образ: `naeel/fission-console:v1.3.81` + +--- + +#### v1.3.82 — Fix: `apiFetch is not defined` → `requestJSON` + +**Проблема:** `apiFetch` не существует в codebase. Правильный хелпер — `requestJSON(url, method, body)` из `api.js`. + +**Fix:** `console/ui/js/functions.js` — переписан `submitClone()` на `requestJSON`. + +- Образ: `naeel/fission-console:v1.3.82` + +--- + +#### v1.3.83 — Fix: clone — задержка 800мс перед reloadAll (race condition) + +**Проблема:** После клонирования таблица обновлялась раньше, чем k8s возвращал +новый объект в List-ответе. + +**Fix:** `setTimeout(reloadAll, 800)` → заменено на polling с ожиданием появления +функции в `S.fns` (до 5 попыток × 1 сек). + +- Образ: `naeel/fission-console:v1.3.83` + +--- + +#### v1.3.84 — Help + LLM промпты: разделы env vars и clone + +**Help modal** (`console/ui/index.html`): +- Новая секция **«Переменные окружения функции»**: как добавлять через UI, как читать в коде (`os.environ` / `process.env` / `os.Getenv`) +- Новая секция **«Клонирование функции»**: кнопка 📋 Клон, что копируется, правила имени + +**LLM системный промпт** (`console/internal/api/ai_prompts.go`): +- В раздел «Редактирование функции» добавлены пункты «Переменные окружения» и «📋 Клон» + +- Образ: `naeel/fission-console:v1.3.84` + +--- + +#### v1.3.85 — Fix: polling до появления клона в таблице + +**Проблема:** После клонирования — резкий переход в таблицу, клон ещё не виден +(k8s list не успел вернуть новый объект). + +**Fix:** `console/ui/js/functions.js` — polling loop: +1. Закрыть модалку +2. Показать статус «Клонирование завершено, обновляем список...» +3. Через 700мс — `reloadAll()` +4. Проверить `S.fns` на наличие нового имени +5. Если не найден — повторить через 1 сек (до 5 попыток) +6. Показать финальное сообщение + +- Образ: `naeel/fission-console:v1.3.85` + +--- + +#### Unit-тесты (`console/internal/api/function_clone_test.go`) + +21 тест, все PASS. Файл создан с нуля. + +| Группа | Тесты | +|---|---| +| Валидация имени | пустое → 400; uppercase → 400; начинается с `-` → 400; заканчивается `-` → 400; 58 символов → 400; 57 символов → OK (404); имя с дефисами → OK | +| Источник не найден | 404 с именем функции в теле | +| Успешный клон (type:literal) | Package создан; Function создана; аннотации `cloned-from`, `language`, `source-type` скопированы; entrypoint и timeout скопированы; HTTPTrigger с методами и маршрутом | +| Маршрут | явный `/custom/path`; автодобавление `/` при отсутствии | +| Конфликт имени | дублирующее → 409 | +| Откат | ошибка создания Function → Package удалён | +| downloadPackageBytes | type:literal; type:url; пустой Package → ошибка | +| downloadFromStoragesvc | HTTP 404 → ошибка с кодом | +| getTriggerMethods | триггер найден; триггер не найден | +| Невалидный JSON | → 400 | +| Ссылка Package→Function | `spec.package.packageref.name` совпадает с реальным Package | + +``` +ok fission-console/internal/api 0.040s +``` ---