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:
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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 — одноразовые запуски функций
|
||||
|
||||
Reference in New Issue
Block a user