From e8d0d78310632ac5f0d4acb24aa518cc819ce6b9 Mon Sep 17 00:00:00 2001 From: Naeel Date: Sat, 21 Mar 2026 06:45:55 +0300 Subject: [PATCH] =?UTF-8?q?fix(api):=20DELETE=20=D0=BD=D0=B5=D1=81=D1=83?= =?UTF-8?q?=D1=89=D0=B5=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B5=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=80=D0=B5=D1=81=D1=83=D1=80=D1=81=D0=B0=20=E2=80=94?= =?UTF-8?q?=20404=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20204=20(function?= =?UTF-8?q?/service/trigger/job)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deployments/k8s/operator.yaml | 4 ++-- internal/api/handler/functions.go | 31 ++++++++++++++++--------------- internal/api/handler/jobs.go | 3 ++- internal/api/handler/services.go | 3 ++- internal/api/handler/triggers.go | 3 ++- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/deployments/k8s/operator.yaml b/deployments/k8s/operator.yaml index 551c3e2..e0d3490 100644 --- a/deployments/k8s/operator.yaml +++ b/deployments/k8s/operator.yaml @@ -3,7 +3,7 @@ # Состав: # - ConfigMap: не-секретные env vars (S3_ENDPOINT, REGISTRY_HOST и т.д.) # - Secret: секретные данные (S3 keys, postgres DSN, API token, Harbor pass) -# - Deployment: оператор naeel/sless-operator:v0.1.33 в namespace sless +# - Deployment: оператор naeel/sless-operator:v0.1.44 в namespace sless # - Service: ClusterIP :9090 (REST API) # - Ingress: sless.kube5s.ru → :9090 (внешний доступ с TLS) # @@ -74,7 +74,7 @@ spec: containers: - name: operator # При обновлении версии оператора — менять тег здесь (не latest!) - image: pearlharbor.registryk8s.services.ngcloud.ru/naeel/sless-operator:v0.1.43 + image: pearlharbor.registryk8s.services.ngcloud.ru/naeel/sless-operator:v0.1.44 # Always — чтобы всегда тянуть по точному тегу (не кешировать старый) imagePullPolicy: Always ports: diff --git a/internal/api/handler/functions.go b/internal/api/handler/functions.go index c1770de..8d1d25b 100644 --- a/internal/api/handler/functions.go +++ b/internal/api/handler/functions.go @@ -1,4 +1,5 @@ // Изменено: 2026-03-18 (добавлены created_at, last_built_at в functionResponse и fnToResponse) +// Изменено: 2026-03-21 (fix: DeleteFunction возвращает 404 вместо 204 при отсутствующем объекте) // functions.go — CRUD handlers для Function CRD. // Принимает JSON, создаёт/обновляет/удаляет k8s ресурсы Function. // Namespace берётся из URL: /v1/namespaces/{namespace}/functions/{name} @@ -30,24 +31,24 @@ type functionRequest struct { // functionResponse — ответ при чтении функции. type functionResponse struct { - Name string `json:"name"` - Namespace string `json:"namespace"` - Runtime string `json:"runtime"` - Entrypoint string `json:"entrypoint"` - MemoryMB int32 `json:"memory_mb"` - TimeoutSec int32 `json:"timeout_sec"` - Env map[string]string `json:"env_vars"` - S3Bucket string `json:"s3_bucket"` - S3Key string `json:"s3_key"` - Phase slessv1alpha1.FunctionPhase `json:"phase"` - ImageRef string `json:"image_ref"` - Message string `json:"message,omitempty"` + Name string `json:"name"` + Namespace string `json:"namespace"` + Runtime string `json:"runtime"` + Entrypoint string `json:"entrypoint"` + MemoryMB int32 `json:"memory_mb"` + TimeoutSec int32 `json:"timeout_sec"` + Env map[string]string `json:"env_vars"` + S3Bucket string `json:"s3_bucket"` + S3Key string `json:"s3_key"` + Phase slessv1alpha1.FunctionPhase `json:"phase"` + ImageRef string `json:"image_ref"` + Message string `json:"message,omitempty"` // CreatedAt — время создания CRD объекта (metadata.creationTimestamp). // Пустое значение = "0001-01-01T00:00:00Z" сериализуется в "", опускаем через omitempty. - CreatedAt string `json:"created_at,omitempty"` + CreatedAt string `json:"created_at,omitempty"` // LastBuiltAt — время последней успешной сборки образа (status.lastBuiltAt). // nil если сборки ещё не было. - LastBuiltAt string `json:"last_built_at,omitempty"` + LastBuiltAt string `json:"last_built_at,omitempty"` } // fnToResponse конвертирует CRD в ответ API. @@ -233,7 +234,7 @@ func (h *Handler) DeleteFunction(w http.ResponseWriter, r *http.Request) { fn := &slessv1alpha1.Function{} if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, fn); err != nil { if errors.IsNotFound(err) { - w.WriteHeader(http.StatusNoContent) + writeJSON(w, http.StatusNotFound, errResp("function not found")) return } writeJSON(w, http.StatusInternalServerError, errResp(err.Error())) diff --git a/internal/api/handler/jobs.go b/internal/api/handler/jobs.go index 251b512..42bc286 100644 --- a/internal/api/handler/jobs.go +++ b/internal/api/handler/jobs.go @@ -1,4 +1,5 @@ // Изменено: 2026-03-20 (merge: FunctionJob теперь самодостаточен — убран FunctionRef, добавлены Runtime/Entrypoint/Env) +// Изменено: 2026-03-21 (fix: DeleteJob возвращает 404 вместо 204 при отсутствующем объекте) // jobs.go — CRUD handlers для FunctionJob CRD. // Создаёт/читает/удаляет k8s FunctionJob ресурсы. // Namespace берётся из URL: /v1/namespaces/{namespace}/jobs/{name} @@ -159,7 +160,7 @@ func (h *Handler) DeleteJob(w http.ResponseWriter, r *http.Request) { var job slessv1alpha1.FunctionJob if err := h.K8s.Get(r.Context(), client.ObjectKey{Namespace: ns, Name: name}, &job); err != nil { if errors.IsNotFound(err) { - w.WriteHeader(http.StatusNoContent) + writeJSON(w, http.StatusNotFound, errResp("job not found")) return } h.Log.Error("get FunctionJob for delete", "err", err) diff --git a/internal/api/handler/services.go b/internal/api/handler/services.go index 6ad5c00..5a71678 100644 --- a/internal/api/handler/services.go +++ b/internal/api/handler/services.go @@ -1,4 +1,5 @@ // Создано: 2026-03-20 (function-service-split) +// Изменено: 2026-03-21 (fix: DeleteService возвращает 404 вместо 204 при отсутствующем объекте) // services.go — CRUD handlers для Service CRD (sless_service). // sless_service = long-running Deployment + URL. Каждый вызов проксируется к поду. // Namespace берётся из URL: /v1/namespaces/{namespace}/services/{name} @@ -228,7 +229,7 @@ func (h *Handler) DeleteService(w http.ResponseWriter, r *http.Request) { svc := &slessv1alpha1.Service{} if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, svc); err != nil { if errors.IsNotFound(err) { - w.WriteHeader(http.StatusNoContent) + writeJSON(w, http.StatusNotFound, errResp("service not found")) return } writeJSON(w, http.StatusInternalServerError, errResp(err.Error())) diff --git a/internal/api/handler/triggers.go b/internal/api/handler/triggers.go index b772d54..1b081b2 100644 --- a/internal/api/handler/triggers.go +++ b/internal/api/handler/triggers.go @@ -1,4 +1,5 @@ // Изменено: 2026-03-08 +// Изменено: 2026-03-21 (fix: DeleteTrigger возвращает 404 вместо 204 при отсутствующем объекте) // triggers.go — CRUD handlers для Trigger CRD. // Триггеры привязаны к Function через FunctionRef. // Namespace берётся из URL: /v1/namespaces/{namespace}/triggers/{name} @@ -140,7 +141,7 @@ func (h *Handler) DeleteTrigger(w http.ResponseWriter, r *http.Request) { tr := &slessv1alpha1.Trigger{} if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, tr); err != nil { if errors.IsNotFound(err) { - w.WriteHeader(http.StatusNoContent) + writeJSON(w, http.StatusNotFound, errResp("trigger not found")) return } writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))