commit ef0f4e3c00947db5b02f88b3213c4e269ee89071 Author: Naeel Date: Tue Apr 14 21:23:23 2026 +0300 doc: CODEX_PLAN.md — подробный план для GPT 5.3 Codex diff --git a/doc/CODEX_PLAN.md b/doc/CODEX_PLAN.md new file mode 100644 index 0000000..00687a9 --- /dev/null +++ b/doc/CODEX_PLAN.md @@ -0,0 +1,711 @@ +# Terraform Provider для Fission — Подробный план разработки +# Дата: 2026-04-14 +# Агент: GPT 5.3 Codex +# Домен: fission.kube5s.ru + +--- + +## КОНТЕКСТ ПРОЕКТА + +### Что делаем +Terraform provider для Fission (https://fission.io) — open-source serverless фреймворка на Kubernetes. +Provider позволяет управлять Fission-ресурсами (environments, packages, functions, triggers) через Terraform. + +### Зачем +Fission используется как managed FaaS-сервис в нашем облаке. Terraform — основной инструмент IaC. +Готового провайдера не существует (единственная попытка — https://github.com/sambuysse/terraform-provider-fission — заброшена 5 лет назад, реализован только 1 ресурс). + +### Архитектура +``` +Terraform Provider (Go) → HTTP → Fission Controller API (порт 443 через Ingress) + ↓ + Fission делает всё сам: + - StorageSvc (PV, позже S3) + - Builder Manager → Builder Pods + - Executor → Function Pods + - Router → HTTP routing +``` + +**Provider НЕ управляет S3, PV, Kubernetes напрямую.** Только HTTP-вызовы к Fission Controller REST API. +Fission сам хранит код (StorageSvc), собирает (Builder), запускает (Executor), маршрутизирует (Router). + +### Ключевые решения +- Без proxy/operator — provider напрямую к Fission Controller API +- StorageSvc на PV (local storage) — позже мигрируем на S3 +- terraform-plugin-framework (НЕ старый SDKv2) +- Паттерны из существующего sless-провайдера (структура, client, build script) +- Domain: fission.kube5s.ru + +--- + +## РЕФЕРЕНСНЫЙ КОД — sless provider + +Провайдер sless (наш существующий, рабочий) находится в: +``` +/home/naeel/terra/sless/terraform/provider/ +├── main.go # Точка входа +├── go.mod / go.sum +├── hack/build-and-publish.sh # Сборка и публикация +└── internal/ + ├── client/client.go # HTTP-клиент (~34KB) — к sless API + ├── provider/provider.go # Конфигурация провайдера + └── resources/ + ├── function_resource.go # sless_function + ├── service_resource.go # sless_service + ├── trigger_resource.go # sless_trigger + ├── job_resource.go # sless_job + └── iot_device_resource.go # sless_iot_device +``` + +**Что копировать из sless:** +- Структуру каталогов и файлов +- main.go (адаптировать имя провайдера) +- provider.go (endpoint, token — аналогично; убрать nubes_endpoint, namespace вычисление) +- build-and-publish.sh (адаптировать имена) +- Паттерн resources: Metadata, Schema, Create, Read, Update, Delete, Configure + +**Что НЕ копировать:** +- client.go целиком — переписать под Fission API (другие endpoints, другой формат) +- Kaniko-логику — Fission строит сам +- S3 upload — Fission принимает через HTTP, хранит сам +- JWT→namespace mapping — для MVP не нужно +- source_dir zip + hash логику — упростить, Fission Package принимает zip напрямую + +--- + +## FISSION API REFERENCE + +### Fission Controller REST API + +Fission Controller слушает на порте 8888 (внутри кластера) или через Ingress. +API работает с Kubernetes CRD-объектами через REST. + +**Base URL:** `https://fission.kube5s.ru/` (через Ingress) или `http://controller.fission.svc:8888` + +### Эндпоинты (v2 API) + +#### Environments +``` +POST /v2/environments — создать environment +GET /v2/environments — список environments +GET /v2/environments/{name} — получить environment +PUT /v2/environments/{name} — обновить environment +DELETE /v2/environments/{name} — удалить environment +``` + +#### Packages +``` +POST /v2/packages — создать package (multipart: zip с кодом) +GET /v2/packages — список packages +GET /v2/packages/{name} — получить package +PUT /v2/packages/{name} — обновить package +DELETE /v2/packages/{name} — удалить package +``` + +#### Functions +``` +POST /v2/functions — создать function +GET /v2/functions — список functions +GET /v2/functions/{name} — получить function +PUT /v2/functions/{name} — обновить function +DELETE /v2/functions/{name} — удалить function +``` + +#### HTTP Triggers +``` +POST /v2/triggers/http — создать HTTP trigger +GET /v2/triggers/http — список HTTP triggers +GET /v2/triggers/http/{name} — получить HTTP trigger +PUT /v2/triggers/http/{name} — обновить HTTP trigger +DELETE /v2/triggers/http/{name} — удалить HTTP trigger +``` + +#### Time Triggers +``` +POST /v2/triggers/time — создать time trigger +GET /v2/triggers/time — список time triggers +GET /v2/triggers/time/{name} — получить time trigger +PUT /v2/triggers/time/{name} — обновить time trigger +DELETE /v2/triggers/time/{name} — удалить time trigger +``` + +#### Message Queue Triggers +``` +POST /v2/triggers/messagequeue — создать MQ trigger +GET /v2/triggers/messagequeue — список MQ triggers +GET /v2/triggers/messagequeue/{name} — получить MQ trigger +PUT /v2/triggers/messagequeue/{name} — обновить MQ trigger +DELETE /v2/triggers/messagequeue/{name} — удалить MQ trigger +``` + +### Аутентификация +Fission 1.22 поддерживает auth. При установке через helm: +```yaml +authentication: + enabled: true +``` +Provider передаёт токен в заголовке: +``` +Authorization: Bearer +``` + +### Namespace +Все ресурсы Fission создаются в namespace указанном при helm install (по дефолту `fission`). +Функции работают в `defaultNamespace` (по дефолту тот же `fission` или кастомный). + +--- + +## FISSION CRD МОДЕЛИ (для Schema ресурсов) + +### Environment +```json +{ + "metadata": { "name": "python", "namespace": "fission-function" }, + "spec": { + "version": 3, + "runtime": { + "image": "ghcr.io/fission/python-env" + }, + "builder": { + "image": "ghcr.io/fission/python-builder", + "command": "build" + }, + "poolsize": 3, + "resources": { + "requests": { "cpu": "100m", "memory": "128Mi" }, + "limits": { "cpu": "200m", "memory": "256Mi" } + }, + "imagepullsecret": "", + "allowedFunctionsPerContainer": "single" + } +} +``` + +### Package +```json +{ + "metadata": { "name": "hello-pkg", "namespace": "fission-function" }, + "spec": { + "environment": { "name": "python", "namespace": "fission-function" }, + "source": { + "type": "literal", + "literal": "" + }, + "buildcmd": "" + }, + "status": { + "buildstatus": "succeeded", + "buildlog": "..." + } +} +``` + +Для больших файлов source.type = "url", и архив загружается через StorageSvc. + +### Function +```json +{ + "metadata": { "name": "hello", "namespace": "fission-function" }, + "spec": { + "environment": { "name": "python", "namespace": "fission-function" }, + "package": { + "packageref": { "name": "hello-pkg", "namespace": "fission-function", "resourceversion": "12345" }, + "functionName": "main.handler" + }, + "resources": { + "requests": { "cpu": "100m", "memory": "128Mi" }, + "limits": { "cpu": "200m", "memory": "256Mi" } + }, + "InvokeStrategy": { + "ExecutionStrategy": { + "ExecutorType": "poolmgr", + "MinScale": 0, + "MaxScale": 5, + "TargetCPUPercent": 80, + "SpecializationTimeout": 120 + }, + "StrategyType": "execution" + }, + "functionTimeout": 60, + "idletimeout": 120, + "concurrency": 500, + "requestsPerPod": 1 + } +} +``` + +### HTTPTrigger +```json +{ + "metadata": { "name": "hello-route", "namespace": "fission-function" }, + "spec": { + "relativeurl": "/hello", + "methods": ["GET", "POST"], + "functionref": { "type": "name", "name": "hello" }, + "createingress": false, + "ingressconfig": { + "host": "fission.kube5s.ru", + "path": "/hello", + "annotations": {} + } + } +} +``` + +### TimeTrigger +```json +{ + "metadata": { "name": "cron-job", "namespace": "fission-function" }, + "spec": { + "cron": "*/5 * * * *", + "functionref": { "type": "name", "name": "hello" } + } +} +``` + +--- + +## СТРУКТУРА ПРОЕКТА (создать) + +``` +fission/ +├── .github/ +│ └── copilot-instructions.md # Правила для агентов +├── doc/ +│ ├── CODEX_PLAN.md # Этот файл +│ └── progress.md # Трекер задач +├── terraform/ +│ └── provider/ +│ ├── main.go # Точка входа terraform-plugin-framework +│ ├── go.mod # Module: terraform-provider-fission +│ ├── go.sum +│ ├── internal/ +│ │ ├── client/ +│ │ │ └── client.go # HTTP-клиент к Fission Controller API +│ │ ├── provider/ +│ │ │ └── provider.go # Конфигурация провайдера +│ │ └── resources/ +│ │ ├── environment_resource.go # fission_environment +│ │ ├── package_resource.go # fission_package +│ │ ├── function_resource.go # fission_function +│ │ ├── http_trigger_resource.go # fission_http_trigger +│ │ ├── time_trigger_resource.go # fission_time_trigger (фаза 2) +│ │ └── mqt_resource.go # fission_mqt (фаза 2) +│ └── hack/ +│ └── build-and-publish.sh +├── examples/ +│ ├── hello-python/ +│ │ ├── main.tf +│ │ └── code/ +│ │ └── main.py +│ └── README.md +├── .gitignore +└── README.md +``` + +--- + +## ФАЗЫ РАЗРАБОТКИ + +### ФАЗА 0 — Подготовка (инфраструктура, ДО codex — руками) + +**0.1** Установить Fission 1.22 на кластер: +```bash +kubectl create namespace fission +kubectl create -k "github.com/fission/fission/crds/v1?ref=v1.22.0" +helm repo add fission-charts https://fission.github.io/fission-charts/ +helm repo update +helm install fission fission-charts/fission-all \ + --version 1.22.1 \ + --namespace fission \ + --set serviceType=ClusterIP \ + --set routerServiceType=ClusterIP \ + --set authentication.enabled=true +``` + +**0.2** Настроить Ingress на fission.kube5s.ru → Fission Router + Controller + +**0.3** Установить fission CLI и проверить: +```bash +fission env create --name python --image ghcr.io/fission/python-env +fission fn create --name hello --env python --code hello.py +fission fn test --name hello +``` + +**0.4** Проверить REST API: +```bash +curl -H "Authorization: Bearer $TOKEN" https://fission.kube5s.ru/v2/environments +``` + +--- + +### ФАЗА 1 — Provider MVP (codex) + +**Задача: provider с 4 ресурсами, рабочий terraform apply → функция отвечает по HTTP.** + +#### 1.1 Scaffolding +- Создать структуру каталогов (см. выше) +- `go.mod` с зависимостями: `github.com/hashicorp/terraform-plugin-framework`, `terraform-plugin-go` +- `main.go` — точка входа (по образцу sless/terraform/provider/main.go) +- `.gitignore` — бинарники, .terraform, *.tfstate + +#### 1.2 Client (internal/client/client.go) +HTTP-клиент к Fission Controller API. + +**Структура:** +```go +package client + +type Client struct { + httpClient *http.Client + endpoint string // https://fission.kube5s.ru + token string // Bearer JWT + namespace string // namespace для функций (дефолт "fission-function") +} + +func New(endpoint, token, namespace string) *Client + +// Environments +func (c *Client) CreateEnvironment(ctx, env) error +func (c *Client) GetEnvironment(ctx, name) (*Environment, error) +func (c *Client) UpdateEnvironment(ctx, env) error +func (c *Client) DeleteEnvironment(ctx, name) error + +// Packages +func (c *Client) CreatePackage(ctx, pkg) (*Package, error) +func (c *Client) GetPackage(ctx, name) (*Package, error) +func (c *Client) UpdatePackage(ctx, pkg) (*Package, error) +func (c *Client) DeletePackage(ctx, name) error + +// Functions +func (c *Client) CreateFunction(ctx, fn) error +func (c *Client) GetFunction(ctx, name) (*Function, error) +func (c *Client) UpdateFunction(ctx, fn) error +func (c *Client) DeleteFunction(ctx, name) error + +// HTTP Triggers +func (c *Client) CreateHTTPTrigger(ctx, trigger) error +func (c *Client) GetHTTPTrigger(ctx, name) (*HTTPTrigger, error) +func (c *Client) UpdateHTTPTrigger(ctx, trigger) error +func (c *Client) DeleteHTTPTrigger(ctx, name) error +``` + +**Формат запросов:** +- Content-Type: application/json (для CRUD) +- Content-Type: multipart/form-data (для upload в Package) +- Authorization: Bearer +- Namespace в metadata объекта + +**ВАЖНО:** Размер client.go — целевой ~500-800 строк. Никакого S3, kaniko, polling. + +#### 1.3 Provider (internal/provider/provider.go) + +**Атрибуты провайдера:** +```hcl +provider "fission" { + endpoint = "https://fission.kube5s.ru" # URL Fission Controller (env: FISSION_ENDPOINT) + token = "xxx" # Bearer JWT (env: FISSION_TOKEN) + namespace = "fission-function" # Namespace (env: FISSION_NAMESPACE, default: "fission-function") +} +``` + +**Configure():** +1. Прочитать endpoint (config → env FISSION_ENDPOINT → default "http://localhost:8888") +2. Прочитать token (config → env FISSION_TOKEN → пусто = без auth) +3. Прочитать namespace (config → env FISSION_NAMESPACE → default "fission-function") +4. Создать Client +5. Положить в resp.ResourceData и resp.DataSourceData + +**Resources():** +```go +return []func() resource.Resource{ + resources.NewEnvironmentResource, + resources.NewPackageResource, + resources.NewFunctionResource, + resources.NewHTTPTriggerResource, +} +``` + +#### 1.4 Resource: fission_environment + +**Terraform Schema:** +```hcl +resource "fission_environment" "python" { + name = "python" # Required, ForceNew + image = "ghcr.io/fission/python-env" # Required (runtime image) + version = 3 # Optional, default 3 + builder_image = "ghcr.io/fission/python-builder" # Optional + builder_command = "build" # Optional + poolsize = 3 # Optional, default 3 + min_cpu = "100m" # Optional + max_cpu = "200m" # Optional + min_memory = "128Mi" # Optional + max_memory = "256Mi" # Optional + image_pull_secret = "" # Optional + keepalive = "single" # Optional: "single" / "infinite" + + # Computed + uid = "..." # k8s UID +} +``` + +**CRUD:** +- Create: POST /v2/environments → JSON body +- Read: GET /v2/environments/{name}?namespace={ns} +- Update: PUT /v2/environments/{name} → JSON body +- Delete: DELETE /v2/environments/{name}?namespace={ns} + +#### 1.5 Resource: fission_package + +**Terraform Schema:** +```hcl +resource "fission_package" "hello_pkg" { + name = "hello-pkg" # Required, ForceNew + environment = "python" # Required — имя environment + source_dir = "${path.module}/code" # Optional — директория (provider пакует в zip) + code_path = "${path.module}/hello.zip" # Optional — путь к готовому zip + code_hash = filesha256("...") # Optional — для детекции изменений + build_command = "" # Optional + + # Computed + build_status = "succeeded" + build_log = "..." + uid = "..." +} +``` + +source_dir и code_path — взаимоисключающие. + +**CRUD:** +- Create: zip source_dir или читаем code_path → POST /v2/packages (multipart) → poll build_status +- Read: GET /v2/packages/{name} +- Update: PUT /v2/packages/{name} (перезаливаем zip) +- Delete: DELETE /v2/packages/{name} + +#### 1.6 Resource: fission_function + +**Terraform Schema:** +```hcl +resource "fission_function" "hello" { + name = "hello" # Required, ForceNew + environment = "python" # Required + package_name = fission_package.hello_pkg.name # Required + entrypoint = "main.handler" # Required + + # Optional — execution strategy + executor_type = "poolmgr" # "poolmgr" / "newdeploy" / "container" + min_scale = 0 + max_scale = 5 + target_cpu_percent = 80 + specialization_timeout = 120 # сек + + # Optional — timeouts и concurrency + function_timeout = 60 # сек + idle_timeout = 120 # сек + concurrency = 500 + requests_per_pod = 1 + + # Optional — resources + min_cpu = "100m" + max_cpu = "200m" + min_memory = "128Mi" + max_memory = "256Mi" + + # Optional — secrets и configmaps + secrets = ["my-secret"] + configmaps = ["my-config"] + + # Computed + uid = "..." +} +``` + +**CRUD:** +- Create: POST /v2/functions → JSON body +- Read: GET /v2/functions/{name} +- Update: PUT /v2/functions/{name} +- Delete: DELETE /v2/functions/{name} + +#### 1.7 Resource: fission_http_trigger + +**Terraform Schema:** +```hcl +resource "fission_http_trigger" "hello_route" { + name = "hello-route" # Required, ForceNew + function = "hello" # Required — имя функции + url = "/hello" # Required — relative URL path + methods = ["GET", "POST"] # Optional, default ["GET"] + create_ingress = false # Optional + host = "fission.kube5s.ru" # Optional — для ingress + prefix = "" # Optional — prefix routing + keep_prefix = false # Optional + + # Computed + uid = "..." +} +``` + +**CRUD:** +- Create: POST /v2/triggers/http → JSON body +- Read: GET /v2/triggers/http/{name} +- Update: PUT /v2/triggers/http/{name} +- Delete: DELETE /v2/triggers/http/{name} + +#### 1.8 Build & Publish (hack/build-and-publish.sh) +Адаптировать из sless: +- Имя: terraform-provider-fission +- Build для linux_amd64 и darwin_amd64 +- Публикация в Gitea +- Версия из git tag + +#### 1.9 Example +```hcl +# examples/hello-python/main.tf + +terraform { + required_providers { + fission = { + source = "gitea.services.ngcloud.ru/Nail/fission" + version = "~> 0.1.0" + } + } +} + +provider "fission" { + endpoint = "https://fission.kube5s.ru" + token = var.token + namespace = "fission-function" +} + +resource "fission_environment" "python" { + name = "python" + image = "ghcr.io/fission/python-env" + version = 3 + poolsize = 3 +} + +resource "fission_package" "hello_pkg" { + name = "hello-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code" +} + +resource "fission_function" "hello" { + name = "hello" + environment = fission_environment.python.name + package_name = fission_package.hello_pkg.name + entrypoint = "main.handler" +} + +resource "fission_http_trigger" "hello_route" { + name = "hello-route" + function = fission_function.hello.name + url = "/hello" + methods = ["GET"] +} + +output "function_url" { + value = "https://fission.kube5s.ru/hello" +} +``` + +```python +# examples/hello-python/code/main.py +def handler(context): + return "Hello from Fission via Terraform!\n" +``` + +--- + +### ФАЗА 2 — Дополнительные ресурсы (после MVP) + +- **fission_time_trigger** — cron triggers +- **fission_mqt** — message queue triggers (Kafka/NATS) +- **fission_canary** — canary deployments +- **fission_watch_trigger** — kubernetes watch triggers +- **data sources** — для чтения существующих ресурсов + +### ФАЗА 3 — Multi-tenancy (после демо) + +- JWT→namespace mapping (как в sless) +- Каждый пользователь — свой namespace для функций +- Валидация токена через nubes API + +--- + +## ПРАВИЛА ДЛЯ CODEX + +1. **Язык — Go.** Все комментарии — на русском. +2. **terraform-plugin-framework** — НЕ terraform-plugin-sdk/v2. +3. **Комментарии обязательны:** в начале файла (дата, назначение), на каждой функции, на нетривиальной логике. +4. **Именование:** уникальные, осмысленные имена. Запрещены `handler`, `data`, `temp` без контекста. +5. **Не выдумывать** значения, API эндпоинты, поведение. Если не уверен — оставить TODO. +6. **Не совершенствовать** то что уже работает. Делать только то что описано в плане. +7. **Размер client.go:** 500-800 строк. Не раздувать. +8. **Тестирование:** `go build ./...` должен проходить после каждого шага. +9. **Git:** коммит после каждого логического этапа. + +--- + +## ПОРЯДОК ВЫПОЛНЕНИЯ ДЛЯ CODEX + +``` +Шаг 1: Создать структуру каталогов + go.mod + main.go + .gitignore +Шаг 2: Написать client/client.go (модели данных + HTTP методы) +Шаг 3: Написать provider/provider.go +Шаг 4: Написать resources/environment_resource.go +Шаг 5: go build — должен компилироваться +Шаг 6: Написать resources/package_resource.go (включая zip-логику) +Шаг 7: Написать resources/function_resource.go +Шаг 8: Написать resources/http_trigger_resource.go +Шаг 9: go build — финальная проверка +Шаг 10: Написать hack/build-and-publish.sh +Шаг 11: Создать examples/ +Шаг 12: Создать README.md +Шаг 13: Создать .github/copilot-instructions.md +Шаг 14: git add -A && git commit && git push +``` + +--- + +## ПРОВЕРКА РЕЗУЛЬТАТА + +После завершения codex, мы руками: +1. Соберём: `cd terraform/provider && go build -o terraform-provider-fission` +2. Установим в ~/.terraform.d/plugins/ +3. `cd examples/hello-python && terraform init && terraform plan && terraform apply` +4. `curl https://fission.kube5s.ru/hello` → "Hello from Fission via Terraform!" +# Terraform Provider для Fission — Подробный план разработки +# Дата: 2026-04-14 +# Агент: GPT 5.3 Codex +# Домен: fission.kube5s.ru + +--- + +## КОНТЕКСТ ПРОЕКТА + +### Что делаем +Terraform provider для Fission (https://fission.io) — open-source serverless фреймворка на Kubernetes. +Provider позволяет управлять Fission-ресурсами (environments, packages, functions, triggers) через Terraform. + +### Зачем +Fission используется как managed FaaS-сервис в нашем облаке. Terraform — основной инструмент IaC. +Готового провайдера не существует. + +### Архитектура +Terraform Provider (Go) -> HTTP -> Fission Controller API (порт 443 через Ingress) + | + Fission делает все сам: + - StorageSvc (PV, позже S3) + - Builder Manager -> Builder Pods + - Executor -> Function Pods + - Router -> HTTP routing + +Provider НЕ управляет S3, PV, Kubernetes напрямую. Только HTTP-вызовы к Fission Controller REST API. + +### Ключевые решения +- Без proxy/operator — provider напрямую к Fission Controller API +- StorageSvc на PV (local storage) — позже мигрируем на S3 +- terraform-plugin-framework (НЕ старый SDKv2) +- Паттерны из существующего sless-провайдера (структура, client, build script) +- Domain: fission.kube5s.ru