feat: trigger.enabled + job.run_id lifecycle control (operator v0.1.6, provider v0.1.4)

- TriggerSpec.Enabled bool (default=true): enabled=false масштабирует Deployment до 0
- FunctionJobSpec.RunID int64 (default=0): run_id=0 = skip, >0 = run
- API: PATCH /v1/namespaces/{ns}/triggers/{name} (UpdateTrigger)
- Provider: enabled attribute (Optional, Computed, in-place update)
- Provider: run_id attribute (Optional, Computed, default=0, RequiresReplace)
- operator image: naeel/sless-operator:v0.1.6
- provider: terra.k8c.ru/naeel/sless v0.1.4
This commit is contained in:
“Naeel”
2026-03-08 10:10:32 +04:00
parent 8fb0ef5ea1
commit d67b9745a8
20 changed files with 509 additions and 143 deletions
+6 -1
View File
@@ -1,4 +1,4 @@
// Изменено: 2026-03-07
// Изменено: 2026-03-08
// jobs.go — CRUD handlers для FunctionJob CRD.
// Создаёт/читает/удаляет k8s FunctionJob ресурсы.
// Namespace берётся из URL: /v1/namespaces/{namespace}/jobs/{name}
@@ -21,6 +21,8 @@ type jobRequest struct {
Name string `json:"name"`
FunctionRef string `json:"function"`
EventJSON string `json:"event_json,omitempty"`
// RunID — идентификатор запуска. 0 = создать без запуска, >0 = запустить.
RunID int64 `json:"run_id"`
}
// jobResponse — ответ при чтении / создании FunctionJob
@@ -29,6 +31,7 @@ type jobResponse struct {
Namespace string `json:"namespace"`
FunctionRef string `json:"function"`
EventJSON string `json:"event_json"`
RunID int64 `json:"run_id"`
Phase string `json:"phase"`
JobName string `json:"job_name,omitempty"`
StartTime string `json:"start_time,omitempty"`
@@ -43,6 +46,7 @@ func jobToResponse(j *slessv1alpha1.FunctionJob) jobResponse {
Namespace: j.Namespace,
FunctionRef: j.Spec.FunctionRef,
EventJSON: j.Spec.EventJSON,
RunID: j.Spec.RunID,
Phase: string(j.Status.Phase),
JobName: j.Status.JobName,
Message: j.Status.Message,
@@ -86,6 +90,7 @@ func (h *Handler) CreateJob(w http.ResponseWriter, r *http.Request) {
Spec: slessv1alpha1.FunctionJobSpec{
FunctionRef: req.FunctionRef,
EventJSON: req.EventJSON,
RunID: req.RunID,
},
}
+50 -2
View File
@@ -1,4 +1,4 @@
// Изменено: 2026-03-07
// Изменено: 2026-03-08
// triggers.go — CRUD handlers для Trigger CRD.
// Триггеры привязаны к Function через FunctionRef.
// Namespace берётся из URL: /v1/namespaces/{namespace}/triggers/{name}
@@ -16,13 +16,16 @@ import (
slessv1alpha1 "gitea-naeel.giteak8s.services.ngcloud.ru/naeel/sless/api/v1alpha1"
)
// triggerRequest — тело запроса для создания триггера.
// triggerRequest — тело запроса для создания/обновления триггера.
type triggerRequest struct {
Name string `json:"name"`
Type string `json:"type"` // http | cron
FunctionRef string `json:"function"` // имя Function CRD
Schedule string `json:"schedule"` // cron-расписание, только для type=cron
PreWarmSeconds int32 `json:"pre_warm_seconds"`
// Enabled — по умолчанию true (включён). false = Deployment масштабируется до 0.
// Используем *bool чтобы различать nil (не передан) от false (явно выключен).
Enabled *bool `json:"enabled"`
}
// triggerResponse — ответ при чтении триггера.
@@ -32,6 +35,7 @@ type triggerResponse struct {
Type string `json:"type"`
FunctionRef string `json:"function"`
Schedule string `json:"schedule,omitempty"`
Enabled bool `json:"enabled"`
Active bool `json:"active"`
URL string `json:"url,omitempty"`
Message string `json:"message,omitempty"`
@@ -45,6 +49,7 @@ func trToResponse(tr *slessv1alpha1.Trigger) triggerResponse {
Type: string(tr.Spec.Type),
FunctionRef: tr.Spec.FunctionRef,
Schedule: tr.Spec.Schedule,
Enabled: tr.Spec.Enabled,
Active: tr.Status.Active,
URL: tr.Status.URL,
Message: tr.Status.Message,
@@ -93,6 +98,8 @@ func (h *Handler) CreateTrigger(w http.ResponseWriter, r *http.Request) {
FunctionRef: req.FunctionRef,
Schedule: req.Schedule,
PreWarmSeconds: req.PreWarmSeconds,
// По умолчанию enabled=true, если явно не передано false
Enabled: req.Enabled == nil || *req.Enabled,
},
}
if err := h.K8s.Create(r.Context(), tr); err != nil {
@@ -141,3 +148,44 @@ func (h *Handler) DeleteTrigger(w http.ResponseWriter, r *http.Request) {
}
w.WriteHeader(http.StatusNoContent)
}
// UpdateTrigger — PATCH /v1/namespaces/{namespace}/triggers/{name}
// Позволяет изменить поля триггера без пересоздания (в частности enabled).
// Принимает частичный JSON: только переданные поля обновляются.
func (h *Handler) UpdateTrigger(w http.ResponseWriter, r *http.Request) {
ns := namespace(r)
name := pathVar(r, "name")
var req triggerRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, errResp("invalid JSON: "+err.Error()))
return
}
tr := &slessv1alpha1.Trigger{}
if err := h.K8s.Get(r.Context(), client.ObjectKey{Name: name, Namespace: ns}, tr); err != nil {
if errors.IsNotFound(err) {
writeJSON(w, http.StatusNotFound, errResp("trigger not found"))
return
}
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
return
}
// Обновляем только явно переданные поля
if req.Enabled != nil {
tr.Spec.Enabled = *req.Enabled
}
if req.Schedule != "" {
tr.Spec.Schedule = req.Schedule
}
if req.PreWarmSeconds != 0 {
tr.Spec.PreWarmSeconds = req.PreWarmSeconds
}
if err := h.K8s.Update(r.Context(), tr); err != nil {
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
return
}
writeJSON(w, http.StatusOK, trToResponse(tr))
}
+2 -1
View File
@@ -1,4 +1,4 @@
// Изменено: 2026-03-07
// Изменено: 2026-03-08
// router.go — регистрация всех REST-маршрутов через gorilla/mux.
// Все маршруты защищены Bearer-токеном (middleware.Auth).
// Маршруты сгруппированы по /v1/namespaces/{namespace}/...
@@ -45,6 +45,7 @@ func NewRouter(h *handler.Handler, apiToken string, log *slog.Logger) http.Handl
v1.HandleFunc("/namespaces/{namespace}/triggers", h.ListTriggers).Methods(http.MethodGet)
v1.HandleFunc("/namespaces/{namespace}/triggers", h.CreateTrigger).Methods(http.MethodPost)
v1.HandleFunc("/namespaces/{namespace}/triggers/{name}", h.GetTrigger).Methods(http.MethodGet)
v1.HandleFunc("/namespaces/{namespace}/triggers/{name}", h.UpdateTrigger).Methods(http.MethodPatch)
v1.HandleFunc("/namespaces/{namespace}/triggers/{name}", h.DeleteTrigger).Methods(http.MethodDelete)
// Jobs CRUD — одноразовые запуски функций