Files
fission-console/doc/progress.md
T

45 KiB
Raw Blame History

Progress Log

2026-05-19 — PV Storage Migration + Fetcher v1.23.0

Ветка: feat/console-pv-storage (git commit 2aadae3, pushed)

Задача: Перевести storagesvc с S3 на PV (PersistentVolume), привести все образы к v1.23.0.

Что сделано

  • helm/fission-values.yamlimageTag: v1.23.0, fetcher.image: naeel/fetcher, fetcher.imageTag: v1.23.0, PV backend включён
  • naeel/fetcher:v1.23.0 — собран из fission-src/cmd/fetcher/, запушен в Docker Hub (отдельный бинарник, в naeel/fission-bundle не входит)
  • fission-storage-pvc — Bound, 2Gi, vcd-disk-ext4, namespace fission; S3 полностью отключён

Баги найдены и задокументированы (doc/report-2026-05-19-pv-migration-bugs.md)

# Описание Причина Fix
1 Helm upgrade откатил образы с v1.23.0 на v1.22.1 imageTag: v1.22.1 в values Исправлено на v1.23.0
2 Field manager конфликт при helm upgrade fission-console патчит FISSION_RESOURCE_NAMESPACES Перед upgrade: kubectl delete deploy executor router -n fission
3 Pool pods ImagePullBackOff — FETCHER_IMAGE=fission/fetcher:v1.22.0 (не существует) fetcher — отдельный образ, его нет в fission-bundle Собрали naeel/fetcher:v1.23.0
4 Router JWT password сменился после helm upgrade Новый secret Console читает динамически — работает; CLI токены устарели

Тест-прогон run_all.sh — PASS=8 FAIL=0 (319 сек)

Скрипт Результат Кол-во проверок
test_auth.sh PASS 14
test_functions_crud.sh PASS 29
test_ttl.sh PASS 10
test_isolation.sh PASS 11
test_update.sh PASS 10
test_invoke.sh PASS 9
test_linters.sh PASS 31
test_stress.sh PASS 3 (8 параллельных пользователей)

Лог: test-results/2026-05-19_08-51-31.log


TODO (backlog)

Биллинг / статистика для бухгалтерии

Цель: считать потреблённые ресурсы по пользователям для тарификации.

  • Метрики: количество вызовов, время выполнения (ms), CPU/RAM пода
  • Агрегация по namespace (пользователю) за период (день/месяц)
  • Хранение истории (сейчас metrics-collector хранит только текущее)
  • Отчёт: пользователь → вызовы + суммарное время → сумма к оплате
  • API для бухгалтерии или выгрузка CSV/Excel
  • Что уже есть: metrics-collector (/metrics endpoint), Fission router логирует вызовы, k8s metrics-server
  • Примерная модель: X руб/1000 вызовов + Y руб/GB·сек

MQ-триггер и Kube-Watch триггер в консоли

  • Backend: добавить GVR для messagequeuetriggers.fission.io и kuberneteswatchtriggers.fission.io
  • UI: формы создания по аналогии с cron, счётчики на главной

Прочий полезный функционал

  • Клонировать функцию (копия с новым именем) v1.3.80
  • Переменные окружения (env vars) через UI v1.3.78
  • Метрики на главной странице (данные уже есть в metrics-collector)
  • Автообновление логов (polling каждые 3-5 сек)
  • Копировать маршрут одной кнопкой (📋 рядом с маршрутом)

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=<name>,functionNamespace=<ns>,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 с именем <new_name>-<timestamp>
  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 форма: поле имени, кнопки «Клонировать» / «✕»
  • Предзаполнение именем <original>-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 не обновлял таблицу (loadFunctionsreloadAll)

Проблема: После клонирования таблица не обновлялась — функция loadFunctions() не существует, правильное название reloadAll().

Fix: console/ui/js/functions.js — замена вызова.

  • Образ: naeel/fission-console:v1.3.81

v1.3.82 — Fix: apiFetch is not definedrequestJSON

Проблема: 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

