Files
fission-console/doc/CODEX_PLAN.md
T

27 KiB
Raw Blame History

Terraform Provider для Fission — Подробный план разработки

Дата: 2026-04-14

Агент: GPT 5.3 Codex

Домен: fission.kube5s.ru

ОБНОВЛЕНИЕ ПО ФАКТУ ПРОВЕРКИ В КЛАСТЕРЕ (2026-04-14)

Проверено на кластере iot-naeel:

  • Fission v1.22.1 поднят и работает (env/function/route через fission CLI успешны)
  • путь GET /v2/environments через ingress (185.247.187.151) возвращает 404 page not found
  • отдельного controller service/deployment в текущем fission-all релизе нет

Критичное решение: MVP провайдера делать через Kubernetes API (CRD Fission) с использованием client-go/dynamic client, а не через REST /v2/*.

Provider продолжает управлять теми же сущностями (Environment, Package, Function, HTTPTrigger), но операции Create/Read/Update/Delete выполняются через Kubernetes CRD ресурсы.


КОНТЕКСТ ПРОЕКТА

Что делаем

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) → Kubernetes API (client-go/dynamic) → Fission CRD
          ↓
        Fission делает всё сам:
        - StorageSvc (PV, позже S3)
        - Builder Manager → Builder Pods
        - Executor → Function Pods
        - Router → HTTP routing

Provider НЕ управляет S3/PV напрямую. Он управляет только Fission CRD через Kubernetes API. Fission сам хранит код (StorageSvc), собирает (Builder), запускает (Executor), маршрутизирует (Router).

Ключевые решения

  • Без proxy/operator — provider напрямую к Kubernetes API (Fission CRD)
  • 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 v1.22.1 в этом кластере REST /v2/* недоступен (404). Раздел ниже оставлен как историческая справка; для реализации MVP использовать Kubernetes CRD API.

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:

authentication:
  enabled: true

Provider передаёт токен в заголовке:

Authorization: Bearer <token>

Namespace

Все ресурсы Fission создаются в namespace указанном при helm install (по дефолту fission). Функции работают в defaultNamespace (по дефолту тот же fission или кастомный).


FISSION CRD МОДЕЛИ (для Schema ресурсов)

Environment

{
  "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

{
  "metadata": { "name": "hello-pkg", "namespace": "fission-function" },
  "spec": {
    "environment": { "name": "python", "namespace": "fission-function" },
    "source": {
      "type": "literal",
      "literal": "<base64 zip>"
    },
    "buildcmd": ""
  },
  "status": {
    "buildstatus": "succeeded",
    "buildlog": "..."
  }
}

Для больших файлов source.type = "url", и архив загружается через StorageSvc.

Function

{
  "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

{
  "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

{
  "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 на кластер:

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

0.3 Установить fission CLI и проверить:

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 Проверить CRD API через Kubernetes:

kubectl get crd environments.fission.io functions.fission.io packages.fission.io httptriggers.fission.io
kubectl get environments -n default

ФАЗА 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)

Клиент к Kubernetes API для работы с Fission CRD.

Структура:

package client

type Client struct {
  dynClient   dynamic.Interface
  k8sClient   kubernetes.Interface
  namespace   string        // namespace для функций (дефолт "default")
}

func New(kubeconfigPath, kubeContext, namespace string) (*Client, error)

// 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

Формат работы:

  • dynamic client для CRD *.fission.io
  • операции CRUD через Kubernetes API
  • Namespace через metadata и provider config
  • код package загружается в spec.source.literal (base64 zip) для MVP

ВАЖНО: Размер client.go — целевой ~500-900 строк. Никакого S3, kaniko, polling.

1.3 Provider (internal/provider/provider.go)

Атрибуты провайдера:

provider "fission" {
  kubeconfig_path = "~/.kube/config"        # env: KUBECONFIG
  kube_context    = ""                      # env: KUBE_CONTEXT (optional)
  namespace       = "default"               # env: FISSION_NAMESPACE
}

Configure():

  1. Прочитать kubeconfig_path (config → env KUBECONFIG)
  2. Прочитать kube_context (config → env KUBE_CONTEXT)
  3. Прочитать namespace (config → env FISSION_NAMESPACE → default "default")
  4. Создать Kubernetes dynamic client
  5. Положить в resp.ResourceData и resp.DataSourceData

Resources():

return []func() resource.Resource{
    resources.NewEnvironmentResource,
    resources.NewPackageResource,
    resources.NewFunctionResource,
    resources.NewHTTPTriggerResource,
}

1.4 Resource: fission_environment

Terraform Schema:

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: Kubernetes create CRD environments.fission.io
  • Read: Kubernetes get CRD environments.fission.io
  • Update: Kubernetes update CRD environments.fission.io
  • Delete: Kubernetes delete CRD environments.fission.io

1.5 Resource: fission_package

Terraform Schema:

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 → base64 → Kubernetes create CRD packages.fission.io
  • Read: Kubernetes get CRD packages.fission.io
  • Update: Kubernetes update CRD packages.fission.io
  • Delete: Kubernetes delete CRD packages.fission.io

1.6 Resource: fission_function

Terraform Schema:

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: Kubernetes create CRD functions.fission.io
  • Read: Kubernetes get CRD functions.fission.io
  • Update: Kubernetes update CRD functions.fission.io
  • Delete: Kubernetes delete CRD functions.fission.io

1.7 Resource: fission_http_trigger

Terraform Schema:

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: Kubernetes create CRD httptriggers.fission.io
  • Read: Kubernetes get CRD httptriggers.fission.io
  • Update: Kubernetes update CRD httptriggers.fission.io
  • Delete: Kubernetes delete CRD httptriggers.fission.io

1.8 Build & Publish (hack/build-and-publish.sh)

Адаптировать из sless:

  • Имя: terraform-provider-fission
  • Build для linux_amd64 и darwin_amd64
  • Публикация в Gitea
  • Версия из git tag

1.9 Example

# 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"
}
# 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