- api/v1alpha1/service_types.go: убрать +kubebuilder:default=30
- invoke.go: TimeoutSec=0 → &http.Client{} (без таймаута)
- services.go: валидация timeout_sec < 0 || > 900 → HTTP 400
- service_resource.go: TF schema Optional (без Computed); 0 → Int64Null()
- deployments/k8s/operator.yaml: v0.1.47 → v0.1.48
- doc/: progress.md + api/design.md (модель Service) + decisions/log.md
- examples/POSTGRES/: bug_hunter.sh, chaos_marathon.sh, chaos_marathon.tf
7.5 KiB
API Design
Последнее обновление: 2026-03-21
Базовый URL
http://<operator-host>:9090/v1
Локально: http://localhost:9090/v1
В кластере: http://sless-operator.sless.svc.cluster.local:9090/v1
Публично: https://sless.kube5s.ru/v1/... (через Ingress)
Реализованные эндпоинты:
GET /v1/namespaces/{ns}/functions
POST /v1/namespaces/{ns}/functions
GET /v1/namespaces/{ns}/functions/{name}
PUT /v1/namespaces/{ns}/functions/{name}
DELETE /v1/namespaces/{ns}/functions/{name}
POST /v1/namespaces/{ns}/functions/{name}/upload
GET /v1/namespaces/{ns}/functions/{name}/source ← файлы кода из S3 tar.gz (JSON)
GET /v1/namespaces/{ns}/functions/{name}/invocations
GET /v1/namespaces/{ns}/services
POST /v1/namespaces/{ns}/services
GET /v1/namespaces/{ns}/services/{name}
PUT /v1/namespaces/{ns}/services/{name}
DELETE /v1/namespaces/{ns}/services/{name}
GET /v1/namespaces/{ns}/services/{name}/source ← файлы кода из S3 tar.gz (JSON)
GET /v1/namespaces/{ns}/triggers
POST /v1/namespaces/{ns}/triggers
GET /v1/namespaces/{ns}/triggers/{name}
PATCH /v1/namespaces/{ns}/triggers/{name} ← {"enabled": bool}
DELETE /v1/namespaces/{ns}/triggers/{name}
POST /v1/namespaces/{ns}/jobs
GET /v1/namespaces/{ns}/jobs/{name}
DELETE /v1/namespaces/{ns}/jobs/{name}
Вызов функций (публичный, без auth):
POST https://sless.kube5s.ru/fn/{namespace}/{service-name} ← прокси к Deployment
Глобальный сервис funcs (не оператор):
GET https://sless.kube5s.ru/funcs/<namespace> ← plain text (курл) / HTML (браузер)
GET https://sless.kube5s.ru/funcs?token=<jwt> ← редирект по namespace
GET https://sless.kube5s.ru/funcs/<namespace>/source/<fn> ← прокси к GET /source
PATCH https://sless.kube5s.ru/funcs/<namespace>/triggers/<name> ← прокси к PATCH /triggers
GET https://sless.kube5s.ru/health ← liveness probe
Аутентификация
Authorization: Bearer <cloud-token>
Токен — JWT от auth-api. Middleware в операторе:
- Извлекает
subиз payload (без проверки подписи — доверяет Ingress) - Вычисляет namespace:
SHA256(sub)[:8]hex →sless-{16 hex символов} - Проверяет что запрошенный
{namespace}совпадает с вычисленным
Ресурсы
Functions
| Метод | Путь | Описание |
|---|---|---|
| GET | /functions | Список функций |
| POST | /functions | Создать функцию |
| GET | /functions/{id} | Получить функцию |
| PUT | /functions/{id} | Обновить функцию |
| DELETE | /functions/{id} | Удалить функцию |
Versions (код функции)
| Метод | Путь | Описание |
|---|---|---|
| GET | /functions/{id}/versions | Список версий |
| POST | /functions/{id}/versions | Загрузить новый код (multipart zip) |
| GET | /functions/{id}/versions/{ver} | Получить версию |
| POST | /functions/{id}/versions/{ver}/activate | Активировать версию |
Triggers
| Метод | Путь | Описание |
|---|---|---|
| GET | /functions/{id}/triggers | Список триггеров |
| POST | /functions/{id}/triggers | Создать триггер (HTTP/Cron) |
| DELETE | /functions/{id}/triggers/{tid} | Удалить триггер |
Invocations (вызов и логи)
| Метод | Путь | Описание |
|---|---|---|
| POST | /functions/{id}/invoke | Синхронный вызов |
| GET | /functions/{id}/invocations | История вызовов |
| GET | /functions/{id}/invocations/{iid} | Детали вызова + логи |
Upload endpoint
POST /v1/namespaces/{namespace}/functions/{name}/upload
Content-Type: multipart/form-data
Authorization: Bearer <token>
field: code = <zip-file>
Процесс:
- Принимает zip (max 32MB)
- Распаковывает zip
- Генерирует
Dockerfile(FROM naeel/sless-runtime-{runtime}:latest\nCOPY . /app/function/) - Перепаковывает в
tar.gz(kaniko требует tar format) - Загружает в S3:
contexts/{ns}/{name}/{timestamp}.tar.gz - Обновляет
fn.Spec.S3Key→ контроллер видит изменение и запускает kaniko Job
Ответ 200 OK:
{"message": "build queued", "phase": "Pending", "s3_key": "contexts/..."}
Поддерживаемые runtime (v1)
python3.11— реализован и протестированnodejs20— реализован и протестированgo1.23— реализован
Модель Function
{
"id": "fn-uuid",
"name": "my-function",
"description": "...",
"runtime": "python3.11",
"entrypoint": "handler.handle",
"memory_mb": 128,
"timeout_sec": 30,
"env_vars": {"KEY": "value"},
"active_version": "1",
"status": "active",
"created_at": "...",
"updated_at": "..."
}
Модель Trigger
{
"id": "tr-uuid",
"type": "http",
"url": "https://sless.api.ngcloud.ru/invoke/fn-uuid",
"created_at": "..."
}
{
"id": "tr-uuid",
"type": "cron",
"schedule": "0 * * * *",
"created_at": "..."
}
Модель Service (sless_service — always-on Deployment)
sless_service — долгоживущая функция. Деплоится как Kubernetes Deployment + Service + Ingress.
Вызывается через POST /fn/{namespace}/{name} без авторизации (прокси напрямую к поду).
{
"name": "pg-info",
"display_name": "PostgreSQL Info",
"description": "Возвращает список таблиц",
"runtime": "python3.11",
"entrypoint": "handler.handle",
"memory_mb": 128,
"timeout_sec": null,
"env_vars": {"DB_HOST": "..."},
"status": "Ready",
"image_ref": "pearlharbor.../naeel/pg-info:abc123",
"invoke_url": "https://sless.kube5s.ru/fn/sless-ffd1f598c169b0ae/pg-info"
}
Поле timeout_sec
| Значение | Поведение |
|---|---|
null / не задано |
Без ограничений — функция выполняется любое время |
1–900 |
Таймаут в секундах (+ 5s grace на стороне прокси) |
< 0 или > 900 |
HTTP 400 Bad Request |
Примечание: Поле опциональное (Optional в Terraform). Не указывать = без лимита. В Terraform state значение
nullозначает "лимит не задан" (не путать с0). В Kubernetes CRDTimeoutSec: 0→ лимита нет (поле omitempty).
Invoke прокси (как работает timeout_sec)
Оператор принимает POST /fn/{ns}/{name}, находит Service CRD, проксирует запрос
к http://{name}.sless-fn-{ns}.svc.cluster.local:8080.
Если TimeoutSec > 0 — создаёт http.Client{Timeout: TimeoutSec*s + 5s}.
Если TimeoutSec == 0 — http.Client{} (Go: Timeout=0 → отсутствие дедлайна).