“Naeel”
94ed02f631
feat: provider v0.1.10 — source_dir (zip внутри провайдера), убран archive провайдер из всех примеров
2026-03-09 17:45:45 +04:00
“Naeel”
addce19cfe
docs: examples/README.md — порядок simple-first, без токена, без pg-query
2026-03-09 15:57:29 +04:00
“Naeel”
a309c72146
feat: provider v0.1.9 — namespace hardcoded in client, removed from provider schema and all examples
2026-03-09 15:27:55 +04:00
“Naeel”
d0ef085705
feat: provider v0.1.9 — namespace removed from resources, moved to provider block
2026-03-09 15:12:07 +04:00
“Naeel”
c4837b193e
feat: operator v0.1.16 — job stdout -> status.Message (feature B)
...
- FunctionJobReconciler: added KubeClient field (kubernetes.Interface)
- getJobPodOutput(): reads pod logs via typed client after job succeeds
- main.go: inject kubernetes.NewForConfigOrDie into FunctionJobReconciler
- rbac.yaml: add pods/pods/log get/list/watch permissions
- examples/simple-python/: job->function chain demo (Python)
- examples/simple-node/: job->function chain demo (Node.js)
sless_job.X.message now contains the return value of the function
2026-03-09 14:50:06 +04:00
“Naeel”
d075a7c0f6
feat: outputs — статус init-джобов для пользователя без kubectl
2026-03-09 14:09:55 +04:00
“Naeel”
5263843852
fix: operator v0.1.15 — обновлять Env при изменении функции
...
function_controller.go: при update deployment обновлять не только Image,
но и Env целиком. Без этого изменение entrypoint или env_vars не применялось
в уже существующем Deployment — поды продолжали стартовать со старым
SLESS_ENTRYPOINT и падали с FileNotFoundError.
2026-03-09 10:26:54 +04:00
“Naeel”
662710713e
refactor: уникальные имена функций-обработчиков
...
handle() → run_sql() (sql_runner.py, entrypoint: sql_runner.run_sql)
handle() → crud() (notes_crud.py, entrypoint: notes_crud.crud)
handle() → list_notes() (notes_list.py, entrypoint: notes_list.list_notes)
2026-03-09 10:14:36 +04:00
“Naeel”
9a48a6fcec
refactor: notes-python — описательные имена файлов/ресурсов + комментарии
...
Python файлы:
- handler.py → sql_runner.py (entrypoint: sql_runner.handle)
- handler.py → notes_crud.py (entrypoint: notes_crud.handle)
- handler.py → notes_list.py (entrypoint: notes_list.handle)
TF ресурсы переименованы:
- sless_function.notes → sless_function.notes_crud
- sless_trigger.notes_http → sless_trigger.notes_crud_http
- sless_job.create_table → sless_job.notes_table_init
- sless_job.create_index → sless_job.notes_index_init
- archive_file.notes → archive_file.notes_crud_zip
- archive_file.sql_runner → archive_file.sql_runner_zip
- archive_file.notes_list → archive_file.notes_list_zip
Добавлены подробные комментарии во все .tf файлы
2026-03-09 10:10:43 +04:00
“Naeel”
42387163c0
fix: provider v0.1.8 — wait for trigger URL after create
...
trigger_resource.go: after CreateTrigger, if URL is empty (HTTP trigger),
retry GetTrigger every 2s up to 30s until controller sets status.URL.
Without this, URL in terraform state was always empty after apply.
2026-03-09 09:58:37 +04:00
“Naeel”
b90b1bd7a6
feat: notes-python CRUD example + runtime path/query forwarding
...
- invoke.go: forward sub-path and query string to function pods
- server.js v0.1.2: add _path, _query, _method to event
- server.py v0.1.1: add _path, _query, _method to event
- upload.go: bump runtime versions (nodejs20:v0.1.2, python3.11:v0.1.1)
- examples/notes-python: CRUD notes via sub-path routing
- sql-runner: generic SQL executor for DDL jobs
- notes: CRUD router (/add, /update, /delete)
- notes-list: SELECT all notes
- init.tf: create TABLE + INDEX on apply
2026-03-09 09:51:56 +04:00
“Naeel”
360f136989
refactor: pg-query — ресурсы вынесены в pg-query.tf, main.tf только провайдеры
2026-03-09 09:11:31 +04:00
“Naeel”
dabb290b7c
refactor: pg-query — code/ исходники, dist/ zip, archive_file datasource
2026-03-09 09:07:57 +04:00
“Naeel”
593bc3b2ad
refactor: hello-node — zip-файлы в dist/, исходники остаются в code/
2026-03-09 09:03:00 +04:00
“Naeel”
00a350e24b
fix: pg-query — filesha256(handler.py) вместо filemd5(handler.zip), версия провайдера 0.1.7
2026-03-09 08:56:19 +04:00
“Naeel”
489da2c0bd
fix: API validation + Terraform plan-time validators
...
API (operator v0.1.13):
- functions.go: добавлена валидация entrypoint (не пустой) и
memory_mb (1-4096). Фиксирует БАГ-1/2/4 из негативных тестов.
- triggers.go: добавлена валидация type (только 'http'/'cron').
Фиксирует БАГ-3 (неверное сообщение об ошибке).
Провайдер (v0.1.7):
- Добавлен пакет terraform-plugin-framework-validators v0.19.0
- function_resource: runtime OneOf, memory_mb 1-4096, timeout_sec 1-900
- trigger_resource: type OneOf(http, cron)
- job_resource: run_id AtLeast(0)
- examples/main.tf: обновлена версия до ~> 0.1.7
doc/errors/log.md: задокументированы исправления и результаты повторных тестов
2026-03-09 08:52:13 +04:00
“Naeel”
a77ac02e1e
fix: откат 409-fallback из клиента провайдера (provider v0.1.6 не опубликован с изменениями)
...
- terraform/provider/internal/client/client.go: откат 409 fallback для
CreateFunction, CreateTrigger, CreateJob — import не нужен в данном провайдере,
409 должен быть ошибкой
- examples/hello-node/main.tf: версия провайдера ~> 0.1.6 (опубликована
без изменений клиента — только исходная версия кода)
- examples/hello-node/job.tf: run_id=9, numbers=[100,200,300]
Тесты пройдены: plan(no-changes), state-rm+apply, code update, run_id++, destroy+apply
2026-03-09 08:17:17 +04:00
“Naeel”
b1f98021e9
fix: уникальный image tag per build вместо :latest (operator v0.1.12)
...
- internal/builder/builder.go: ImageRef() теперь использует sha256(s3Key)[:12]
как тег образа вместо :latest
Пример: naeel/sless-default-hello-http:d431de61e2c9
- controllers/function_controller.go: убран хак с restartedAt аннотацией —
больше не нужен, новый тег = kubelet всегда пул-ит новый образ
- deployments/k8s/operator.yaml: обновлён до v0.1.12
- doc/progress.md: версия обновлена
Преимущества уникального тега:
- imagePullPolicy: IfNotPresent работает корректно
- Rollback к предыдущей версии возможен (теги не перезаписываются)
- Нет race condition при параллельных сборках
2026-03-08 21:05:35 +04:00
“Naeel”
fa3cd9f691
fix: rollout restart после kaniko rebuild (operator v0.1.11)
...
- controllers/function_controller.go: в ensureDeployment добавить аннотацию
kubectl.kubernetes.io/restartedAt = fn.Status.LastBuiltAt при обновлении
существующего Deployment — принудительный rolling restart после каждой сборки
- deployments/k8s/operator.yaml: образ обновлён до v0.1.11
- doc/errors/log.md: задокументирована причина и решение
- doc/decisions/log.md: добавлено правило restartedAt + :latest
- doc/progress.md: версия обновлена до v0.1.11
Причина бага: imagePullPolicy=IfNotPresent + :latest — kubelet кешировал
старый образ, pod не рестартовал после успешного kaniko build.
2026-03-08 20:55:47 +04:00
“Naeel”
2180c68e01
docs: обновление doc/ по итогам сессии 2026-03-08
2026-03-08 20:36:16 +04:00
“Naeel”
67914155b9
fix: убрать UseStateForUnknown с image_ref, provider v0.1.5
2026-03-08 20:34:00 +04:00
“Naeel”
953889db5a
config: REGISTRY_HOST переключён с Harbor на DockerHub (naeel)
2026-03-08 20:18:59 +04:00
“Naeel”
a58d3b9af5
fix: FunctionJob зависал в Running — добавлен RequeueAfter polling
2026-03-08 12:13:15 +04:00
“Naeel”
df98991b3a
fix: imagePullSecrets, SLESS_ENTRYPOINT, registry secret propagation
...
- function_controller: добавить RegistrySecret + OperatorNamespace, копировать
sless-registry-auth в sless-fn-<ns>, выставлять imagePullSecrets в Deployment,
также обновлять imagePullSecrets при reconcile
- functionjob_controller: fnEnvVars включает SLESS_ENTRYPOINT, runner читает его
- server.js + server.py: читать SLESS_ENTRYPOINT вместо hardcoded handler.js/py
- rbac.yaml: добавить права на secrets
- operator.yaml: v0.1.8
- main.go: передать RegistrySecret + OperatorNamespace в FunctionReconciler
2026-03-08 11:15:48 +04:00
“Naeel”
a231e0c8c4
feat: trigger.enabled + job.run_id lifecycle control (operator v0.1.6, provider v0.1.4)
...
- TriggerSpec.Enabled bool (default=true): enabled=false масштабирует Deployment до 0
- FunctionJobSpec.RunID int64 (default=0): run_id=0 = skip, >0 = run
- API: PATCH /v1/namespaces/{ns}/triggers/{name} (UpdateTrigger)
- Provider: enabled attribute (Optional, Computed, in-place update)
- Provider: run_id attribute (Optional, Computed, default=0, RequiresReplace)
- operator image: naeel/sless-operator:v0.1.6
- provider: terra.k8c.ru/naeel/sless v0.1.4
2026-03-08 10:10:32 +04:00
“Naeel”
19fe8e41e5
ops: switch registry from DockerHub to Harbor (pearlharbor.registryk8s.services.ngcloud.ru/sless)
2026-03-08 09:28:18 +04:00
“Naeel”
aad33b79a4
examples/hello-node: two different functions (http greeting, job sum)
2026-03-08 09:22:38 +04:00
“Naeel”
87f28d8b19
examples/hello-node: move handler to code/, split http.tf and job.tf
2026-03-08 09:14:34 +04:00
“Naeel”
a9ff7ace7f
examples: switch hello-node to sless_job (one-shot run)
2026-03-07 23:05:09 +04:00
“Naeel”
11c6faf4e9
examples: auto-zip via hashicorp/archive, remove manual zip step
2026-03-07 18:46:23 +04:00
“Naeel”
221c46e7f7
doc: обновлена документация — FunctionJob, proxy /fn/, operator v0.1.5, provider v0.1.3
2026-03-07 18:40:36 +04:00
“Naeel”
65ead2554c
feat: proxy /fn/{namespace}/{name} — обход wildcard DNS
...
Проблема: wildcard DNS *.fn.kube5s.ru недоступен.
Решение: прокси через sless-api.kube5s.ru/fn/{ns}/{name}.
- handler/invoke.go: прокси к Service функции внутри кластера
- router.go: /fn/ без auth токена, /v1/ с auth (gorilla Use())
- config.go: поле ExternalURL (EXTERNAL_URL env)
- trigger_controller.go: если ExternalURL задан — URL = ExternalURL/fn/{ns}/{fn}
иначе fallback: Ingress + поддомен (прежнее поведение)
- operator.yaml: EXTERNAL_URL=https://sless-api.kube5s.ru , image v0.1.5
Оператор v0.1.5 задеплоен.
E2E: curl https://sless-api.kube5s.ru/fn/default/hello-node → {"message":"Hello, Naeel! (nodejs20)"}
2026-03-07 18:36:03 +04:00
“Naeel”
54b7f4404e
feat: configurable timeouts for sless_function and sless_job
...
- sless_function: build_timeout_sec (optional, default 300s = 5 min)
- sless_job: wait_timeout_sec (optional, default 600s = 10 min)
- provider v0.1.3 published to terra.k8c.ru
2026-03-07 17:49:07 +04:00
“Naeel”
2fec209880
feat: sless_job terraform resource + jobs REST API
...
Operator (v0.1.4):
- internal/api/handler/jobs.go: CreateJob/GetJob/DeleteJob handlers
- internal/api/router.go: POST/GET/DELETE /v1/namespaces/{ns}/jobs/{name}
Terraform provider (v0.1.2):
- client.go: JobRequest/JobResponse + CreateJob/GetJob/DeleteJob/WaitJobDone
- resources/job_resource.go: sless_job resource (Create blocks until Succeeded/Failed)
- provider.go: register NewJobResource
Deploy:
- operator:v0.1.4 deployed and running in cluster
- provider v0.1.2 published to terra.k8c.ru
2026-03-07 17:43:26 +04:00
“Naeel”
4bbb3cb4b2
feat: add FunctionJob CRD for one-shot function runs
...
- api/v1alpha1/job_types.go: new CRD FunctionJob (Pending/Running/Succeeded/Failed)
- controllers/functionjob_controller.go: reconciler creates k8s Job from FunctionRef + EventJSON
- zz_generated.deepcopy.go: DeepCopy methods for FunctionJob types
- config/crd/bases: generated CRD YAML, applied to cluster
- main.go: register FunctionJobReconciler
- rbac.yaml: add functionjobs permissions
- operator.yaml: v0.1.2 -> v0.1.3
- operator:v0.1.3 deployed and running in cluster
2026-03-07 17:20:21 +04:00
“Naeel”
7fc9bef96e
doc: document operator deploy, nodejs20 runtime, Dockerfile fixes, go.mod fix
2026-03-07 17:02:28 +04:00
“Naeel”
ee71eccf0c
feat: add nodejs20 runtime
...
- runtimes/nodejs20/server.js: HTTP wrapper, exports.handle(event)
- runtimes/nodejs20/Dockerfile: node:20-alpine base image
- naeel/sless-runtime-nodejs20:v0.1.0 pushed to DockerHub
- upload.go: nodejs20 in runtimeBaseImage(), package.json → npm install
- upload.go: python3.11 now uses v0.1.0 tag (no more latest)
- operator v0.1.2 deployed in cluster
- E2E: hello-node-default.fn.kube5s.ru → {"message":"Hello, Naeel! (nodejs20)"}
2026-03-07 17:00:29 +04:00
“Naeel”
6bcdb31f25
chore: switch pg-query example to remote endpoint sless-api.kube5s.ru
2026-03-07 16:50:05 +04:00
“Naeel”
b5fe310e33
chore: go mod tidy — fix direct/indirect annotations
2026-03-07 16:31:54 +04:00
“Naeel”
e8fa9e1723
feat: deploy operator in-cluster v0.1.1
...
- Dockerfile: fix golang 1.23→1.25, add internal/ + migrations/ to image
- deployments/k8s/operator.yaml: ConfigMap + Secret + Deployment + Service + Ingress
- Ingress: sless-api.kube5s.ru, TLS via cert-manager letsencrypt-prod
- naeel/sless-operator:v0.1.1 — running in namespace sless
- E2E: https://sless-api.kube5s.ru → HTTP/2 200
2026-03-07 16:30:14 +04:00
“Naeel”
7deea18848
fix: multiple fixes + pg-query e2e passed
...
upload.go:
- Update → Patch (MergeFrom) to avoid resourceVersion conflict when operator
modifies Function between Get() and Update()
terraform provider v0.1.1:
- trigger_resource.go: trToModel returns StringNull() for empty schedule
(fixes 'provider produced inconsistent result' for http triggers)
- main.go: bump version to 0.1.1
examples/pg-query:
- handler.py: fix column name started_at → created_at (matches migrations/001)
- main.tf: pin provider to ~> 0.1.1
.gitignore: add terraform state, lock, .terraform/, handler.zip
doc/errors/log.md: documented all 5 errors from this session:
- resourceVersion conflict → use Patch
- terraform inconsistent result for schedule → StringNull
- terraform import not implemented → delete+recreate workaround
- wrong column name → check migrations before writing handlers
- Deployment not restarting after image rebuild → rollout restart / TODO: restartedAt annotation
doc/progress.md: terraform apply e2e ✅
2026-03-07 10:52:29 +04:00
“Naeel”
e2c366a406
feat: add pg-query example + upload.go supports requirements.txt
...
- examples/pg-query/handler.py: Python function querying PostgreSQL invocations table
- examples/pg-query/requirements.txt: psycopg2-binary==2.9.9
- examples/pg-query/main.tf: terraform config for sless_function + sless_trigger
- internal/api/handler/upload.go: generateDockerfile() now accepts hasRequirements bool
- scans zip for requirements.txt at upload time
- adds RUN pip install --no-cache-dir to Dockerfile when requirements.txt present
- doc/progress.md: updated status for pg-query e2e task
2026-03-07 10:30:50 +04:00
“Naeel”
5f8dd6fa25
docs: обновить всю документацию по результатам сессии 2026-03-07
...
- infrastructure/overview.md: исправить S3 URL, Container Registry (DockerHub),
namespace sless, Terraform Registry terra.k8c.ru
- errors/log.md: добавить 3 ошибки — kaniko S3 scheme, бесконечный цикл сборки,
docker credStore desktop.exe
- decisions/log.md: добавить решения — DockerHub, terraform провайдер в той же
репе, WaitReady паттерн, code_hash для версионирования кода
- api/design.md: обновить базовый URL, добавить upload endpoint с описанием
процесса, исправить runtime список
2026-03-07 10:26:13 +04:00
“Naeel”
3d834e9b42
feat: Terraform провайдер sless v0.1.0 + обновление doc/progress.md
...
Независимый Go-модуль terraform/provider/ для управления функциями через REST API.
Ресурсы:
- sless_function: CRUD + upload zip + WaitReady (kaniko build 5 мин)
- sless_trigger: CRUD (http/cron)
Компоненты:
- internal/client/client.go — HTTP-клиент, готов к переносу в nubes
- internal/provider/provider.go — паттерн идентичен nubes NubesProvider
- internal/resources/ — function_resource.go, trigger_resource.go
- hack/build-and-publish.sh — GPG-подпись + mc upload в S3
Опубликовано: terra.k8c.ru/naeel/sless v0.1.0
Проверено: terraform init успешен
2026-03-07 10:23:52 +04:00
“Naeel”
290d6514e7
fix: бесконечный цикл сборки — idempotency guard через last-built-s3key аннотацию
...
Проблема: upload handler сбрасывал phase в Pending ПОСЛЕ того как
контроллер уже выставил Building → бесконечный цикл (94 job'а).
Решение:
- controllers/function_controller.go: startBuild сначала ставит аннотацию
last-built-s3key = spec.S3Key (idempotency guard), потом status.
Reconcile стартует сборку только если spec.S3Key != last-built-s3key.
- handler/upload.go: убран Status().Update() — контроллер сам управляет фазой.
- builder.go: IsAlreadyExists при создании job не ошибка (parallel reconcile).
2026-03-07 09:50:24 +04:00
“Naeel”
15db7c972d
fix: kaniko S3 endpoint — добавить https:// схему и S3_FORCE_PATH_STYLE=true
...
Kaniko AWS SDK требует полный URL с протоколом.
Ceph не поддерживает virtual-hosted style — нужен path style.
2026-03-07 09:39:53 +04:00
“Naeel”
c13edd7ee1
feat: upload endpoint POST /v1/namespaces/{ns}/functions/{name}/upload
...
- s3/client.go: Bucket() accessor + UploadContext() для tar.gz build context
- handler/upload.go: принимает zip, генерирует Dockerfile (FROM naeel/sless-runtime-{runtime}),
перепаковывает в tar.gz, загружает в S3, обновляет Function CRD → kaniko запускается
- router.go: маршрут POST .../upload зарегистрирован
2026-03-07 09:36:32 +04:00
“Naeel”
5cc438d9e6
feat: python3.11 base runtime image + DockerHub registry support
...
- runtimes/python3.11/: Dockerfile + server.py (HTTP wrapper на :8080)
- builder.go: RegistrySecret field, volume mount docker-creds для kaniko, убран --skip-tls-verify
- config.go: добавлен RegistrySecret (env REGISTRY_SECRET, default sless-registry-auth)
- main.go: передаём RegistrySecret в builder.Config
- hack/create-registry-secret.sh: создаёт k8s Secret из DockerHub токена
Образ наружу: naeel/sless-runtime-python3.11:latest (DockerHub)
K8s secret: sless-registry-auth в namespace sless
2026-03-07 09:32:59 +04:00
“Naeel”
37ff9dd5d2
docs: обновить progress.md по фактическому состоянию
...
- отражён реальный статус всех компонентов кода
- отражено состояние кластера (CRD, RBAC, postgres)
- добавлен список что ещё не сделано
- добавлены deployments/k8s/rbac.yaml, postgres.yaml
2026-03-07 08:57:54 +04:00
“Naeel”
78e4f6bca3
feat: REST API (gorilla/mux + slog) + trigger controller + main.go wiring
...
- controllers/trigger_controller.go: полная реализация, HTTP->Ingress+Service, Cron->CronJob
- internal/config: добавлены IngressHost, APIToken
- internal/api/router.go: gorilla/mux роутер /v1/namespaces/{ns}/...
- internal/api/handler/: functions, triggers, invocations, base handler с slog
- internal/api/middleware/: auth (Bearer token) + logging (slog)
- main.go: запуск operator + HTTP сервера параллельно
- go.sum: добавлен gorilla/mux v1.8.1
2026-03-07 08:46:10 +04:00