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
|
||||
// FunctionJobReconciler — контроллер одноразовых запусков функций.
|
||||
// При создании FunctionJob:
|
||||
// 1. Ждёт пока Function станет Ready
|
||||
@@ -58,6 +58,18 @@ func (r *FunctionJobReconciler) Reconcile(ctx context.Context, req ctrl.Request)
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// RunID=0 означает "не запускать".
|
||||
// Позволяет создать FunctionJob в кластере, но запустить его явно позже
|
||||
// (увеличив RunID > 0 через Terraform или kubectl patch).
|
||||
if fj.Spec.RunID == 0 {
|
||||
if fj.Status.Phase != "Skipped" {
|
||||
fj.Status.Phase = "Skipped"
|
||||
fj.Status.Message = "run_id=0: set run_id>0 to execute"
|
||||
_ = r.Status().Update(ctx, fj)
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// Проверяем что Function существует и готова
|
||||
fn := &slessv1alpha1.Function{}
|
||||
if err := r.Get(ctx, client.ObjectKey{Name: fj.Spec.FunctionRef, Namespace: fj.Namespace}, fn); err != nil {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user