# Прогресс разработки Последнее обновление: 2026-03-10 (добавлен подробный архитектурный handoff-документ для следующего агента) ## Статусы: ✅ готово | 🔄 в процессе | ⏳ не начато --- ## 2026-03-10 — Архитектурный разбор и handoff для следующего агента | # | Задача | Статус | Заметки | |---|--------|--------|---------| | 1 | GPT-5.4: Подробный разбор кода и lifecycle issues | ✅ | `doc/architecture/agent-handoff-2026-03-10.md` — детальный code review, event model problems, invocation history gap, приоритеты | | 2 | Claude Sonnet 4.6: Review + security roadmap | ✅ | `doc/architecture/sonnet-review-of-gpt-analysis.md` — где GPT-5.4 прав, что пропустил (gVisor, LLM validation, NetworkPolicy), production security roadmap | --- ## v1 — Базовый сервис ### Код | # | Компонент | Статус | Заметки | |---|-----------|--------|---------| | 1 | Структура проекта, operator-sdk init | ✅ | module: gitea-naeel.giteak8s.services.ngcloud.ru/naeel/sless | | 2 | CRD types: Function, Trigger | ✅ | api/v1alpha1/, zz_generated.deepcopy.go | | 3 | internal/config | ✅ | config.go, Load() из env vars, добавлены IngressHost + APIToken | | 4 | Миграции PostgreSQL | ✅ | migrations/001_initial.sql — таблица invocations | | 5 | internal/storage/postgres | ✅ | store.go: SaveInvocation, ListInvocations, RunMigrations | | 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; handleDeletion удаляет Service+Ingress | | 9 | controllers/trigger_controller.go | ✅ | HTTP→Service+Ingress (fallback) или прокси через ExternalURL, Cron→CronJob, finalizer; handleTriggerDeletion удаляет Service+Ingress | | 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 — no such host → 404), handler.go (slog) | | 12 | internal/api/middleware/ | ✅ | auth.go (Bearer token), logging.go (slog) | | 13 | main.go | ✅ | operator manager + HTTP сервер параллельно, wire всех зависимостей | ### Кластер (namespace: sless) | # | Ресурс | Статус | Заметки | |---|--------|--------|---------| | 1 | namespace sless | ✅ | создан | | 2 | CRD functions.sless.kube5s.ru | ✅ | установлен из config/crd/bases/ | | 3 | CRD triggers.sless.kube5s.ru | ✅ | установлен из config/crd/bases/ | | 4 | ServiceAccount sless-operator | ✅ | deployments/k8s/rbac.yaml | | 5 | ClusterRole + ClusterRoleBinding | ✅ | deployments/k8s/rbac.yaml | | 6 | PostgreSQL Deployment + Service | ✅ | deployments/k8s/postgres.yaml, Running | | 7 | Secret postgres-secret | ✅ | в namespace sless | ### Runtime image + Upload endpoint (2026-03-07) | # | Компонент | Статус | Заметки | |---|-----------|--------|---------| | 1 | runtimes/python3.11/server.py | ✅ | HTTP wrapper :8080, loads /app/function/handler.py | | 2 | runtimes/python3.11/Dockerfile | ✅ | FROM python:3.11-slim, naeel/sless-runtime-python3.11:v0.1.0 | | 3 | Secret sless-registry-auth | ✅ | DockerHub creds для kaniko в namespace sless | | 4 | internal/api/handler/upload.go | ✅ | POST /v1/namespaces/{ns}/functions/{name}/upload | | 5 | Fix: kaniko S3 endpoint | ✅ | https:// + S3_FORCE_PATH_STYLE=true (Ceph) | | 6 | Fix: бесконечный цикл сборки | ✅ | idempotency guard через аннотацию last-built-s3key | ### E2E тест (2026-03-07) | # | Шаг | Результат | |---|-----|-----------| | 1 | Запуск оператора локально | ✅ `source hack/local.env && go run main.go` | | 2 | Создание функции hello + upload handler.zip | ✅ kaniko собрал naeel/sless-default-hello:latest | | 3 | Function phase=Ready, Deployment Running | ✅ namespace sless-fn-default | | 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)"}` via https://sless-api.kube5s.ru/fn/default/hello-node | ### Terraform провайдер (2026-03-07) | # | Компонент | Статус | Заметки | |---|-----------|--------|---------| | 1 | terraform/provider/ — независимый Go-модуль | ✅ | module: terraform-provider-sless | | 2 | internal/client/client.go | ✅ | HTTP-клиент sless API, готов к переносу в nubes | | 3 | internal/provider/provider.go | ✅ | паттерн идентичен nubes NubesProvider | | 4 | sless_function resource | ✅ | CRUD + upload zip + WaitReady (kaniko) | | 5 | sless_trigger resource | ✅ | CRUD (http/cron); Delete ждёт исчезновения CR (WaitGone, 90с) | | 6 | hack/build-and-publish.sh | ✅ | GPG-подпись + mc upload в S3 | | 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/`. ### source_dir + fix destroy cleanup (2026-03-09) | # | Компонент | Статус | Заметки | |---|-----------|--------|----------| | 1 | provider: source_dir атрибут | ✅ | zip в памяти, SHA256 автоматически; hashicorp/archive не нужен | | 2 | fix: trigger_controller handleTriggerDeletion | ✅ | удаляет Service+Ingress из sless-fn-{ns} | | 3 | fix: function_controller handleDeletion | ✅ | удаляет Service+Ingress из sless-fn-{ns} | | 4 | fix: trigger_resource.go Delete WaitGone | ✅ | polling GetTrigger до 404, таймаут 90с | | 5 | fix: invoke.go no such host → 404 | ✅ | после destroy DNS NXDOMAIN → 404 вместо 502 | | 6 | E2E тест run_terraform_examples.sh | ✅ | все 4 примера: hello-node, simple-node, simple-python, notes-python | ### Что ещё не сделано | # | Компонент | Статус | Заметки | |---|-----------|--------|---------| | 1 | terraform apply e2e — функция с postgres | ✅ | `{"invocations": [], "count": 0}` — функция подключилась к postgres.sless.svc, таблица пустая | | 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 | | 7 | upload.go: nodejs20 + package.json | ✅ | runtimeBaseImage switch, hasPackageJSON → npm install | | 8 | go.mod: direct/indirect fix | ✅ | go mod tidy — gorilla/mux, lib/pq, minio-go, k8s.io/api помечены direct | | 9 | Runtime образы: версионированные теги | ✅ | python3.11:v0.1.0, nodejs20:v0.1.0 (убираем :latest) | --- ## v2 — Расширения | # | Компонент | Статус | Заметки | |---|-----------|--------|---------| | 1 | RabbitMQ event triggers | ⏳ | | | 0 | Изоляция пользователей по namespace | ⏳ | Каждый токен → свой k8s namespace. API: GET /v1/whoami → {namespace}. Провайдер получает ns при Configure(), юзер не видит. Сейчас: хардкод "default" для демо. | | 2 | Облачный auth (nubes.ru token validation) | ⏳ | v1 — статический токен | | 3 | Метрики → Victoria Metrics | ⏳ | | | 4 | Managed PostgreSQL от провайдера | ⏳ | сейчас postgres в k8s | | 5 | Pre-warm для cron триггеров | ⏳ | TriggerSpec.PreWarmSeconds — поле есть, логика не реализована | | 11 | trigger.enabled | ✅ | enabled=false → Deployment replicas=0, in-place update через PATCH | | 12 | job.run_id | ✅ | run_id=0 → skip, run_id>0 → execute. Повторный запуск = увеличить run_id |