From 8ac8428a76b3c354ae33ae26b251c32568f19eec Mon Sep 17 00:00:00 2001 From: Naeel Date: Wed, 15 Apr 2026 14:43:58 +0300 Subject: [PATCH] docs: record strict cleanup to 6 verified functions --- doc/progress.md | 140 +++++++++++++++++++++++ doc/thinking/2026-04-15.md | 221 +++++++++++++++++++++++++++++++++++++ 2 files changed, 361 insertions(+) diff --git a/doc/progress.md b/doc/progress.md index 7a25a53..f3ec9b9 100644 --- a/doc/progress.md +++ b/doc/progress.md @@ -258,6 +258,30 @@ #### Правила репозитория Создан `.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-конфликты) @@ -326,3 +350,119 @@ ### Статус `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` + - обновлен `` на `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`. diff --git a/doc/thinking/2026-04-15.md b/doc/thinking/2026-04-15.md index c4daa5b..0b9cfc3 100644 --- a/doc/thinking/2026-04-15.md +++ b/doc/thinking/2026-04-15.md @@ -147,3 +147,224 @@ User → POST /console/api/functions/NAME/invoke Причина: VPN может быть активен локально, вызывая сбои при прямом выполнении команд. Монтирование sshfs делает локальное редактирование файлов эквивалентным редактированию на ВМ. + +--- + +## Сессия: JS invoke timeouts в UI (root cause + fix) + +### Симптом + +- Все JS invoke через UI (`/console/api/functions/{name}/invoke`) падали по timeout. +- В router логах: `roundtripper timeout (60s)`/`error sending request to function`. +- В executor логах specialization для node окружения могла проходить, но ответ функции не возвращался. + +### Ключевые находки + +1. Node runtime работал через `POST /v2/specialize`. +2. При `functionName=main` runtime строил путь загрузки как: + - `/userfunc/deployarchive/main` +3. В реальном поде `/userfunc/deployarchive` был **файлом** (literal payload), а не директорией. +4. После перевода на пустой entrypoint (`functionName=""`) specialization стала успешной (`202`, `user code loaded`), + но запросы всё равно зависали. +5. Прямая проверка контейнера показала второй контрактный нюанс node runtime: + - пользовательская функция должна возвращать объект формата + `{ status, body, headers? }` + - возврат простой строки приводил к зависанию ответа (callback не отправлял HTTP response). + +### Принятые изменения + +- `nodejs-acc` закреплен на `ghcr.io/fission/node-env:1.32.5`. +- Для JS функций (`fn-js-acc`, `fn-js-direct`, тестовые `jsm1..jsm4`): + - выставлен пустой entrypoint (`functionName=""`) + - код приведен к контракту Node runtime: + - `module.exports = async function(context) { return { status: 200, body: "..." }; }` +- Для основных JS trigger включены методы `GET` и `POST`. + +### Проверка + +- UI invoke: + - `fn-js-acc` -> `status=200`, `response_raw=hello-js-ok` + - `fn-js-direct` -> `status=200`, `response_raw=hello-js-ok` +- Прямые GET через роутер: + - `/js-acc` -> 200 + - `/js-direct` -> 200 +- Тестовые `jsm1..jsm4` после унификации кода -> 200 через UI invoke. + +### Вывод + +Проблема была не в UI-рендеринге и не в одном конкретном trigger, а в несовпадении контракта Node runtime: +- entrypoint/path specialization +- shape возвращаемого значения функции. + +--- + +## Сессия: Финальный fix `fn-go-acc` (Go runtime specialization) + +### Симптом + +- `fn-go-acc` выдавал timeout на invoke через console/router. + +### Диагностика + +1. На исходной конфигурации в executor логах: + - `plugin.Open("/userfunc/deployarchive/main.go"): invalid ELF header`. +2. Это означало, что runtime ожидал plugin-артефакт, но в package deployment лежал исходник `main.go`. +3. После первой попытки собрать plugin локальным `go1.26.1` ошибка `invalid ELF` ушла, но появился новый фейл specialization: + - `Post "http://127.0.0.1:8888/v2/specialize": EOF`. +4. Вывод: plugin собран несовместимой версией Go относительно runtime. + +### Решение + +- Сборка plugin выполнена в `ghcr.io/fission/go-builder` (Go 1.25.6), то есть тем же toolchain, что у Fission environment builder: + - `GO111MODULE=off /usr/local/go/bin/go build -buildmode=plugin -o main.so ./main.go` + - упаковка `main.so` в `deploy.zip`. +- Обновление функции через 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` и без `EOF`. + +### Контрольная матрица маршрутов + +- `/auto/ok` -> 200 +- `/js-acc` -> 200 +- `/js-direct` -> 200 +- `/go-acc` -> 200 + +### Практический вывод + +Для go-env в этом кластере критично соблюдать контракт runtime: +1. deploy-пакет должен содержать именно plugin (`.so`), а не исходник. +2. plugin должен быть собран совместимой версией Go (через `ghcr.io/fission/go-builder`). + +--- + +## Сессия: `Edit Code` для `fn-go-acc` пустой + +### Симптом + +- В UI (`GET /console/api/functions/fn-go-acc`) поле `code` было пустым. + +### Почему так произошло + +- После фикса runtime функция была переведена на deploy-архив plugin (`main.so`). +- Package имел вид: + - `spec.deployment.type=url` + - `spec.deployment.url=...` + - без `spec.deployment.literal` +- Backend в `handleGetFunction` извлекал код только из `spec.deployment.literal`, поэтому для URL-пакета отдавал пустую строку. + +### Что изменено + +- В backend добавлен `extractPackageSourceCode(...)` с fallback-приоритетом: + 1. `spec.source.literal` + 2. `spec.deployment.literal` + 3. `spec.source.url` + 4. `spec.deployment.url` +- Добавлена загрузка URL-архива через `fetchPackageArchive(...)` и декодирование через `decodeArchiveBytesToSource(...)`. +- Обновлен unit-тестами сценарий, где `deployment.literal` отсутствует, но есть `source.literal`. + +### Операционные шаги + +- Собран и задеплоен `naeel/fission-console:v0.2.6`. +- Для текущей `fn-go-acc` дополнительно обновлен `sourcearchive` (`main.go`), чтобы исходник гарантированно отображался в Edit Code. + +### Результат + +- `GET /console/api/functions/fn-go-acc` теперь возвращает непустой Go source в `code`. +- Вызов `/go-acc` остается рабочим (`hello-go-ok`, HTTP 200). + +--- + +## Сессия: Проверка TLS + branding NUBES + верификация `tf-neg-syntax-fn` + +### TLS + +- Проверен доступ к console: + - `http://.../console/` -> `308` redirect на HTTPS + - `https://.../console/` -> `200` +- Ingress конфиг содержит корректный TLS блок и принудительный SSL redirect. +- Вывод: endpoint защищен TLS, «незащищенного HTTP-доступа» нет. + +### Брендинг NUBES + +- В `console/ui/index.html` добавлены: + - `<title>NUBES Fission Console` + - favicon (inline SVG) + - navbar brand block с `NUBES` / `FISSION CONSOLE`. +- Обновлен образ до `naeel/fission-console:v0.2.9`. + +### `tf-neg-syntax-fn` — почему timeout вместо прямого SyntaxError + +- Функция содержит заведомо битый Python (`def main(:`), confirmed через `GET /console/api/functions/tf-neg-syntax-fn`. +- На runtime это роняет specialization (`500`), после чего executor ретраит. +- Поэтому router/console не получает «чистый traceback» сразу из runtime API и видит timeout/ошибку specialization. +- Для UX введен fail-fast и явная ошибка в console invoke: + - `timeout after 20s: function specialization likely failed (for example, syntax error)`. + +--- + +## Сессия: "Не защищено красным" — экстренное лечение + +### Наблюдение + +- Сертификат endpoint сам по себе валидный (Let's Encrypt, CN/SAN = `fission.kube5s.ru`). +- Но на том же host были два ingress с разной TLS-конфигурацией: + - `fission-console` с TLS + - `fission-router` без TLS + +### Действие + +- Патч `fission-router`: + - добавлен `spec.tls` с `secretName: fission-tls` + - добавлен `force-ssl-redirect=true` + +### Результат + +- HTTP на роутер-пути дает 308 -> HTTPS +- HTTPS на console стабильно 200 +- Конфигурация host выровнена: теперь и console, и router на одном сертификате. + +--- + +## Сессия: Строгая чистка до "только точно рабочие и видимые" + +### Запрос + +- Оставить только функции, которые в UI/Console: + - показывают исходник (`code` не пустой) + - реально вызываются (`invoke.status == 200`) + +### Что произошло + +- Выполнен массовый cleanup с keep-list. +- По логу cleanup выявилась ошибка jsonpath в пост-обработке orphan-пакетов: + - использовалось `{n}` вместо `{"\\n"}` + - это ломало шаг удаления orphan-объектов после основного удаления. +- Основное удаление функций при этом сработало корректно. + +### Проверка после cleanup + +- Текущее состояние: + - functions: 6 + - httptriggers: 6 + - packages: 6 +- Остались только: + - `auth-test2` + - `fn-js-direct` + - `fn-js-acc` + - `hello` + - `tf-auto-ok-fn` + - `tf-stress-fast-fn` +- Для каждой функции через Console API подтверждено: + - `code=OK` + - `invoke=OK` + +### Вывод + +- Финальный набор теперь соответствует строгому критерию "однозначно работает и показывается".