diff --git a/doc/errors/log.md b/doc/errors/log.md index 1b0af1a..009b49f 100644 --- a/doc/errors/log.md +++ b/doc/errors/log.md @@ -4,6 +4,85 @@ --- +## 2026-03-21 — БАГ: memory_mb через PUT не применяется в k8s Deployment (НЕ ИСПРАВЛЕН) + +### Симптом + +``` +PUT /v1/namespaces/sless-xxx/services/my-svc +{ "memory_mb": 256, ... } +→ HTTP 200 OK + +kubectl get deployment my-svc -n sless-fn-xxx + containers[0].resources.limits.memory: 128Mi ← было 128, осталось 128 +``` + +### Причина + +`controllers/service_controller.go:ensureServiceDeployment` при UPDATE существующего Deployment обновляет только два поля: +```go +existing.Spec.Template.Spec.Containers[0].Image = svc.Status.ImageRef +existing.Spec.Template.Spec.Containers[0].Env = desired.Spec.Template.Spec.Containers[0].Env +// Resources (memory limit) НЕ обновляется! +``` +`desired` Deployment строится с правильным `memory_mb`, но в `existing` он не копируется. + +### Фикс (не применён) + +```go +// В ensureServiceDeployment, блок else (UPDATE): +existing.Spec.Template.Spec.Containers[0].Image = svc.Status.ImageRef +existing.Spec.Template.Spec.Containers[0].Env = desired.Spec.Template.Spec.Containers[0].Env +existing.Spec.Template.Spec.Containers[0].Resources = desired.Spec.Template.Spec.Containers[0].Resources // ← ДОБАВИТЬ +existing.Spec.Template.Spec.ImagePullSecrets = desired.Spec.Template.Spec.ImagePullSecrets +``` + +### Файл + +`controllers/service_controller.go` ~ строка 241 + +### Обнаружен + +`operator_lifecycle_test.sh`, тест 2.13 + +--- + +## 2026-03-21 — БАГ: нет self-healing — ручное удаление Deployment не восстанавливается (НЕ ИСПРАВЛЕН) + +### Симптом + +``` +kubectl delete deployment my-svc -n sless-fn-sless-xxx +# Deployment исчез. +# Ждём 90s — контроллер не пересоздаёт. +# GET /fn/sless-xxx/my-svc → 502 (pod отсутствует, CRD=Ready) +``` + +### Причина + +`ServiceReconciler` реагирует только на изменения объектов типа `Service` (sless CRD) в namespace `sless`. +Deployment живёт в `sless-fn-sless-xxx` — другой namespace. controller-runtime не допускает `Owns()` для cross-namespace ресурсов. +`ensureServiceDeployment` вызывается только когда `phase=Ready` И пришёл reconcile event (=изменение CRD). Просто удалённый Deployment event не генерирует. + +### Фикс (вариант) + +Добавить `RequeueAfter: 60s` в `ensureServiceDeployment` — тогда контроллер будет периодически проверять и пересоздавать: +```go +// В конце ensureServiceDeployment: +return ctrl.Result{RequeueAfter: 60 * time.Second}, nil +``` +Или использовать `Watches()` с cross-namespace mapper (сложнее). + +### Файл + +`controllers/service_controller.go` ~ строка 340 + +### Обнаружен + +`operator_lifecycle_test.sh`, тест 3.2 + +--- + ## 2026-03-21 — Баг: DELETE несуществующего ресурса → HTTP 204 вместо 404 ### Симптом diff --git a/doc/progress.md b/doc/progress.md index 0250a3c..33487c9 100644 --- a/doc/progress.md +++ b/doc/progress.md @@ -1,6 +1,43 @@ # Прогресс разработки -Последнее обновление: 2026-03-21 (operator v0.1.48 — timeout_sec: 0 = нет лимита; валидация 1–900; Terraform state = null при отсутствии лимита) +Последнее обновление: 2026-03-21 (operator_lifecycle_test.sh — 44/44 PASS; 2 бага оператора найдены) + +--- + +## 2026-03-21 — Сессия 5: lifecycle-тест оператора — 44/44 PASS; 2 бага + +### Что сделано + +| # | Компонент | Результат | +|---|-----------|-----------| +| 1 | `operator_lifecycle_test.sh` — 44 теста жизненного цикла | ✅ 44/44 PASS | +| 2 | Найден БАГ 1: `memory_mb` через PUT не применяется в k8s | ⚠️ зафиксировано | +| 3 | Найден БАГ 2: нет self-healing при ручном удалении Deployment | ⚠️ зафиксировано | + +### Структура теста (operator_lifecycle_test.sh) + +| Группа | Что тестируется | Тестов | +|--------|----------------|--------| +| 1 (API validation) | `memory_mb=0/5000` → 400; `timeout_sec=-1/901` → 400; без runtime → 400; GET/PUT/DELETE несущ. → 404 | 8 | +| 2 (Full lifecycle solo) | create→upload→build→ready→invoke→env update→k8s verify→memory update→timeout→delete→k8s cleanup | 18 | +| 3 (Edge cases) | DELETE while Building (kaniko убит, Deployment не создан); Reconcile (self-healing) | 10 | +| 4 (Multi parallel) | 3 функции параллельно; delete одной в Building; 2 дошли до Ready; 40 parallel invoke | 8 | + +### Найденные баги оператора + +| # | Баг | Место | Суть | +|---|-----|-------|------| +| 1 | `memory_mb` через PUT не применяется | `controllers/service_controller.go:ensureServiceDeployment` | При UPDATE обновляются только `Image` и `Env`. `Resources` (memory limit) не трогается — k8s Deployment хранит старое значение | +| 2 | Нет self-healing при удалении Deployment | `ServiceReconciler` | Если Deployment удалили вручную — контроллер не пересоздаёт. Нет cross-namespace watch (`sless-fn-*`) и нет `RequeueAfter`. Reconcile срабатывает только при изменении CRD | + +### Что НЕ упало (важно) + +- DELETE во время Building → CRD удалён, kaniko Job убит, Deployment не создан ✅ +- Duplicate create + Ready → 409 ✅ +- env_vars через PUT → k8s Deployment обновился, rollout OK, invoke вернул новое значение ✅ +- 3 параллельных build → все 3 независимы, delete одного не ломает остальные ✅ +- 40 параллельных invoke → 40/40 OK ✅ +- Финальный teardown → все lc-* сервисы удалены ✅ --- @@ -14,8 +51,8 @@ | 2 | `internal/api/handler/invoke.go` — убрать хардкод 35s дефолт | — | ✅ `TimeoutSec=0` → `&http.Client{}` (нет таймаута) | | 3 | `internal/api/handler/services.go` — валидация `timeout_sec` | — | ✅ `< 0` или `> 900` → HTTP 400 | | 4 | `terraform/provider/…/service_resource.go` — schema + svcToModel | — | ✅ `0` → `null` в Terraform state | -| 5 | Оператор Docker build v0.1.48 + push | operator | в процессе | -| 6 | kubectl rollout + rollout status | k8s | в процессе | +| 5 | Оператор Docker build v0.1.48 + push | operator | ✅ задеплоен, rollout OK | +| 6 | kubectl rollout + rollout status | k8s | ✅ | ### Изменения логики timeout_sec