From 43b806ab985e5011c197de5a863cd3af1cc744e4 Mon Sep 17 00:00:00 2001 From: Onur Solmaz Date: Thu, 12 Mar 2026 14:50:15 +0100 Subject: [PATCH] fix(operator): scope reconciliation to configured namespaces --- .../spritz/templates/operator-deployment.yaml | 4 ++ helm/spritz/values.yaml | 1 + operator/main.go | 38 ++++++++++++++ operator/main_test.go | 52 +++++++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 operator/main_test.go diff --git a/helm/spritz/templates/operator-deployment.yaml b/helm/spritz/templates/operator-deployment.yaml index 4211a7c..a492e12 100644 --- a/helm/spritz/templates/operator-deployment.yaml +++ b/helm/spritz/templates/operator-deployment.yaml @@ -41,6 +41,10 @@ spec: - name: SPRITZ_TTL_GRACE_PERIOD value: {{ .Values.operator.ttlGracePeriod | quote }} {{- end }} + {{- if .Values.operator.watchNamespaces }} + - name: SPRITZ_OPERATOR_WATCH_NAMESPACES + value: {{ join "," .Values.operator.watchNamespaces | quote }} + {{- end }} {{- if .Values.operator.workspaceSizeLimit }} - name: SPRITZ_WORKSPACE_SIZE_LIMIT value: {{ .Values.operator.workspaceSizeLimit | quote }} diff --git a/helm/spritz/values.yaml b/helm/spritz/values.yaml index d516445..2bc69b7 100644 --- a/helm/spritz/values.yaml +++ b/helm/spritz/values.yaml @@ -82,6 +82,7 @@ operator: imagePullPolicy: IfNotPresent rolloutAt: "" namespace: spritz-system + watchNamespaces: [] serviceAccountName: spritz-operator clusterRoleName: spritz-operator clusterRoleBindingName: spritz-operator diff --git a/operator/main.go b/operator/main.go index 9eb16c6..24097be 100644 --- a/operator/main.go +++ b/operator/main.go @@ -2,6 +2,7 @@ package main import ( "os" + "strings" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -9,6 +10,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/log/zap" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" @@ -37,9 +39,19 @@ func main() { metricsAddr := envOrDefault("SPRITZ_OPERATOR_METRICS_ADDR", ":8080") healthAddr := envOrDefault("SPRITZ_OPERATOR_HEALTH_ADDR", ":8081") + watchNamespaces := parseWatchNamespaces(os.Getenv("SPRITZ_OPERATOR_WATCH_NAMESPACES")) + + cacheOptions := cache.Options{} + if len(watchNamespaces) > 0 { + cacheOptions.DefaultNamespaces = make(map[string]cache.Config, len(watchNamespaces)) + for _, namespace := range watchNamespaces { + cacheOptions.DefaultNamespaces[namespace] = cache.Config{} + } + } mgr, err := ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, + Cache: cacheOptions, Metrics: metricsserver.Options{ BindAddress: metricsAddr, }, @@ -72,3 +84,29 @@ func envOrDefault(key, fallback string) string { } return value } + +func parseWatchNamespaces(raw string) []string { + if strings.TrimSpace(raw) == "" { + return nil + } + + seen := make(map[string]struct{}) + namespaces := make([]string, 0) + for _, value := range strings.Split(raw, ",") { + namespace := strings.TrimSpace(value) + if namespace == "" { + continue + } + if _, exists := seen[namespace]; exists { + continue + } + seen[namespace] = struct{}{} + namespaces = append(namespaces, namespace) + } + + if len(namespaces) == 0 { + return nil + } + + return namespaces +} diff --git a/operator/main_test.go b/operator/main_test.go new file mode 100644 index 0000000..d1a12f8 --- /dev/null +++ b/operator/main_test.go @@ -0,0 +1,52 @@ +package main + +import ( + "reflect" + "testing" +) + +func TestParseWatchNamespaces(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + raw string + want []string + }{ + { + name: "empty", + raw: "", + want: nil, + }, + { + name: "whitespace only", + raw: " ", + want: nil, + }, + { + name: "single namespace", + raw: "spritz-staging", + want: []string{"spritz-staging"}, + }, + { + name: "multiple namespaces", + raw: "spritz-staging,spritz-system-staging", + want: []string{"spritz-staging", "spritz-system-staging"}, + }, + { + name: "trims and deduplicates", + raw: " spritz-staging , spritz-system-staging , spritz-staging ,, ", + want: []string{"spritz-staging", "spritz-system-staging"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := parseWatchNamespaces(tt.raw) + if !reflect.DeepEqual(got, tt.want) { + t.Fatalf("parseWatchNamespaces(%q) = %#v, want %#v", tt.raw, got, tt.want) + } + }) + } +}