diff --git a/doc/decisions/log.md b/doc/decisions/log.md index 3f22e59..0b6c57f 100644 --- a/doc/decisions/log.md +++ b/doc/decisions/log.md @@ -130,3 +130,32 @@ - `runtimes/nodejs20/server.js` — `http.createServer`, динамический `require(HANDLER_PATH)` - Зависимости через `package.json` → `npm install --omit=dev` (аналог `requirements.txt` → `pip install`) - `entrypoint` в HCL игнорируется для Node.js (всегда `handler.js` + `exports.handle`) — TODO: поддержать произвольный entrypoint в v1.1 + +--- + +## 2026-03-07 — FunctionJob CRD: одноразовые запуски функций + +**Решение:** Добавлен `FunctionJob` CRD для одноразового запуска функции с произвольным JSON-событием. +**Причина:** Нужны sync-вызовы без HTTP — для батч-обработки, миграций, крон-задач через Terraform. +**Реализация:** +- `api/v1alpha1/job_types.go` — CRD: `FunctionRef`, `EventJSON`, phases: Pending/Running/Succeeded/Failed +- `controllers/functionjob_controller.go` — создаёт k8s Job, ждёт завершения, синхронизирует статус +- `internal/api/handler/jobs.go` — REST: CreateJob/GetJob/DeleteJob +- `terraform/provider/internal/resources/job_resource.go` — ресурс `sless_job` +- Настраиваемые таймауты: `build_timeout_sec` (sless_function), `wait_timeout_sec` (sless_job) + +--- + +## 2026-03-07 — Прокси /fn/ вместо wildcard Ingress + +**Проблема:** wildcard DNS `*.fn.kube5s.ru` недоступен (провайдер не позволяет). +**Решение:** HTTP-прокси внутри оператора — маршрут `GET|POST|... /fn/{namespace}/{name}` на `sless-api.kube5s.ru`. +**Реализация:** +- `internal/api/handler/invoke.go` — форвардит запрос к `http://{fn}.sless-fn-{ns}.svc.cluster.local:8080` +- `internal/api/router.go` — `/fn/` регистрируется **до** auth middleware, публично доступен; `/v1/` — по-прежнему с Bearer токеном (gorilla `Use()`) +- `internal/config/config.go` — новое поле `ExternalURL` (env `EXTERNAL_URL`) +- `controllers/trigger_controller.go` — если `ExternalURL` задан, `Trigger.Status.URL = ExternalURL/fn/{ns}/{name}`; иначе fallback: создаёт Ingress с поддоменом (прежнее поведение) +- `deployments/k8s/operator.yaml` — `EXTERNAL_URL=https://sless-api.kube5s.ru` + +**URL функции:** `https://sless-api.kube5s.ru/fn/{namespace}/{name}` +**E2E:** `curl https://sless-api.kube5s.ru/fn/default/hello-node` → `{"message":"Hello, Naeel! (nodejs20)"}` diff --git a/doc/progress.md b/doc/progress.md index a800718..d5a9da5 100644 --- a/doc/progress.md +++ b/doc/progress.md @@ -1,6 +1,6 @@ # Прогресс разработки -Последнее обновление: 2026-03-07 +Последнее обновление: 2026-03-07 (operator v0.1.5, provider v0.1.3) ## Статусы: ✅ готово | 🔄 в процессе | ⏳ не начато @@ -20,9 +20,9 @@ | 6 | internal/storage/s3 | ✅ | client.go: Upload, Download, Delete, EnsureBucket (Ceph S3) | | 7 | internal/builder | ✅ | builder.go: kaniko Jobs для сборки образов функций | | 8 | controllers/function_controller.go | ✅ | Pending→Building(kaniko)→Ready/Failed, Deployment, finalizer | -| 9 | controllers/trigger_controller.go | ✅ | HTTP→Service+Ingress, Cron→CronJob, finalizer | -| 10 | internal/api/router.go | ✅ | gorilla/mux, /v1/namespaces/{ns}/... | -| 11 | internal/api/handler/ | ✅ | functions.go, triggers.go, invocations.go, handler.go (slog) | +| 9 | controllers/trigger_controller.go | ✅ | HTTP→Service+Ingress (fallback) или прокси через ExternalURL, Cron→CronJob, finalizer | +| 10 | internal/api/router.go | ✅ | gorilla/mux, /v1/namespaces/{ns}/... (auth), /fn/{ns}/{name} (публичный прокси) | +| 11 | internal/api/handler/ | ✅ | functions.go, triggers.go, invocations.go, invoke.go (proxy), handler.go (slog) | | 12 | internal/api/middleware/ | ✅ | auth.go (Bearer token), logging.go (slog) | | 13 | main.go | ✅ | operator manager + HTTP сервер параллельно, wire всех зависимостей | @@ -59,7 +59,7 @@ | 4 | `GET /health` | ✅ `{"status": "ok"}` | | 5 | `POST / {"name":"Naeel"}` | ✅ `{"message": "Hello, Naeel!"}` | | 6 | terraform apply (pg-query python3.11) | ✅ `{"invocations": [], "count": 0}` через https://sless-api.kube5s.ru | -| 7 | hello-node (nodejs20) E2E | ✅ `{"message": "Hello, Naeel! (nodejs20)"}` |} +| 7 | hello-node (nodejs20) E2E | ✅ | `{"message": "Hello, Naeel! (nodejs20)"}` via https://sless-api.kube5s.ru/fn/default/hello-node | ### Terraform провайдер (2026-03-07) @@ -71,8 +71,10 @@ | 4 | sless_function resource | ✅ | CRUD + upload zip + WaitReady (kaniko) | | 5 | sless_trigger resource | ✅ | CRUD (http/cron) | | 6 | hack/build-and-publish.sh | ✅ | GPG-подпись + mc upload в S3 | -| 7 | Публикация в terra.k8c.ru | ✅ | v0.1.0, key CB3A0DF161ECC416 | -| 8 | terraform init | ✅ | Installed terra.k8c.ru/naeel/sless v0.1.0 | +| 7 | Публикация в terra.k8c.ru | ✅ | v0.1.3, key CB3A0DF161ECC416 | +| 8 | terraform init | ✅ | Installed terra.k8c.ru/naeel/sless v0.1.3 | +| 9 | sless_job resource | ✅ | одноразовые запуски функции через FunctionJob CRD | +| 10 | build_timeout_sec / wait_timeout_sec | ✅ | настраиваемые таймауты в sless_function и sless_job | **Примечание:** Код провайдера писался с прицелом на перенос в nubes провайдер. `internal/client/` → `internal/core/` nubes, ресурсы → `internal/resources_gen/`. @@ -82,8 +84,8 @@ | # | Компонент | Статус | Заметки | |---|-----------|--------|---------| | 1 | terraform apply e2e — функция с postgres | ✅ | `{"invocations": [], "count": 0}` — функция подключилась к postgres.sless.svc, таблица пустая | -| 2 | HTTP trigger e2e тест | ⏳ | Service+Ingress через TriggerController | -| 3 | deployments/k8s/operator.yaml | ✅ | Deployment+Service+Ingress, naeel/sless-operator:v0.1.2, Running | +| 2 | HTTP trigger e2e тест | ✅ | прокси /fn/ через sless-api, без wildcard DNS | +| 3 | deployments/k8s/operator.yaml | ✅ | Deployment+Service+Ingress, naeel/sless-operator:v0.1.5, Running | | 4 | Внешний доступ к API оператора | ✅ | https://sless-api.kube5s.ru → HTTP/2 200, TLS cert OK | | 5 | DNS запись sless-api.kube5s.ru | ✅ | A → 5.172.178.182, TTL 3600, zone kube5s.ru | | 6 | nodejs20 runtime | ✅ | runtimes/nodejs20/server.js + Dockerfile, naeel/sless-runtime-nodejs20:v0.1.0 |