Files
fission-console/doc/AUDIT_PROVIDER_VS_FISSION_2026-06-03.md
T
Naeel fd236d87ea feat: provider audit — builder support, function tuning, source archive
Аудит провайдера 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
2026-04-15 17:46:47 +03:00

474 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Аудит: Terraform Provider vs Fission Canonical CRD
**Дата:** 2026-06-03
**Ветка:** `feat/provider-audit`
**Предыдущая версия:** v0.2.4 (ветка `feat/console`)
## Методология
Сравнение производилось по трём источникам:
1. **Наш код**`/terraform/provider/internal/resources/*.go` и `/terraform/provider/internal/client/client.go`
2. **Fission CRD types.go**`github.com/fission/fission/pkg/apis/core/v1/types.go` (канонические Go-структуры)
3. **Реальные CRD объекты в кластере**`kubectl get` для environments/packages/functions/httptriggers (наши vs CLI-созданные)
---
## 1. ENVIRONMENT (fission_environment)
### 1.1 Что у нас
```go
// environmentResourceModel
ID, Name, Image, Version(default=3), PoolSize(default=3), Namespace, UID
```
`environmentToUnstructured` генерирует:
```json
{
"spec": {
"version": 3,
"runtime": { "image": "..." },
"poolsize": 3
}
}
```
### 1.2 Что делает Fission CLI (`fission env create`)
Fission CLI (из `environment/create.go`) создает полный `EnvironmentSpec`:
```json
{
"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.image`
- `builder_command` (string, optional) → `spec.builder.command`
**Что можно добавить позже:**
- `resources` (object) → `spec.resources`
- `imagepullsecret` (string) → `spec.imagepullsecret`
- `keeparchive` (bool) → `spec.keeparchive`
- `runtime_container_name` — Fission автозаполняет, мы не ставим, k8s принимает без него
**Что НЕ нужно (Fission автозаполняет):**
- `spec.runtime.container`, `spec.runtime.podspec` — заливаются defaults на стороне сервера
- `spec.builder.container`, `spec.builder.podspec` — аналогично
---
## 2. PACKAGE (fission_package)
### 2.1 Что у нас
```go
// packageResourceModel
ID, Name, Environment, SourceDir, CodePath, CodeHash, BuildCmd, Namespace, UID, BuildStatus, BuildLog
```
`packageToUnstructured` генерирует:
```json
{
"spec": {
"deployment": {
"type": "literal",
"literal": "base64..."
},
"environment": { "name": "...", "namespace": "..." },
"source": {}
}
}
```
### 2.2 Что делает Fission CLI
Для **deploy-only** (literal):
```json
{
"spec": {
"deployment": {
"type": "literal",
"literal": "base64...",
"checksum": {}
},
"environment": { "name": "...", "namespace": "..." },
"source": { "checksum": {} }
},
"status": {
"buildstatus": "none"
}
}
```
Для **source-with-builder** (Go, Node с build):
```json
{
"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):
1. Код упаковывается в zip
2. zip кодируется в base64 → `spec.source.literal` (если <256KB)
3. `spec.source.type` = `"literal"`
4. `spec.deployment` = пусто
5. `spec.buildcmd` = `"build"` (или пользовательская)
6. `status.buildstatus` = `"pending"` → builder собирает → `"succeeded"`/`"failed"`
7. После 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 Что у нас
```go
// functionResourceModel
ID, Name, Environment, PackageName, Entrypoint, Namespace, UID
```
`functionToUnstructured` генерирует:
```json
{
"spec": {
"environment": { "name": "...", "namespace": "..." },
"InvokeStrategy": {
"ExecutionStrategy": { "ExecutorType": "poolmgr" },
"StrategyType": "execution"
},
"package": {
"packageref": { "name": "...", "namespace": "..." },
"functionName": "main.main"
}
}
}
```
### 3.2 Что делает Fission CLI (`fission fn create`)
```json
{
"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 strategies
- `function_timeout` (int, optional) → `spec.functionTimeout` — важно для долгих функций
- `idle_timeout` (int, optional) → `spec.idletimeout` — управление scale-to-zero
- `min_scale` / `max_scale` (int, optional) → ExecutionStrategy — для newdeploy
**Что можно добавить позже:**
- `concurrency` (int) → `spec.concurrency`
- `requests_per_pod` (int) → `spec.requestsPerPod`
- `specialization_timeout` (int) → `spec.InvokeStrategy.ExecutionStrategy.SpecializationTimeout`
- `resources` (object) → CPU/MEM limits
- `secrets`, `configmaps` (list) → volume mounts
---
## 4. HTTP TRIGGER (fission_http_trigger)
### 4.1 Что у нас
```go
// httpTriggerResourceModel
ID, Name, Function, URL, Methods, CreateIngress, Host, Namespace, UID
```
`httpTriggerToUnstructured` генерирует:
```json
{
"spec": {
"relativeurl": "/tf-hello",
"methods": ["GET"],
"functionref": { "type": "name", "name": "tf-hello-fn" },
"createingress": false
}
}
```
### 4.2 Что делает Fission CLI
```json
{
"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 routing
- `keep_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()` для обработки 404
- `New()` строит config из kubeconfig + context
**Расхождений с Fission нет** — это наш собственный low-level клиент для работы с CRD.
---
## 6. VALIDATION (validation_helpers.go, entrypoint validation)
### 6.1 Оценка
- `ensureEnvironmentExists` — ✅ корректно (проверяет наличие env перед созданием pkg/fn)
- `ensurePackageExists` — ✅ корректно
- `validateEntrypointAgainstPackageSource` — ⚠️ Проверяет только Python `def funcname(`. Не проверяет:
- Node: `module.exports` или `export function`
- Go: plugin symbol
- PHP: `function handler(`
- Ruby: `def handler`
**Это допустимо** — избыточная валидация может мешать. Лучше валидировать только точно известные паттерны.
---
## 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) генерируются правильно.
**Главные пробелы:**
1. Нет builder support → Go и любые compiled languages не работают через builder pipeline
2. Нет source archive → только deployment-only (literal из одного файла)
3. Function executor hardcoded to poolmgr → нет newdeploy/container strategy
4. Нет пользовательских таймаутов
Ни один из пробелов не является **ошибкой** в существующем коде — это **недостающий функционал**. То, что есть, соответствует канону Fission.