# 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