fix: immediate fixes from Opus review (v0.1.22)

- trigger: CronJob moved to deployNS (sless-fn-{userNS}), was tr.Namespace
  Reason: with NetworkPolicy default-deny, pod in user-ns can't reach
  Service in sless-fn-ns. Co-locating CronJob with Service guarantees
  connectivity regardless of NetworkPolicy configuration.
  handleTriggerDeletion updated consistently.

- trigger: pin curlimages/curl to 8.5.0 (was :latest)
  Reason: reproducibility, no unexpected behavior changes from image updates.

- function: sort env vars in buildDeployment (was non-deterministic map range)
  Reason: non-deterministic order caused k8s to detect container spec 'change'
  on every reconcile → unnecessary pod restarts. Sorted order is stable.

- function: cleanup kaniko Job in handleDeletion
  Reason: if Function deleted during Building phase, kaniko Job continued
  running, wasting CPU/memory and pushing an unused image.

- invoke: filter hop-by-hop headers in proxy response (RFC 2616 §13.5.1)
  Reason: Transfer-Encoding especially dangerous — forwarding it corrupts
  response body framing for the client.

- config: SLESS_API_TOKEN no longer required
  Reason: dead code — field loaded but never passed to any component.
  Auth uses validateJWT() middleware, not static token.

Namespace lifecycle: user namespaces preserved on destroy (not changed).
E2E: apply 4 resources + destroy clean. Operator v0.1.22 deployed.
This commit is contained in:
“Naeel”
2026-03-11 09:20:09 +04:00
parent bca889d355
commit e761439546
5 changed files with 600 additions and 19 deletions
+12 -6
View File
@@ -1,4 +1,4 @@
// Изменено: 2026-03-10
// Изменено: 2026-03-11
// TriggerReconciler — контроллер триггеров.
// HTTP триггер: создаёт Service + Ingress в namespace функции.
// Cron триггер: создаёт k8s CronJob который периодически вызывает функцию по внутреннему URL.
@@ -218,6 +218,9 @@ func (r *TriggerReconciler) reconcileHTTP(ctx context.Context, tr *slessv1alpha1
// reconcileCron создаёт CronJob который вызывает функцию по HTTP внутри кластера.
// curl делает POST на внутренний Service функции — это исключает внешний round-trip.
// CronJob размещается в deployNS (sless-fn-{userNS}), НЕ в user-namespace:
// при NetworkPolicy default-deny под в user-ns не может достучаться до Service в sless-fn-ns.
// Размещение CronJob в том же namespace что и Service — гарантирует работу при любой политике.
func (r *TriggerReconciler) reconcileCron(ctx context.Context, tr *slessv1alpha1.Trigger, fn *slessv1alpha1.Function) (ctrl.Result, error) {
deployNS := "sless-fn-" + tr.Namespace
// Внутренний URL: Service должен быть создан HTTP триггером или заранее
@@ -226,7 +229,7 @@ func (r *TriggerReconciler) reconcileCron(ctx context.Context, tr *slessv1alpha1
wantCJ := &batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: tr.Name,
Namespace: tr.Namespace,
Namespace: deployNS, // размещаем там же где Service функции
Labels: map[string]string{"managed-by": "sless", "trigger": tr.Name},
},
Spec: batchv1.CronJobSpec{
@@ -238,9 +241,10 @@ func (r *TriggerReconciler) reconcileCron(ctx context.Context, tr *slessv1alpha1
RestartPolicy: corev1.RestartPolicyOnFailure,
Containers: []corev1.Container{
{
// curlimages/curl вызывает функцию по внутреннему адресу
// curlimages/curl вызывает функцию по внутреннему адресу.
// Версия зафиксирована для воспроизводимости — не latest.
Name: "invoker",
Image: "curlimages/curl:latest",
Image: "curlimages/curl:8.5.0",
Command: []string{"curl", "-sf", "-X", "POST", funcURL},
},
},
@@ -252,7 +256,7 @@ func (r *TriggerReconciler) reconcileCron(ctx context.Context, tr *slessv1alpha1
}
existing := &batchv1.CronJob{}
if err := r.Get(ctx, client.ObjectKey{Name: tr.Name, Namespace: tr.Namespace}, existing); err != nil {
if err := r.Get(ctx, client.ObjectKey{Name: tr.Name, Namespace: deployNS}, existing); err != nil {
if errors.IsNotFound(err) {
if err := r.Create(ctx, wantCJ); err != nil {
return ctrl.Result{}, fmt.Errorf("create cronjob: %w", err)
@@ -277,10 +281,12 @@ func (r *TriggerReconciler) reconcileCron(ctx context.Context, tr *slessv1alpha1
}
// handleTriggerDeletion удаляет ресурсы триггера и убирает finalizer.
// CronJob ищется в deployNS — туда же куда reconcileCron его создаёт.
func (r *TriggerReconciler) handleTriggerDeletion(ctx context.Context, tr *slessv1alpha1.Trigger) (ctrl.Result, error) {
if tr.Spec.Type == slessv1alpha1.TriggerTypeCron {
deployNS := "sless-fn-" + tr.Namespace
cj := &batchv1.CronJob{}
if err := r.Get(ctx, client.ObjectKey{Name: tr.Name, Namespace: tr.Namespace}, cj); err == nil {
if err := r.Get(ctx, client.ObjectKey{Name: tr.Name, Namespace: deployNS}, cj); err == nil {
_ = r.Delete(ctx, cj)
}
}