План перед работой

  • Зафиксировать, что REST /v2/* недоступен в текущем кластере Fission v1.22.1 и MVP идет через Kubernetes CRD API.
  • Реализовать первый рабочий Terraform ресурс fission_environment.
  • Добавить минимальный CRUD в клиент для CRD environments.fission.io.
  • Проверить сборку go build ./....

Факт выполнения

  • Обновлен план в doc/CODEX_PLAN.md: путь реализации переведен на CRD API.
  • Создан каркас провайдера и заготовки ресурсов.
  • Реализован рабочий fission_environment:
    • schema (name, image, version, poolsize, namespace, id, uid)
    • Configure() с получением клиента из provider
    • Create/Read/Update/Delete через Kubernetes CRD environments.fission.io
  • В internal/client/client.go добавлены методы:
    • CreateEnvironment / GetEnvironment / UpdateEnvironment / DeleteEnvironment
    • IsNotFound для обработки удаления/дрейфа state
  • Проверка go build ./... проходит успешно.

Следующий шаг

  • Реализовать fission_package (zip/base64 -> spec.source.literal) через CRD packages.fission.io.

Обновление этапа (fission_package)

  • Реализован CRUD в internal/client/client.go для packages.fission.io:
    • CreatePackage
    • GetPackage
    • UpdatePackage
    • DeletePackage
  • Реализован ресурс fission_package в internal/resources/package_resource.go:
    • schema: name, environment, source_dir, code_path, code_hash, build_command, namespace, computed id, uid, build_status, build_log
    • валидация источника кода: задан ровно один из source_dir или code_path
    • упаковка source_dir в zip и кодирование base64 в spec.source.literal
    • Create/Read/Update/Delete через Kubernetes CRD API
  • Проверка сборки: go build ./... успешно.

Следующий шаг

  • Реализовать fission_function через CRD functions.fission.io.

Обновление этапа (fission_function)

  • Реализован CRUD в internal/client/client.go для functions.fission.io:
    • CreateFunction
    • GetFunction
    • UpdateFunction
    • DeleteFunction
  • Реализован ресурс fission_function в internal/resources/function_resource.go:
    • schema: name, environment, package_name, entrypoint, namespace, computed id, uid
    • Configure/Create/Read/Update/Delete
    • маппинг в CRD Function (spec.environment, spec.package.packageref, spec.package.functionName)
  • Проверка сборки: go build ./... успешно.

Следующий шаг

  • Реализовать fission_http_trigger через CRD httptriggers.fission.io.

Обновление этапа (fission_http_trigger)

  • Реализован CRUD в internal/client/client.go для httptriggers.fission.io:
    • CreateHTTPTrigger
    • GetHTTPTrigger
    • UpdateHTTPTrigger
    • DeleteHTTPTrigger
  • Реализован ресурс fission_http_trigger в internal/resources/http_trigger_resource.go:
    • schema: name, function, url, methods, create_ingress, host, namespace, computed id, uid
    • Configure/Create/Read/Update/Delete
    • маппинг в CRD HTTPTrigger (spec.relativeurl, spec.methods, spec.functionref, spec.createingress)
  • Проверка сборки: go build ./... успешно.

Следующий шаг

  • Добавить пример examples/hello-python/main.tf и выполнить smoke Terraform apply.

Обновление этапа (пример Terraform)

  • Создан пример examples/hello-python/main.tf с использованием ресурсов:
    • fission_environment
    • fission_package
    • fission_function
    • fission_http_trigger
  • Добавлен код функции examples/hello-python/code/main.py.

Следующий шаг

  • Подготовить локальную установку бинарника провайдера для terraform init и выполнить smoke terraform apply.

Обновление этапа (smoke Terraform apply)

  • Собран бинарник провайдера и подключен через Terraform dev_overrides.
  • Прогнан terraform plan для examples/hello-python: план успешен, 4 ресурса к созданию.
  • Прогнан terraform apply и выполнена функциональная проверка.

Исправленные баги по факту smoke:

  • fission_package: после Create computed-поля (build_status, build_log) могли оставаться unknown.
    • Исправлено формирование state в unstructuredToPackageModel.
  • fission_function: CRD требовал обязательный spec.InvokeStrategy.
    • Добавлен InvokeStrategy в payload функции.
  • fission_http_trigger: несогласованность state (create_ingress null -> false).
    • В schema добавлены Computed + Default(false) для create_ingress.
    • Для methods добавлен Computed.

Дополнительно:

  • Для текущего python MVP fission_package переведен на spec.deployment.literal (как у рабочего CLI-пакета).
  • Проверка endpoint после apply:
    • GET /tf-hello -> hello from fission via terraform.

Следующий шаг

  • Добавить README по запуску dev override и оговорить ограничения текущего MVP (source_dir ожидает main.py).

Обновление этапа (README)

  • Добавлен README.md в корень репозитория.
  • Описаны:
    • список реализованных ресурсов MVP
    • запуск через Terraform dev override
    • текущие ограничения MVP

Обновление этапа (import + тесты)

  • Добавлена поддержка terraform import для всех 4 ресурсов:
    • fission_environment
    • fission_package
    • fission_function
    • fission_http_trigger
  • Формат import ID: namespace/name.
  • Добавлены unit-тесты в terraform/provider/internal/resources/*_test.go:
    • парсинг import ID
    • конвертация model <-> unstructured
    • валидация package source
    • базовая проверка HTTP trigger round-trip
  • Прогон валидации:
    • go test ./... — успешно
    • smoke terraform plan/apply — успешно
    • endpoint GET /tf-hellohello from fission via terraform

Следующий шаг

  • Добавить acceptance-тесты с опциональным запуском по env-флагу.

Обновление этапа (acceptance тест)

  • Добавлен acceptance-тест terraform/provider/internal/client/client_acceptance_test.go.
  • Тест выполняет живой CRUD в кластере для цепочки:
    • Environment -> Package -> Function -> HTTPTrigger
  • Запуск теста:
    • ACCEPTANCE_TEST=1 KUBECONFIG=/home/naeel/.kube/config go test ./internal/client -run TestAcceptanceFissionCRUD -v
  • Результат: PASS.

Следующий шаг

  • Расширить acceptance-тест проверкой реального HTTP-вызова функции через ingress.

Обновление этапа (много функций + суровая нагрузка)

  • Добавлен examples/stress-suite:
    • функции: fast, cpu, json
    • маршруты: /stress/fast, /stress/cpu, /stress/json
    • Terraform-конфиг на 10 ресурсов (env + 3 package + 3 function + 3 trigger)
  • Добавлен скрипт examples/stress-suite/scripts/load_test.sh для параллельной нагрузки.
  • Реальный прогон после донастройки:
    • 900 запросов на endpoint
    • 90 параллелизм
    • итог: 100% success на всех трех endpoint-ах.

Следующий шаг

  • Добавить в acceptance-тест проверку HTTP latency/perf budget и порогов SLO.

Обновление этапа (JS/Go source support)

  • В fission_package расширена поддержка source_dir:
    • main.py
    • main.js
    • main.go
  • Добавлены unit-тесты на выбор JS/Go исходников в package_resource_test.go.
  • Прогон go test ./... — успешно.

Следующий шаг

  • Добавить отдельные Terraform примеры для Node.js и Go функций.

2026-04-15

Fission Console — Web UI для управления функциями

Ветка: feat/console

Реализовано (14 апреля, вечер → 15 апреля, утро)

Backend (console/main.go):

  • Go HTTP-сервер с embedded UI
  • CRUD API для Fission CRD через dynamic k8s client:
    • POST /api/functions — создание (Package + Function + HTTPTrigger атомарно с rollback)
    • GET /api/functions — список всех
    • GET /api/functions/{name} — детали (с декодированным кодом, route, methods)
    • PUT /api/functions/{name}/code — обновление кода
    • POST /api/functions/{name}/invoke — вызов функции через роутер
    • DELETE /api/functions/{name} — удаление (trigger + function + package)
  • Двойная маршрутизация: /api/* и /console/api/* (для работы через ingress /console/)
  • CORS middleware, request logging

UI (console/ui/index.html):

  • SPA-дашборд с карточками (environments, packages, functions, httptriggers, timetriggers)
  • Таблица функций с кнопками Edit/Invoke/Delete
  • Модал Create: выбор environment, ввод кода, route, methods
  • Модал Edit Code: редактирование и сохранение
  • Модал Invoke: отправка запроса, отображение статуса/latency/response
  • Модал Delete: подтверждение
  • Динамический API_BASE для работы как с / так и с /console/ prefix

Тесты (console/main_test.go):

  • 5 unit-тестов:
    • TestNormalizeMethods — нормализация HTTP-методов
    • TestCreateFunctionValidation — валидация обязательных полей
    • TestCreateFunctionSuccessAndGetDetails — полный CRUD flow + Get с декодированным кодом
    • TestUpdateFunctionCode — обновление кода в package
    • TestInvokeFunctionWithJWTAuth — invoke с mock-роутером, проверка JWT auth flow
  • Используется dynamicfake.NewSimpleDynamicClientWithCustomListKinds

Docker (console/Dockerfile):

  • Multi-stage: golang:1.26-alpinealpine:3.20
  • Бинарник ~15MB

K8s deployment (console/deploy/console.yaml):

  • ServiceAccount fission-console
  • ClusterRole с доступом к fission.io CRD (get/list/create/update/patch/delete)
  • ClusterRoleBinding
  • Deployment (1 replica, port 8090, health probes, resource limits)
  • Service (ClusterIP:8090)
  • Ingress (fission.kube5s.ru/console, nginx, TLS)

Invoke auth — проблема и решение

Проблема: invoke через console возвращал 401 от Fission router.

Исследование:

  1. Попробовал SA token из пода → key is of invalid type (K8s SA = RS256, router ожидает HS256)
  2. Прочитал feature-config: auth.enabled: true, endpoint /auth/login, JWT expiry 120s
  3. Нашёл credentials в секрете router: username=admin, password=..., jwtSigningKey=...
  4. Протестировал: POST /auth/login → получил JWT → invoke с Bearer JWT → 200 OK

Решение: console при invoke делает POST /auth/login к роутеру, получает JWT, кеширует на 100s.

Баги по пути:

  • Router возвращает 201 Created (не 200) на login — код проверял строго 200 → добавил || 201
  • Кешированный Docker-образ: пересобрал тот же тег v0.2.0, нод использовал старый → перешёл на v0.2.2

Env переменные для auth:

  • FISSION_AUTH_USERNAME → secretKeyRef из router.username
  • FISSION_AUTH_PASSWORD → secretKeyRef из router.password

E2E результат (все через ingress https://fission.kube5s.ru/console/)

Операция Результат
health 200 ok
create 201 Created (function + package + httptrigger)
get 200 (code, route, methods, environment)
update code 200
invoke 200, response_raw = ответ функции, latency_ms = 138
delete 200 (trigger + function + package очищены)

Коммиты

  • 6731e89 — feat: deliver fission console UI, k8s deploy, and tests
  • 8920ba1 — fix: invoke auth via Fission router JWT login

Docker Hub: naeel/fission-console:v0.2.2

Правила репозитория

Создан .github/copilot-instructions.md с правилами:

Обновление этапа (UI invoke stability: JS)

  • Проведена диагностика JS invoke через реальный UI-путь (/console/api/functions/{name}/invoke) и роутер/экзекьютор логи.
  • Найдена корневая причина JS-таймаутов:
    • для node-env используется v2/specialize
    • при functionName=main runtime пытался загрузить /userfunc/deployarchive/main
    • при plain literal deployarchive является файлом, не директорией
    • после specialize без корректного контракта запросы зависали и упирались в router roundtripper timeout.
  • Для nodejs-acc зафиксирован runtime image: ghcr.io/fission/node-env:1.32.5.
  • Для JS-функций выровнен контракт runtime:
    • spec.package.functionName выставлен в пустой entrypoint ("") для default export
    • код приведен к формату ответа Node runtime: return { status: 200, body: "..." }
    • для основных JS-маршрутов включены методы GET + POST.
  • Подтверждена работоспособность через console invoke:
    • fn-js-acc -> status=200, response_raw=hello-js-ok
    • fn-js-direct -> status=200, response_raw=hello-js-ok
    • тестовая матрица jsm1..jsm4 -> status=200.

Статус после фикса

  • Python invoke: работает.
  • JS invoke: работает по UI-пути и по прямому GET роутов.
  • Go invoke (fn-go-acc): остается отдельной runtime-проблемой (вне JS-фикса).
  • Маппинг путей (локально ~/remote_dev/ = ВМ ~/terra/)
  • Редактирование файлов — разрешено локально
  • Команды — ИСКЛЮЧИТЕЛЬНО через SSH (VPN-конфликты)

Следующий шаг

  • UI: автоматическое обновление дашборда после create/delete
  • Рассмотреть добавление логов функций (kubectl logs)
  • Рассмотреть добавление time triggers в UI

2026-04-15 (дополнение) — Fix по результатам баг-репорта

Что исправлено в Terraform provider

  • fission_package: добавлен ModifyPlan, который автоматически пересчитывает code_hash по локальному коду (source_dir/code_path).
  • fission_package: добавлена валидация существования environment до создания/обновления package.
  • fission_function: добавлена валидация существования environment и package до create/update.
  • fission_function: добавлена pre-flight валидация entrypoint для Python-исходника (main.func должен существовать как def func().
  • Добавлены unit-тесты на новый функционал (code_hash, entrypoint validation).

Проверка на живом кластере

  • После изменения examples/hello-python/code/main.py terraform plan теперь показывает fission_package.hello will be updated in-place с изменением code_hash.
  • Конфигурация с несуществующим environment теперь падает на этапе apply с ошибкой валидации.
  • Конфигурация с неверным entrypoint теперь падает на этапе apply с ошибкой валидации.

Ограничения

  • Runtime-проблемы Fission (зависания на cold start/таймауты выполнения) в этом изменении не трогались: исправлен только provider-слой валидации и обнаружения изменений.

2026-04-15 (дополнение) — Fix отображения кода в Console UI

Проблема

  • В модальном окне редактирования функции (Edit Code) для некоторых пакетов отображались байты ZIP (PK...) вместо исходного кода.

Причина

  • GET /console/api/functions/{name} декодировал spec.deployment.literal только из base64, но не обрабатывал архивированный payload.

Исправление

  • В console/main.go добавлено декодирование literal с поддержкой ZIP:
    • если payload plain text/utf-8 -> отдаётся как есть
    • если payload ZIP -> извлекается main.py/main.js/main.go (или первый utf-8 файл)
  • Обновлён deployment image: naeel/fission-console:v0.2.4.

Проверка

  • GET /console/api/functions/fn-go-acc теперь возвращает читаемый Go-код, без PK... сигнатур.

2026-04-15 (дополнение) — Полный пользовательский прогон UI и invoke-fix

Что проверено как пользовательский сценарий

  • Прогнан массовый invoke через UI API (POST /console/api/functions/{name}/invoke) для всех функций в списке.
  • Итого: 31 функций, из них 25 успешно отработали, 6 вернули 502/timeout (ожидаемо проблемные/сломанные кейсы).
  • Проверен полный edit flow через UI API на рабочей функции:
    • GET function -> PUT /code -> POST /invoke -> PUT /code (restore) -> POST /invoke.

Найденный UI-баг и исправление

  • Баг: после обновления кода через UI следующий invoke мог отдавать старую специализацию/кэш.
  • Причина: обновлялся только Package, но не обновлялся Function.spec.package.packageref.resourceversion.
  • Фикс в console/main.go:
    • после package update читается новый package.resourceVersion
    • выполняется update Function с новым packageref.resourceversion
    • invoke сразу использует новую (или восстановленную) версию кода.

Проверка фикса

  • После update через UI invoke возвращает новый ответ.
  • После restore через UI invoke возвращает исходный ответ (без зависания старого кэша).

Статус fn-go-acc

  • fn-go-acc продолжает падать не из-за UI, а из-за runtime specialization на стороне Fission.
  • Подтверждено логами router/executor: GetServiceForFunction ... context canceled и постоянными readiness-fail у poolmgr pod-ов go-acc.

2026-04-15 (дополнение) — Финальный фикс fn-go-acc

Симптом и root cause

  • fn-go-acc стабильно timeout'ился на invoke.
  • Изначальный пакет содержал main.go как deployment.literal, из-за чего go-runtime пытался грузить текст как plugin:
    • plugin.Open("/userfunc/deployarchive/main.go"): invalid ELF header.

Что сделано

  • Пересобран deploy-артефакт как Go plugin (main.so) и упакован в deploy.zip.
  • Важно: сборка выполнена в том же образе, что у Fission environment builder:
    • ghcr.io/fission/go-builder (Go 1.25.6), чтобы избежать несовместимости plugin ABI.
  • Функция обновлена через Fission CLI:
    • fission function update -n default --name fn-go-acc --env go-acc --entrypoint Handler --deployarchive /tmp/fn-go-acc-fix2/deploy.zip -f.

Результат проверки

  • /go-acc через router с JWT: hello-go-ok, HTTP 200.
  • Executor логи: specialization проходит успешно (specialized pod, added function service), без invalid ELF.

Контрольный smoke после фикса

  • /auto/ok -> HTTP 200
  • /js-acc -> HTTP 200
  • /js-direct -> HTTP 200
  • /go-acc -> HTTP 200

2026-04-15 (дополнение) — Edit Code для fn-go-acc снова показывает исходник

Проблема

  • В Edit Code для fn-go-acc поле code было пустым.
  • Причина: после --deployarchive пакет pkg-go-acc перешел на spec.deployment.type=url, а в console backend чтение кода шло только из spec.deployment.literal.

Исправление

  • В console/main.go добавлен fallback-поиск исходника:
    • spec.source.literal
    • spec.deployment.literal
    • spec.source.url
    • spec.deployment.url
  • Добавлена загрузка архива по URL и извлечение исходника из zip (если есть текстовые файлы).
  • Добавлен unit-тест TestGetFunctionUsesSourceLiteralWhenDeploymentLiteralMissing.
  • Собран и выкачен образ naeel/fission-console:v0.2.6, деплой обновлен.

Дополнительно по данным в кластере

  • Для fn-go-acc обновлен sourcearchive (main.go), чтобы pkg-go-acc.spec.source.literal содержал исходник и был доступен в Edit Code.

Проверка

  • GET /console/api/functions/fn-go-acc возвращает непустой code (Go source).
  • /go-acc продолжает отвечать hello-go-ok, HTTP 200.

2026-04-15 (дополнение) — TLS в console, бренд NUBES, проверка tf-neg-syntax-fn

TLS: фактический статус

  • http://fission.kube5s.ru/console/ -> 308 Permanent Redirect на https://...
  • https://fission.kube5s.ru/console/ -> 200
  • Ingress fission-console настроен с:
    • nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    • tls.secretName: fission-tls
    • cert-manager.io/cluster-issuer: letsencrypt-prod

UI оформление (NUBES)

  • В console/ui/index.html добавлены:
    • favicon (inline SVG)
    • брендинг в navbar: mark + wordmark NUBES / FISSION CONSOLE
    • обновлен <title> на NUBES Fission Console
  • Выкат: naeel/fission-console:v0.2.9.

Invoke tf-neg-syntax-fn — проверка

  • Подтверждено, что у функции синтаксически невалидный код (def main(: ...).
  • Console invoke теперь возвращает fail-fast ошибку (не «молчание»):
    • {"error":"invoke \"tf-neg-syntax-fn\" timeout after 20s: function specialization likely failed (for example, syntax error)"}
  • Причина на кластере: specialization падает в runtime с 500, executor делает ретраи.

2026-04-15 (дополнение) — Лечение "красного" HTTPS

Root cause

  • На одном host fission.kube5s.ru было два ingress:
    • fission-console с TLS
    • fission-router без TLS
  • Из-за смешанной host-конфигурации TLS мог работать нестабильно/давать красный индикатор в браузере.

Fix

  • Пропатчен fission/fission-router:
    • добавлен spec.tls с secretName: fission-tls
    • добавлена аннотация nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

Проверка

  • http://fission.kube5s.ru/neg/syntax -> 308 redirect на HTTPS
  • Сертификат endpoint: Let's Encrypt R13, CN/SAN fission.kube5s.ru, валиден
  • https://fission.kube5s.ru/console/ -> HTTP 200

2026-04-15 (дополнение) — Строгая очистка: оставлены только рабочие и с видимым кодом

Требование

  • Убрать всё лишнее и оставить только функции, которые одновременно:
    • имеют непустой code в GET /console/api/functions/{name}
    • успешно проходят POST /console/api/functions/{name}/invoke со status=200

Что сделано

  • Выполнена финальная очистка функций по whitelist.
  • После очистки дополнительно проверены все оставшиеся функции через Console API (code + invoke).
  • Исправлена ошибка в служебном cleanup-скрипте (битый jsonpath с {n}), из-за которой падала пост-обработка orphan-ресурсов.

Итоговый набор

  • auth-test2
  • fn-js-direct
  • fn-js-acc
  • hello
  • tf-auto-ok-fn
  • tf-stress-fast-fn

Финальное состояние кластера

  • functions=6
  • httptriggers=6
  • packages=6

Финальная валидация

  • Для каждой из 6 функций: code=OK, invoke=OK.

2026-04-15 (дополнение) — Наращивание до 15 функций + исправление фавикона в live UI

Запрос

  • Увеличить набор до 15 функций, включая error-кейсы.
  • Прогнать тесты и чинить код/манифесты при расхождении с ожиданием.
  • Исправить favicon в реальном UI (а не только в репозитории).

Что сделано по функциям

  • Подняты функции из examples: hello-python, deep-recursion, destroy-test, frequent-update, orphan-test, multi-env-1/2/3.
  • Добавлен негативный кейс tf-neg-syntax-fn с route /neg/syntax.
  • Доведено до ровно functions=15, httptriggers=15.

Фиксы по коду/манифестам (по результатам тестов)

  • examples/multi-env-1/main.tf
    • исправлен source_dir с "$\{path.module\}/code" на "${path.module}/code".
    • заменен image env с ghcr.io/fission/python-env:v1.20.0 на ghcr.io/fission/python-env.
  • examples/multi-env-2/main.tf
    • аналогичные исправления source_dir и image.
  • examples/multi-env-3/main.tf
    • аналогичные исправления source_dir и image.

Тест-матрица (router + JWT)

  • Итог: PASS 15 / FAIL 0.
  • Успешные (HTTP 200):
    • /auth-test2, /js-acc, /js-direct, /hello, /auto/ok, /destroy-test, /freq-update, /tf-hello, /multi-env-1, /multi-env-2, /multi-env-3, /orphan-test, /stress/fast.
  • Ожидаемые error-кейсы:
    • /deep-recursion -> timeout (curl rc=28, HTTP 000)
    • /neg/syntax -> timeout (curl rc=28, HTTP 000)
  • Доп. проверка через Console invoke:
    • tf-multi-env-1-fn -> status=200
    • tf-hello-fn -> status=200
    • tf-neg-syntax-fn и tf-deep-recursion-fn -> ожидаемая fail-fast ошибка invoke timeout.

Фавикон (live)

  • Причина «старого фавикона»: в кластере работал старый образ naeel/fission-console:v0.3.0.
  • Собран и выкачен новый образ: naeel/fission-console:v0.3.1.
  • Deployment обновлен и успешно прокатан.
  • Проверено в live HTML: отдается
    • <link rel="icon" type="image/png" href="https://nubes.ru/themes/custom/nubes_2025/favicon.png">.

2026-04-27

Сессия: poolmgr reuse fix (Bug #1 + Bug #2) + console cleanup

Bug #1 — Generation в TapService/UnTapService (client.go, commit 775845b)

  • Симптом: 10/10 HTTP 200, но pod count рос 1→11 (новый pod на каждый invoke).
  • Root cause: Generation не передавался в TapService/UnTapService. MarkAvailable строил ключ {UID, RV, Generation=0} вместо {UID, RV, Generation=1}activeRequests никогда не декрементировался → всегда cache miss.
  • Fix: добавить Generation: fnMeta.Generation в оба вызова в pkg/executor/client/client.go.
  • Image: naeel/fission-bundle:v1.22.0-multi-ns-9.

Bug #2 — gpm.podLister[ns] nil для user namespace (gpm.go, commit 0cae275)

  • Симптом: после Bug #1 fix — reuse всё ещё не работал.
  • Root cause: AddNamespace обновлял только poolPodC.podLister[ns], но не gpm.podLister[ns]. IsValid вызывал gpm.podLister[ns].Pods(...).Get(...) → nil pointer panic → net/http рвал соединение → router retry → activeRequests=1 (stuck) → cache miss → новый pod.
  • Fix: добавить одну строку в AddNamespace в pkg/executor/executortype/poolmgr/gpm.go:
    gpm.podLister[ns] = gpmInformer.Core().V1().Pods().Lister()
    
  • Image: naeel/fission-bundle:v1.22.0-multi-ns-10.
  • Live validation: PHP_PODS_BEFORE=1 → PHP_PODS_AFTER=2, NEW_PODS_CREATED=1, REUSE_WORKING=YES_REUSE_FIXED.
  • Postmortem: doc/POOLMGR_REUSE_BUG_POSTMORTEM_2026-04-27.md.

Console: убрана карточка тайм-триггеров (console/ui/index.html, commit 96a02b4)

  • Убрана карточка "Тайм-триггеры" из dashboard (счётчик 0).
  • Убраны JS-строки: getJSON('/timetriggers'), setText('time-count', ...), const [..., time].
  • Образ: naeel/fission-console:v1.1 (sha256:0713fee1...).
  • Деплой: kubectl set image deployment/fission-console console=naeel/fission-console:v1.1 -n fission.
  • Важно: container name в deployment = console (не fission-console!).

TODO: тайм-триггеры (не реализовано, отложено)

Нужно реализовать:

  1. Поле "Cron" в форме создания функции (или отдельная форма/таблица)
  2. POST /console/api/timetriggers → handler handleCreateTimeTrigger
  3. DELETE /console/api/timetriggers/:name → handler
  4. model.CreateTimeTriggerRequest {Name, FunctionName, Cron string}
  5. CRD builder: fission.io/v1 kind TimeTrigger, spec: {cron, functionref: {name, namespace}}
  6. Таблица тайм-триггеров в UI с колонками: имя, функция, расписание, удалить

Текущее состояние live кластера

  • Fission bundle: naeel/fission-bundle:v1.22.0-multi-ns-10 (executor + router)
  • Console: naeel/fission-console:v1.1
  • User namespace: fission-ffd1f598c169b0ae
  • Функции: 88 (Python), 88node (Node.js), phppp (PHP), rub (Ruby)
  • Маршруты: /f598c169b0ae/{name}
  • SSH: naeel@5.172.178.213, key ~/.ssh/naeel_vm_id_ed25519
  • Token: grep -m1 "^api_token" /home/naeel/terra/terraform/TEST_STAND/POSTGRES/terraform.tfvars | sed -E "s/^api_token = \"(.*)\"$/\1/"