Аудит провайдера vs каноничный Fission. Добавлено:
Environment:
- builder_image, builder_command для Go и языков с build step
Package:
- deploy_type (literal/source) для переключения deployment/source archive
- loadPackageSourceArchive() — zip-упаковка source_dir
- Убран пустой source:{} из literal mode
Function:
- executor_type (poolmgr/newdeploy/container)
- function_timeout, idle_timeout
- min_scale, max_scale для ExecutionStrategy
Все 21 тест пройден. Обратная совместимость проверена.
Документация: doc/AUDIT_PROVIDER_VS_FISSION_2026-06-03.md
18 KiB
Аудит: Terraform Provider vs Fission Canonical CRD
Дата: 2026-06-03
Ветка: feat/provider-audit
Предыдущая версия: v0.2.4 (ветка feat/console)
Методология
Сравнение производилось по трём источникам:
- Наш код —
/terraform/provider/internal/resources/*.goи/terraform/provider/internal/client/client.go - Fission CRD types.go —
github.com/fission/fission/pkg/apis/core/v1/types.go(канонические Go-структуры) - Реальные CRD объекты в кластере —
kubectl getдля environments/packages/functions/httptriggers (наши vs CLI-созданные)
1. ENVIRONMENT (fission_environment)
1.1 Что у нас
// environmentResourceModel
ID, Name, Image, Version(default=3), PoolSize(default=3), Namespace, UID
environmentToUnstructured генерирует:
{
"spec": {
"version": 3,
"runtime": { "image": "..." },
"poolsize": 3
}
}
1.2 Что делает Fission CLI (fission env create)
Fission CLI (из environment/create.go) создает полный EnvironmentSpec:
{
"spec": {
"version": 3,
"runtime": {
"image": "ghcr.io/fission/python-env",
"container": { "name": "env-name", "resources": {} },
"podspec": { "containers": [{"name": "env-name", "resources": {}}] }
},
"builder": {
"image": "ghcr.io/fission/go-builder",
"command": "build",
"container": { "name": "builder", "resources": {} },
"podspec": { "containers": [{"name": "builder", "resources": {}}] }
},
"poolsize": 3,
"resources": {},
"imagepullsecret": "",
"keeparchive": false
}
}
1.3 Реальное сравнение в кластере
| Поле | Наш (tf-python-env) | CLI (python) | Вердикт |
|---|---|---|---|
spec.version |
3 | 3 | ✅ OK |
spec.runtime.image |
✅ | ✅ | ✅ OK |
spec.runtime.container |
❌ отсутствует | {name, resources} |
⚠️ Fission заполняет defaults — не критично |
spec.runtime.podspec |
❌ отсутствует | {containers} |
⚠️ Fission заполняет defaults — не критично |
spec.builder |
❌ ОТСУТСТВУЕТ | {image, command, container, podspec} |
🔴 КРИТИЧНО для Go |
spec.poolsize |
3 | 3 | ✅ OK |
spec.resources |
❌ отсутствует | {} |
⚠️ Defaults — не критично |
spec.imagepullsecret |
❌ | "" |
⚠️ Можно добавить позже |
spec.keeparchive |
❌ | false |
⚠️ Нужно для JVM — не критично сейчас |
1.4 Выводы по Environment
Критичный баг: Невозможно создать environment с builder (нет полей builder_image, builder_command). Это блокирует Go, любой язык с build step.
Что добавить (приоритетно):
builder_image(string, optional) →spec.builder.imagebuilder_command(string, optional) →spec.builder.command
Что можно добавить позже:
resources(object) →spec.resourcesimagepullsecret(string) →spec.imagepullsecretkeeparchive(bool) →spec.keeparchiveruntime_container_name— Fission автозаполняет, мы не ставим, k8s принимает без него
Что НЕ нужно (Fission автозаполняет):
spec.runtime.container,spec.runtime.podspec— заливаются defaults на стороне сервераspec.builder.container,spec.builder.podspec— аналогично
2. PACKAGE (fission_package)
2.1 Что у нас
// packageResourceModel
ID, Name, Environment, SourceDir, CodePath, CodeHash, BuildCmd, Namespace, UID, BuildStatus, BuildLog
packageToUnstructured генерирует:
{
"spec": {
"deployment": {
"type": "literal",
"literal": "base64..."
},
"environment": { "name": "...", "namespace": "..." },
"source": {}
}
}
2.2 Что делает Fission CLI
Для deploy-only (literal):
{
"spec": {
"deployment": {
"type": "literal",
"literal": "base64...",
"checksum": {}
},
"environment": { "name": "...", "namespace": "..." },
"source": { "checksum": {} }
},
"status": {
"buildstatus": "none"
}
}
Для source-with-builder (Go, Node с build):
{
"spec": {
"source": {
"type": "literal",
"literal": "base64-of-zip...",
"checksum": {}
},
"environment": { "name": "...", "namespace": "..." },
"buildcmd": "build"
},
"status": {
"buildstatus": "pending"
}
}
Для large archives (>256KB):
- Загрузка через StorageSvc
/v1/archive(multipart POST) - В CRD сохраняется
type: "url",url: "http://storagesvc/v1/archive?id=..."
2.3 Реальное сравнение в кластере
| Поле | Наш (tf-hello-pkg) | CLI (hello-*) | Вердикт |
|---|---|---|---|
spec.deployment.type |
"literal" |
"literal" |
✅ OK |
spec.deployment.literal |
✅ base64 | ✅ base64 | ✅ OK |
spec.deployment.checksum |
❌ отсутствует | {} |
⚠️ K8s принимает без, но лучше добавить |
spec.environment |
✅ | ✅ | ✅ OK |
spec.source |
{} (пустая map) |
{"checksum":{}} |
🟡 БАГ: мы ставим пустой source — не мешает, но мусор |
spec.buildcmd |
✅ (если задан) | ✅ | ✅ OK |
status.buildstatus |
"none" (от k8s default) |
"none" |
✅ OK (k8s сам ставит) |
2.4 Что ОТСУТСТВУЕТ для builder pipeline (Go)
Для Go-функций нужен source package (не deployment):
- Код упаковывается в zip
- zip кодируется в base64 →
spec.source.literal(если <256KB) spec.source.type="literal"spec.deployment= пустоspec.buildcmd="build"(или пользовательская)status.buildstatus="pending"→ builder собирает →"succeeded"/"failed"- После build:
spec.deploymentзаполняется builder'ом (url на StorageSvc)
2.5 Выводы по Package
Баг (некритичный): Мы ВСЕГДА ставим "source": {} — пустой объект. Fission ставит "source": {"checksum": {}}. Оба варианта работают, но чистый вариант — не ставить source вообще если нет source archive.
Что добавить (приоритетно):
- Режим source archive — для Go и языков с build step. Нужно:
- Флаг/переключатель: deployment-only vs source-with-build
- Упаковка source_dir в zip → base64 →
spec.source.literal - Проверка размера <256KB (лимит ArchiveLiteralSizeLimit)
- Очистка
spec.deploymentпри source mode status.buildstatus="pending"на create
Что можно добавить позже:
- StorageSvc загрузка для >256KB архивов
spec.source.checksum- Поддержка
type: "url"(для уже загруженных архивов)
3. FUNCTION (fission_function)
3.1 Что у нас
// functionResourceModel
ID, Name, Environment, PackageName, Entrypoint, Namespace, UID
functionToUnstructured генерирует:
{
"spec": {
"environment": { "name": "...", "namespace": "..." },
"InvokeStrategy": {
"ExecutionStrategy": { "ExecutorType": "poolmgr" },
"StrategyType": "execution"
},
"package": {
"packageref": { "name": "...", "namespace": "..." },
"functionName": "main.main"
}
}
}
3.2 Что делает Fission CLI (fission fn create)
{
"spec": {
"environment": { "name": "...", "namespace": "..." },
"InvokeStrategy": {
"ExecutionStrategy": {
"ExecutorType": "poolmgr",
"MaxScale": 0,
"MinScale": 0,
"SpecializationTimeout": 120,
"TargetCPUPercent": 0
},
"StrategyType": "execution"
},
"package": {
"packageref": {
"name": "...",
"namespace": "...",
"resourceversion": "6000598"
},
"functionName": ""
},
"functionTimeout": 60,
"idletimeout": 120,
"concurrency": 500,
"requestsPerPod": 1,
"resources": {}
}
}
3.3 Реальное сравнение в кластере
| Поле | Наш (tf-hello-fn) | CLI (fn-js-acc) | Вердикт |
|---|---|---|---|
spec.environment |
✅ | ✅ | ✅ OK |
spec.InvokeStrategy.ExecutionStrategy.ExecutorType |
"poolmgr" |
"poolmgr" |
✅ OK |
spec.InvokeStrategy.ExecutionStrategy.MaxScale |
❌ отсутствует | 0 |
⚠️ Defaults работают, но лучше ставить |
spec.InvokeStrategy.ExecutionStrategy.MinScale |
❌ | 0 |
⚠️ |
spec.InvokeStrategy.ExecutionStrategy.SpecializationTimeout |
❌ | 120 |
⚠️ |
spec.InvokeStrategy.ExecutionStrategy.TargetCPUPercent |
❌ | 0 |
⚠️ Не критично |
spec.InvokeStrategy.StrategyType |
"execution" |
"execution" |
✅ OK |
spec.package.packageref.resourceversion |
❌ отсутствует | ✅ | 🟡 CLI ставит для оптимизации, мы — нет |
spec.package.functionName |
✅ "main.main" |
"" (или функция) |
✅ OK |
spec.functionTimeout |
❌ | 60 |
🟡 Полезно для управления таймаутами |
spec.idletimeout |
❌ | 120 |
🟡 Полезно для scale-to-zero |
spec.concurrency |
❌ | 500 |
⚠️ |
spec.requestsPerPod |
❌ | 1 |
⚠️ |
spec.resources |
❌ | {} |
⚠️ |
3.4 Выводы по Function
Критичных багов нет. Наши функции работают, потому что k8s/Fission подставляет defaults. НО:
Что добавить (приоритетно):
executor_type(string, optional, default="poolmgr") → для newdeploy/container strategiesfunction_timeout(int, optional) →spec.functionTimeout— важно для долгих функцийidle_timeout(int, optional) →spec.idletimeout— управление scale-to-zeromin_scale/max_scale(int, optional) → ExecutionStrategy — для newdeploy
Что можно добавить позже:
concurrency(int) →spec.concurrencyrequests_per_pod(int) →spec.requestsPerPodspecialization_timeout(int) →spec.InvokeStrategy.ExecutionStrategy.SpecializationTimeoutresources(object) → CPU/MEM limitssecrets,configmaps(list) → volume mounts
4. HTTP TRIGGER (fission_http_trigger)
4.1 Что у нас
// httpTriggerResourceModel
ID, Name, Function, URL, Methods, CreateIngress, Host, Namespace, UID
httpTriggerToUnstructured генерирует:
{
"spec": {
"relativeurl": "/tf-hello",
"methods": ["GET"],
"functionref": { "type": "name", "name": "tf-hello-fn" },
"createingress": false
}
}
4.2 Что делает Fission CLI
{
"spec": {
"relativeurl": "/hello",
"methods": ["GET"],
"functionref": {
"type": "name",
"name": "hello",
"functionweights": null
},
"createingress": false,
"host": "",
"ingressconfig": {
"annotations": null,
"host": "*",
"path": "/hello",
"tls": ""
},
"method": "",
"prefix": ""
}
}
4.3 Реальное сравнение в кластере
| Поле | Наш (tf-hello-route) | CLI (hello-route) | Вердикт |
|---|---|---|---|
spec.relativeurl |
✅ | ✅ | ✅ OK |
spec.methods |
✅ | ✅ | ✅ OK |
spec.functionref.type |
"name" |
"name" |
✅ OK |
spec.functionref.name |
✅ | ✅ | ✅ OK |
spec.functionref.functionweights |
❌ | null |
✅ Не нужно |
spec.createingress |
✅ | ✅ | ✅ OK |
spec.host |
❌ (если пусто) | "" |
✅ Не критично |
spec.ingressconfig |
Частично (host) | Полный | ⚠️ IngressConfig неполный |
spec.method |
❌ | "" |
✅ Legacy, не нужно |
spec.prefix |
❌ | "" |
⚠️ Для prefix routing — добавить |
4.4 Выводы по HTTPTrigger
Багов нет. Работает корректно. Мелкие расхождения не влияют.
Что можно добавить позже:
prefix(string) →spec.prefix— для prefix-based routingkeep_prefix(bool) →spec.keepPrefix- Полный
ingressconfig(annotations, path, tls) — приcreate_ingress=true function_weights(map) → для canary deployments
5. CLIENT (client.go)
5.1 Оценка
Код корректный. Чистый CRUD через dynamic.Interface:
- 4 GVR определения (environments, packages, functions, httptriggers)
- CRUD для каждого: Create/Get/Update/Delete
IsNotFound()для обработки 404New()строит config из kubeconfig + context
Расхождений с Fission нет — это наш собственный low-level клиент для работы с CRD.
6. VALIDATION (validation_helpers.go, entrypoint validation)
6.1 Оценка
ensureEnvironmentExists— ✅ корректно (проверяет наличие env перед созданием pkg/fn)ensurePackageExists— ✅ корректноvalidateEntrypointAgainstPackageSource— ⚠️ Проверяет только Pythondef funcname(. Не проверяет:- Node:
module.exportsилиexport function - Go: plugin symbol
- PHP:
function handler( - Ruby:
def handler
- Node:
Это допустимо — избыточная валидация может мешать. Лучше валидировать только точно известные паттерны.
7. СВОДНАЯ ТАБЛИЦА ПРИОРИТЕТОВ
🔴 Критично (блокирует функционал)
| # | Ресурс | Проблема | Решение |
|---|---|---|---|
| 1 | Environment | Нет builder support | Добавить builder_image, builder_command |
| 2 | Package | Нет source archive mode | Добавить zip-упаковку source_dir → spec.source.literal |
🟡 Важно (улучшает пользовательский опыт)
| # | Ресурс | Проблема | Решение |
|---|---|---|---|
| 3 | Function | Захардкожен poolmgr | Добавить executor_type с optional default |
| 4 | Function | Нет пользовательских таймаутов | Добавить function_timeout, idle_timeout |
| 5 | Function | Нет min/max scale | Добавить min_scale, max_scale |
| 6 | Package | Пустой source: {} мусор |
Убрать пустой source из payload |
⚪ Не критично (можно позже)
| # | Ресурс | Проблема |
|---|---|---|
| 7 | Environment | Нет resources, imagepullsecret, keeparchive |
| 8 | Function | Нет concurrency, requestsPerPod, resources, secrets, configmaps |
| 9 | HTTPTrigger | Нет prefix, keepPrefix, полного ingressconfig |
| 10 | Package | Нет StorageSvc загрузки (>256KB) |
| 11 | Package | Нет checksum |
8. ПЛАН РЕАЛИЗАЦИИ (предлагаемый)
Этап 1: Builder support (Environment + Package)
environment_resource.go:
- Добавить поля
builder_imageиbuilder_commandв модель и schema - Добавить
spec.builderвenvironmentToUnstructured(если builder_image задан) - Обновить
unstructuredToEnvironmentModelдля чтения builder полей
package_resource.go:
- Добавить поле
deploy_type(string:"literal"или"source", default"literal") - При
deploy_type = "source": zip source_dir → base64 →spec.source.literal,spec.deploymentпустой - Убрать пустой
"source": {}при deploy_type = "literal" - Добавить base64 size check (<256KB) при literal mode
Этап 2: Function tuning
function_resource.go:
- Добавить optional поля:
executor_type,function_timeout,idle_timeout,min_scale,max_scale - Обновить
functionToUnstructuredдля заполнения ExecutionStrategy полностью - Обновить
unstructuredToFunctionModelдля чтения новых полей
Этап 3: Мелкие улучшения
- HTTPTrigger: prefix, keepPrefix
- Package: checksum
- Environment: resources, imagepullsecret
9. ВЫВОД
Наш провайдер работает корректно для основного сценария: Python/Node/PHP/Ruby/Perl literal deployment + poolmgr executor. Все критические поля (version, runtime.image, poolsize, deployment.literal, functionName, relativeurl, methods) генерируются правильно.
Главные пробелы:
- Нет builder support → Go и любые compiled languages не работают через builder pipeline
- Нет source archive → только deployment-only (literal из одного файла)
- Function executor hardcoded to poolmgr → нет newdeploy/container strategy
- Нет пользовательских таймаутов
Ни один из пробелов не является ошибкой в существующем коде — это недостающий функционал. То, что есть, соответствует канону Fission.