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
+32 -1
View File
@@ -1,4 +1,4 @@
// Изменено: 2026-03-07
// Изменено: 2026-03-08
// TriggerReconciler — контроллер триггеров.
// HTTP триггер: создаёт Service + Ingress в namespace функции.
// Cron триггер: создаёт k8s CronJob который периодически вызывает функцию по внутреннему URL.
@@ -9,6 +9,7 @@ import (
"context"
"fmt"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
netv1 "k8s.io/api/networking/v1"
@@ -84,6 +85,36 @@ func (r *TriggerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
return ctrl.Result{}, nil
}
// Управляем масштабом Deployment функции в зависимости от Enabled.
// Deployment находится в namespace sless-fn-{userNS}, имя = имя функции.
// Это позволяет "заморозить" функцию без удаления ресурса.
deployNS := "sless-fn-" + tr.Namespace
dep := &appsv1.Deployment{}
if err := r.Get(ctx, client.ObjectKey{Name: fn.Name, Namespace: deployNS}, dep); err == nil {
var wantReplicas int32
if tr.Spec.Enabled {
wantReplicas = 1
} else {
wantReplicas = 0
}
// Обновляем только если значение изменилось, чтобы не создавать лишних событий
if dep.Spec.Replicas == nil || *dep.Spec.Replicas != wantReplicas {
dep.Spec.Replicas = &wantReplicas
if err := r.Update(ctx, dep); err != nil {
return ctrl.Result{}, fmt.Errorf("scale deployment replicas: %w", err)
}
logger.Info("scaled deployment", "function", fn.Name, "replicas", wantReplicas)
}
}
// Если триггер выключен — останавливаем reconcile здесь, ресурсы не создаём
if !tr.Spec.Enabled {
tr.Status.Active = false
tr.Status.Message = "disabled (enabled=false)"
_ = r.Status().Update(ctx, tr)
return ctrl.Result{}, nil
}
switch tr.Spec.Type {
case slessv1alpha1.TriggerTypeHTTP:
logger.Info("reconcile http trigger", "trigger", tr.Name)