diff --git a/doc/decisions/log.md b/doc/decisions/log.md index 5534970..f3eb7c6 100644 --- a/doc/decisions/log.md +++ b/doc/decisions/log.md @@ -2,6 +2,59 @@ --- +## 2026-03-21 — Объединить sless_function и sless_service в единый пользовательский листинг + +### Контекст + +`/funcs/{namespace}` (web-консоль) показывал только `sless_function` ресурсы (Kind=Function). +`sless_service` ресурсы (`pg-info`, `pg-table-reader`, `pg-table-writer`) были скрыты — пользователь не видел часть своих развёрнутых функций. + +Первоначальный вопрос: почему `https://sless.kube5s.ru/funcs/sless-ffd1f598c169b0ae` пуст? +Ответ: там были `sless_service`, а не `sless_function` — их не рендерили. + +### Решение + +Пользователю всё равно какой тип ресурса лежит под капотом — для него это просто «функция». +Объединить оба типа в один список с визуальным маркером типа: +- `sless_function` → бейдж `job` +- `sless_service` → бейдж `always-on` + +Добавить поля `Kind` и `URL` в `fnResponse`. `fetchAndRender` теперь делает два запроса: +1. `GET /v1/namespaces/{ns}/functions` — sless_function (job-style) +2. `GET /v1/namespaces/{ns}/services` — sless_service (always-on Deployment) + +Оба списка объединяются, фильтруются и сортируются единообразно. + +### Почему НЕ делаем единый endpoint на операторе +Не усложняем оператор ради UI. Агрегацию делает funcs-service — он уже служит «фасадом» между браузером и оператором. Оператор остаётся строго CRUD. + +### Имплементация +- `services/funcs/main.go`: `svcResponse`, объединение в `fetchAndRender` +- `services/funcs/index.html`: `badge-kind-service/function`, счётчик типов +- Коммит `683d728`, funcs-service `v0.2.1` + +--- + +## 2026-03-21 — Добавить /services/{name}/source в оператор, не расширять proxySourceGet на API gateway + +### Контекст + +После объединения листинга возникла 404 при просмотре кода `sless_service` через web-консоль. +`proxySourceGet` передавал запрос на `/functions/{fn}/source`, но оператор маршрута `/services/{fn}/source` не имел. + +### Варианты +1. В операторе: один универсальный `/resources/{fn}/source?type=service|function` — усложнит роутинг, нарушит REST-конвенцию. +2. В funcs-service: разветвлять URL по `kind` — но тогда funcs-service должен знать о внутренней топологии. +3. **Выбранный**: добавить отдельный `GET /v1/namespaces/{ns}/services/{name}/source` в оператор — симметрично с `/functions/{name}/source`. funcs-service передаёт `?kind` параметр. + +### Почему так +- Симметричность `/functions/…/source` и `/services/…/source` — интуитивный REST. +- Никаких изменений в роутинге оператора — просто новый endpoint с той же логикой. +- `GetServiceSource` — буквально `GetSource` с `Service` CRD вместо `Function`. 30 строк кода. +- Коммит `50f2456`, оператор `v0.1.45` + +--- + ## 2026-03-20 — Merge: убрать sless_function как обязательный prerequisite для sless_job ### Контекст diff --git a/doc/errors/log.md b/doc/errors/log.md index a73acb3..1b0af1a 100644 --- a/doc/errors/log.md +++ b/doc/errors/log.md @@ -4,6 +4,97 @@ --- +## 2026-03-21 — Баг: DELETE несуществующего ресурса → HTTP 204 вместо 404 + +### Симптом +``` +DELETE /v1/namespaces/sless-xxx/functions/not-exists +→ HTTP 204 (пустой ответ, как будто удаление прошло успешно) +``` +Аналогично для services, triggers, jobs. + +### Причина +Все четыре `Delete*` хендлера при `errors.IsNotFound(err)` выполняли `w.WriteHeader(http.StatusNoContent)` вместо возврата 404. + +```go +// БЫЛО (ошибочно): +if errors.IsNotFound(err) { + w.WriteHeader(http.StatusNoContent) + return +} + +// СТАЛО (правильно): +if errors.IsNotFound(err) { + writeJSON(w, http.StatusNotFound, errResp("function not found")) + return +} +``` + +### Затронутые файлы +- `internal/api/handler/functions.go` — `DeleteFunction` +- `internal/api/handler/services.go` — `DeleteService` +- `internal/api/handler/triggers.go` — `DeleteTrigger` +- `internal/api/handler/jobs.go` — `DeleteJob` + +### Фикс +Коммит `e8d0d78`, оператор `v0.1.44`. + +--- + +## 2026-03-21 — Баг: funcs-service pod в ImagePullBackOff после обновления образа + +### Симптом +После `kubectl set image deployment/sless-funcs-service funcs=pearlharbor…/sless-funcs-service:v0.2.1`: +``` +Events: + Warning Failed kubelet Failed to pull image "...v0.2.1": + authorization failed: no basic auth credentials +``` +Новый под застрял в `ImagePullBackOff`. Старый под продолжал работать с v0.2.0 (без services). + +### Причина +`deployments/k8s/funcs-service.yaml` не содержал `imagePullSecrets`, а образ находится в приватном реестре Harbor (`pearlharbor.registryk8s.services.ngcloud.ru`). +Старый под (v0.2.0) работал с другой нодой, где уже был cached образ с credentials. + +### Фикс +```yaml +spec: + imagePullSecrets: + - name: sless-registry-auth + containers: + - name: funcs + image: pearlharbor.registryk8s.services.ngcloud.ru/naeel/sless-funcs-service:v0.2.2 +``` +Коммит `09b3588`. Правило: все образы из pearlharbor требуют `imagePullSecrets: sless-registry-auth`. + +--- + +## 2026-03-21 — Баг: /funcs/{ns}/source/{fn} → 404 для sless_service ресурсов + +### Симптом +Клик на карточку `pg-info` (sless_service) в web-консоли → ошибка 404 при загрузке кода. +``` +GET /funcs/sless-ffd1f598c169b0ae/source/pg-info → HTTP 404 +{"error":"function not found"} +``` + +### Причина +`proxySourceGet` в funcs-service всегда обращался к оператору по пути: +``` +/v1/namespaces/{ns}/functions/{fn}/source +``` +`pg-info` — это `sless_service` (Kind=Service), а не `sless_function`. У оператора не было эндпоинта `/services/{name}/source`. + +### Фикс +1. **Оператор** (`internal/api/handler/source.go`): добавлен `GetServiceSource` — делает то же что `GetSource`, но читает `Service` CRD вместо `Function`. +2. **Оператор** (`internal/api/router.go`): зарегистрирован маршрут `GET /v1/namespaces/{ns}/services/{name}/source`. +3. **funcs-service** (`services/funcs/main.go`): `proxySourceGet` принимает параметр `kind`; при `kind=service` обращается к `/services/…/source`. +4. **funcs-service** (`services/funcs/index.html`): `loadSource(body, ns, fnName, fnKind)` добавляет `?kind=service` в fetch URL для сервисов. + +Коммит `50f2456`, оператор `v0.1.45`, funcs-service `v0.2.2`. + +--- + ## 2026-03-20 — Баг: неверный hostname в api_endpoint провайдера nubes ### Симптом diff --git a/doc/progress.md b/doc/progress.md index baf5f6d..83b845a 100644 --- a/doc/progress.md +++ b/doc/progress.md @@ -1,10 +1,64 @@ # Прогресс разработки -Последнее обновление: 2026-03-21 (deploy v0.1.43, terraform apply POSTGRES — Succeeded) +Последнее обновление: 2026-03-21 (operator v0.1.45, funcs-service v0.2.2 — source для sless_service) --- -## 2026-03-21 — Deploy + E2E тест: sless_job self-contained (POSTGRES пример) +## 2026-03-21 — Сессия 2: тестирование API, баги, web-консоль, source для services + +### Что сделано + +| # | Компонент | Версия | Результат | +|---|-----------|--------|-----------| +| 1 | Полный цикл CRUD-тестирования | — | ✅ functions / triggers / services / jobs — все операции проверены | +| 2 | Фикс: DELETE несуществующего ресурса → 204 вместо 404 | operator v0.1.44 | ✅ исправлено в 4 хендлерах | +| 3 | funcs-console: объединить functions + services в единый листинг | funcs-service v0.2.1 | ✅ сервисы отображаются с бейджем `always-on` | +| 4 | Фикс: imagePullSecrets отсутствовал в funcs-service.yaml | manif. fix | ✅ образ v0.2.1 успешно стягивается на всех нодах | +| 5 | Фикс: `/funcs/{ns}/source/{fn}` → 404 для sless_service | operator v0.1.45 + funcs-service v0.2.2 | ✅ новый endpoint `/services/{name}/source` | + +### Найденные и исправленные баги + +| Баг | Причина | Фикс | Коммит | +|-----|---------|------|--------| +| `DELETE /functions/not-exists` → HTTP 204 | Все 4 Delete-хендлера возвращали `204 No Content` при `IsNotFound` | `writeJSON(w, 404, errResp("... not found"))` в functions.go / services.go / triggers.go / jobs.go | `e8d0d78` | +| funcs-service pod в `ImagePullBackOff` после обновления образа | `deployments/k8s/funcs-service.yaml` не содержал `imagePullSecrets` | Добавить `imagePullSecrets: [{name: sless-registry-auth}]` + полный образ с pearlharbor prefix | `09b3588` | +| `/funcs/{ns}/source/{fn}` → 404 для sless_service (pg-info, pg-table-reader, etc.) | `proxySourceGet` всегда обращался к `/functions/{fn}/source`; у оператора не было эндпоинта `/services/{name}/source` | Добавить `GetServiceSource` в source.go + роут в router.go; в funcs-service передавать `?kind=service` | `50f2456` | + +### Новые ресурсы / изменения кода + +| Файл | Изменение | +|------|-----------| +| `internal/api/handler/functions.go` + `services.go` + `triggers.go` + `jobs.go` | `Delete*`: `IsNotFound` → HTTP 404 вместо 204 | +| `internal/api/handler/source.go` | Новый хендлер `GetServiceSource` — аналог `GetSource` для Service CRD | +| `internal/api/router.go` | Новый маршрут `GET /v1/namespaces/{ns}/services/{name}/source` | +| `services/funcs/main.go` | `fnResponse` + поля `Kind/URL`; новая структура `svcResponse`; `fetchAndRender` объединяет functions + services; `proxySourceGet` поддерживает `?kind=service` | +| `services/funcs/index.html` | Бейджи `badge-kind-service` / `badge-kind-function`; `loadSource(…, fnKind)` передаёт `?kind=service`; счётчик "Функций N \| Сервисов N \| Всего N" | +| `deployments/k8s/funcs-service.yaml` | Добавлен `imagePullSecrets: sless-registry-auth`; образ → `pearlharbor…/sless-funcs-service:v0.2.2` | +| `deployments/k8s/operator.yaml` | Образ → `pearlharbor…/sless-operator:v0.1.45` | + +### Результаты тестирования (ключевые) +- CREATE 3 функций (nodejs20 / python3.11 / go1.23) → 201 ✅ +- UPDATE memory / timeout / env_vars → 200 ✅ +- DELETE существующей → 204; DELETE несуществующей → 404 ✅ (после фикса) +- Дубликат → 409; bad input → 400; no auth → 401 ✅ +- Триггеры: CREATE http+cron / PATCH enable-disable / DELETE ✅ +- Services CRUD ✅; Jobs API ✅ +- `/funcs/sless-ffd1f598c169b0ae` показывает 5 ресурсов: 3 sless_service + 2 sless_function ✅ +- `source` для function → 200, для service → 200 ✅ + +### Коммиты сессии (feat/function-service-split) +- `e8d0d78` fix(api): DELETE несуществующего ресурса — 404 вместо 204 (function/service/trigger/job) +- `683d728` feat(funcs-console): показывать sless_service вместе с функциями — единый листинг +- `09b3588` fix(deploy): imagePullSecrets + образ v0.2.1 в funcs-service.yaml +- `50f2456` fix(source): add /services/{name}/source endpoint; fix 404 for service code view in funcs-console + +### Задеплоено +- **Оператор**: `pearlharbor.registryk8s.services.ngcloud.ru/naeel/sless-operator:v0.1.45` — rollout ✅ +- **funcs-service**: `pearlharbor.registryk8s.services.ngcloud.ru/naeel/sless-funcs-service:v0.2.2` — rollout ✅ + +--- + +## 2026-03-21 — Сессия 1: Deploy + E2E тест: sless_job self-contained (POSTGRES пример) ### Что сделано