fix(api): DELETE несуществующего ресурса — 404 вместо 204 (function/service/trigger/job)
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
# Состав:
|
# Состав:
|
||||||
# - ConfigMap: не-секретные env vars (S3_ENDPOINT, REGISTRY_HOST и т.д.)
|
# - ConfigMap: не-секретные env vars (S3_ENDPOINT, REGISTRY_HOST и т.д.)
|
||||||
# - Secret: секретные данные (S3 keys, postgres DSN, API token, Harbor pass)
|
# - 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)
|
# - Service: ClusterIP :9090 (REST API)
|
||||||
# - Ingress: sless.kube5s.ru → :9090 (внешний доступ с TLS)
|
# - Ingress: sless.kube5s.ru → :9090 (внешний доступ с TLS)
|
||||||
#
|
#
|
||||||
@@ -74,7 +74,7 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: operator
|
- name: operator
|
||||||
# При обновлении версии оператора — менять тег здесь (не latest!)
|
# При обновлении версии оператора — менять тег здесь (не 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 — чтобы всегда тянуть по точному тегу (не кешировать старый)
|
# Always — чтобы всегда тянуть по точному тегу (не кешировать старый)
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Изменено: 2026-03-18 (добавлены created_at, last_built_at в functionResponse и fnToResponse)
|
// Изменено: 2026-03-18 (добавлены created_at, last_built_at в functionResponse и fnToResponse)
|
||||||
|
// Изменено: 2026-03-21 (fix: DeleteFunction возвращает 404 вместо 204 при отсутствующем объекте)
|
||||||
// functions.go — CRUD handlers для Function CRD.
|
// functions.go — CRUD handlers для Function CRD.
|
||||||
// Принимает JSON, создаёт/обновляет/удаляет k8s ресурсы Function.
|
// Принимает JSON, создаёт/обновляет/удаляет k8s ресурсы Function.
|
||||||
// Namespace берётся из URL: /v1/namespaces/{namespace}/functions/{name}
|
// Namespace берётся из URL: /v1/namespaces/{namespace}/functions/{name}
|
||||||
@@ -30,24 +31,24 @@ type functionRequest struct {
|
|||||||
|
|
||||||
// functionResponse — ответ при чтении функции.
|
// functionResponse — ответ при чтении функции.
|
||||||
type functionResponse struct {
|
type functionResponse struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Namespace string `json:"namespace"`
|
Namespace string `json:"namespace"`
|
||||||
Runtime string `json:"runtime"`
|
Runtime string `json:"runtime"`
|
||||||
Entrypoint string `json:"entrypoint"`
|
Entrypoint string `json:"entrypoint"`
|
||||||
MemoryMB int32 `json:"memory_mb"`
|
MemoryMB int32 `json:"memory_mb"`
|
||||||
TimeoutSec int32 `json:"timeout_sec"`
|
TimeoutSec int32 `json:"timeout_sec"`
|
||||||
Env map[string]string `json:"env_vars"`
|
Env map[string]string `json:"env_vars"`
|
||||||
S3Bucket string `json:"s3_bucket"`
|
S3Bucket string `json:"s3_bucket"`
|
||||||
S3Key string `json:"s3_key"`
|
S3Key string `json:"s3_key"`
|
||||||
Phase slessv1alpha1.FunctionPhase `json:"phase"`
|
Phase slessv1alpha1.FunctionPhase `json:"phase"`
|
||||||
ImageRef string `json:"image_ref"`
|
ImageRef string `json:"image_ref"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
// CreatedAt — время создания CRD объекта (metadata.creationTimestamp).
|
// CreatedAt — время создания CRD объекта (metadata.creationTimestamp).
|
||||||
// Пустое значение = "0001-01-01T00:00:00Z" сериализуется в "", опускаем через omitempty.
|
// Пустое значение = "0001-01-01T00:00:00Z" сериализуется в "", опускаем через omitempty.
|
||||||
CreatedAt string `json:"created_at,omitempty"`
|
CreatedAt string `json:"created_at,omitempty"`
|
||||||
// LastBuiltAt — время последней успешной сборки образа (status.lastBuiltAt).
|
// LastBuiltAt — время последней успешной сборки образа (status.lastBuiltAt).
|
||||||
// nil если сборки ещё не было.
|
// nil если сборки ещё не было.
|
||||||
LastBuiltAt string `json:"last_built_at,omitempty"`
|
LastBuiltAt string `json:"last_built_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// fnToResponse конвертирует CRD в ответ API.
|
// fnToResponse конвертирует CRD в ответ API.
|
||||||
@@ -233,7 +234,7 @@ func (h *Handler) DeleteFunction(w http.ResponseWriter, r *http.Request) {
|
|||||||
fn := &slessv1alpha1.Function{}
|
fn := &slessv1alpha1.Function{}
|
||||||
if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, fn); err != nil {
|
if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, fn); err != nil {
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
writeJSON(w, http.StatusNotFound, errResp("function not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Изменено: 2026-03-20 (merge: FunctionJob теперь самодостаточен — убран FunctionRef, добавлены Runtime/Entrypoint/Env)
|
// Изменено: 2026-03-20 (merge: FunctionJob теперь самодостаточен — убран FunctionRef, добавлены Runtime/Entrypoint/Env)
|
||||||
|
// Изменено: 2026-03-21 (fix: DeleteJob возвращает 404 вместо 204 при отсутствующем объекте)
|
||||||
// jobs.go — CRUD handlers для FunctionJob CRD.
|
// jobs.go — CRUD handlers для FunctionJob CRD.
|
||||||
// Создаёт/читает/удаляет k8s FunctionJob ресурсы.
|
// Создаёт/читает/удаляет k8s FunctionJob ресурсы.
|
||||||
// Namespace берётся из URL: /v1/namespaces/{namespace}/jobs/{name}
|
// 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
|
var job slessv1alpha1.FunctionJob
|
||||||
if err := h.K8s.Get(r.Context(), client.ObjectKey{Namespace: ns, Name: name}, &job); err != nil {
|
if err := h.K8s.Get(r.Context(), client.ObjectKey{Namespace: ns, Name: name}, &job); err != nil {
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
writeJSON(w, http.StatusNotFound, errResp("job not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.Log.Error("get FunctionJob for delete", "err", err)
|
h.Log.Error("get FunctionJob for delete", "err", err)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Создано: 2026-03-20 (function-service-split)
|
// Создано: 2026-03-20 (function-service-split)
|
||||||
|
// Изменено: 2026-03-21 (fix: DeleteService возвращает 404 вместо 204 при отсутствующем объекте)
|
||||||
// services.go — CRUD handlers для Service CRD (sless_service).
|
// services.go — CRUD handlers для Service CRD (sless_service).
|
||||||
// sless_service = long-running Deployment + URL. Каждый вызов проксируется к поду.
|
// sless_service = long-running Deployment + URL. Каждый вызов проксируется к поду.
|
||||||
// Namespace берётся из URL: /v1/namespaces/{namespace}/services/{name}
|
// Namespace берётся из URL: /v1/namespaces/{namespace}/services/{name}
|
||||||
@@ -228,7 +229,7 @@ func (h *Handler) DeleteService(w http.ResponseWriter, r *http.Request) {
|
|||||||
svc := &slessv1alpha1.Service{}
|
svc := &slessv1alpha1.Service{}
|
||||||
if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, svc); err != nil {
|
if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, svc); err != nil {
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
writeJSON(w, http.StatusNotFound, errResp("service not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Изменено: 2026-03-08
|
// Изменено: 2026-03-08
|
||||||
|
// Изменено: 2026-03-21 (fix: DeleteTrigger возвращает 404 вместо 204 при отсутствующем объекте)
|
||||||
// triggers.go — CRUD handlers для Trigger CRD.
|
// triggers.go — CRUD handlers для Trigger CRD.
|
||||||
// Триггеры привязаны к Function через FunctionRef.
|
// Триггеры привязаны к Function через FunctionRef.
|
||||||
// Namespace берётся из URL: /v1/namespaces/{namespace}/triggers/{name}
|
// Namespace берётся из URL: /v1/namespaces/{namespace}/triggers/{name}
|
||||||
@@ -140,7 +141,7 @@ func (h *Handler) DeleteTrigger(w http.ResponseWriter, r *http.Request) {
|
|||||||
tr := &slessv1alpha1.Trigger{}
|
tr := &slessv1alpha1.Trigger{}
|
||||||
if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, tr); err != nil {
|
if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, tr); err != nil {
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
writeJSON(w, http.StatusNotFound, errResp("trigger not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
||||||
|
|||||||
Reference in New Issue
Block a user