Files
sless/doc/api/design.md
T
Naeel b86ff3a62e feat(service): timeout_sec без дефолта; 0=нет таймаута; operator v0.1.48
- 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
2026-03-21 16:58:43 +03:00

7.5 KiB
Raw Blame History

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 в операторе:

  1. Извлекает sub из payload (без проверки подписи — доверяет Ingress)
  2. Вычисляет namespace: SHA256(sub)[:8] hex → sless-{16 hex символов}
  3. Проверяет что запрошенный {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>

Процесс:

  1. Принимает zip (max 32MB)
  2. Распаковывает zip
  3. Генерирует Dockerfile (FROM naeel/sless-runtime-{runtime}:latest\nCOPY . /app/function/)
  4. Перепаковывает в tar.gz (kaniko требует tar format)
  5. Загружает в S3: contexts/{ns}/{name}/{timestamp}.tar.gz
  6. Обновляет 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 / не задано Без ограничений — функция выполняется любое время
1900 Таймаут в секундах (+ 5s grace на стороне прокси)
< 0 или > 900 HTTP 400 Bad Request

Примечание: Поле опциональное (Optional в Terraform). Не указывать = без лимита. В Terraform state значение null означает "лимит не задан" (не путать с 0). В Kubernetes CRD TimeoutSec: 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 == 0http.Client{} (Go: Timeout=0 → отсутствие дедлайна).