From d2ff55f9e07ddcc0cb859c9145eff3ed575645db Mon Sep 17 00:00:00 2001 From: Naeel Date: Sun, 26 Apr 2026 11:02:09 +0300 Subject: [PATCH] layer1: add managed watcher config --- .../2026-04-26-namespace-manager-step50.md | 17 +++++++++ pkg/buildermgr/ns_watcher.go | 7 +++- pkg/executor/multitenant/ns_watcher.go | 7 +++- pkg/router/ns_watcher.go | 7 +++- pkg/utils/namespace_manager.go | 18 +++++---- pkg/utils/namespace_manager_model.go | 7 ++++ pkg/utils/namespace_manager_test.go | 38 ++++++++++++++++++- 7 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 doc/thinking/2026-04-26-namespace-manager-step50.md diff --git a/doc/thinking/2026-04-26-namespace-manager-step50.md b/doc/thinking/2026-04-26-namespace-manager-step50.md new file mode 100644 index 00000000..3e446fef --- /dev/null +++ b/doc/thinking/2026-04-26-namespace-manager-step50.md @@ -0,0 +1,17 @@ +# 2026-04-26 — NamespaceManager rewrite, step 50 + +## Цель шага + +Сделать orchestration API для managed namespace watcher-а жёстче и читабельнее. + +## Что меняем + +1. Добавляем `ManagedNamespaceWatcherConfig`. +2. `PrepareManagedNamespaceWatcher()` и `RunManagedNamespaceWatcher()` принимают config struct. +3. Если strategy не задана, используется `track-only`. +4. Обновляем unit tests и call sites. + +## Что НЕ меняем + +- не меняем runtime semantics; +- не меняем subscriber logic. \ No newline at end of file diff --git a/pkg/buildermgr/ns_watcher.go b/pkg/buildermgr/ns_watcher.go index 4cd94108..d4189119 100644 --- a/pkg/buildermgr/ns_watcher.go +++ b/pkg/buildermgr/ns_watcher.go @@ -25,7 +25,12 @@ func StartNSWatcher( pkgw *packageWatcher, mgr manager.Interface, ) { - _, err := utils.RunManagedNamespaceWatcher(ctx, logger, "buildermgr.NSWatcher", kubeClient, mgr, utils.DefaultNSResolver().Snapshot(), utils.NamespaceRemovalStrategyTrackOnly, NewNamespaceSubscriber(envw, pkgw, mgr)) + _, err := utils.RunManagedNamespaceWatcher(ctx, logger, kubeClient, mgr, utils.ManagedNamespaceWatcherConfig{ + Component: "buildermgr.NSWatcher", + Namespaces: utils.DefaultNSResolver().Snapshot(), + RemovalStrategy: utils.NamespaceRemovalStrategyTrackOnly, + Subscriber: NewNamespaceSubscriber(envw, pkgw, mgr), + }) if err != nil { logger.Error("buildermgr.NSWatcher: BootstrapAndDispatch failed", zap.Error(err)) } diff --git a/pkg/executor/multitenant/ns_watcher.go b/pkg/executor/multitenant/ns_watcher.go index dd122d5c..617933bf 100644 --- a/pkg/executor/multitenant/ns_watcher.go +++ b/pkg/executor/multitenant/ns_watcher.go @@ -71,7 +71,12 @@ import ( "github.com/fission/fission/pkg/utils" "github.com/fission/fission/pkg/utils/manager" ) - + _, err := utils.RunManagedNamespaceWatcher(ctx, logger, kubernetesClient, mgr, utils.ManagedNamespaceWatcherConfig{ + Component: "multitenant.NSWatcher", + Namespaces: utils.DefaultNSResolver().Snapshot(), + RemovalStrategy: utils.NamespaceRemovalStrategyTrackOnly, + Subscriber: NewNamespaceSubscriber(logger, kubernetesClient, executorTypes, mgr), + }) // StartNSWatcher registers a Kubernetes Namespace Informer that reacts immediately // when a Namespace with label fission.io/managed=true is created or relabeled. // diff --git a/pkg/router/ns_watcher.go b/pkg/router/ns_watcher.go index 54c19a49..82e91dfe 100644 --- a/pkg/router/ns_watcher.go +++ b/pkg/router/ns_watcher.go @@ -14,7 +14,12 @@ import ( "github.com/fission/fission/pkg/utils" "github.com/fission/fission/pkg/utils/manager" ) - + _, err := utils.RunManagedNamespaceWatcher(ctx, logger, kubeClient, mgr, utils.ManagedNamespaceWatcherConfig{ + Component: "router.NSWatcher", + Namespaces: utils.DefaultNSResolver().Snapshot(), + RemovalStrategy: utils.NamespaceRemovalStrategyTrackOnly, + Subscriber: NewNamespaceSubscriber(ts, mgr), + }) // StartNSWatcher registers a Kubernetes Namespace Informer for the router. // Whenever a Namespace with label fission.io/managed=true appears (or is relabeled), // the router immediately subscribes to HTTPTriggers and Functions in that namespace. diff --git a/pkg/utils/namespace_manager.go b/pkg/utils/namespace_manager.go index 170a3073..313d50f9 100644 --- a/pkg/utils/namespace_manager.go +++ b/pkg/utils/namespace_manager.go @@ -110,16 +110,20 @@ func NewWatcherNamespaceManager(ctx context.Context, namespaces []string, source return manager, err } -func PrepareManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, component string, namespaces []string, removalStrategy NamespaceRemovalStrategy, subscriber NamespaceSubscriber) (NamespaceManager, k8sCache.ResourceEventHandlerFuncs, error) { - manager, err := NewWatcherNamespaceManager(ctx, namespaces, NamespaceSourceEnv, time.Now().UTC(), subscriber) - handlers := NewNamespaceWatcherEventHandlers(ctx, logger, component, manager, removalStrategy) - LogNamespaceManagerSummary(logger, component+": prepared namespace manager", manager.Summary()) +func PrepareManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, config ManagedNamespaceWatcherConfig) (NamespaceManager, k8sCache.ResourceEventHandlerFuncs, error) { + strategy := config.RemovalStrategy + if strategy == "" { + strategy = NamespaceRemovalStrategyTrackOnly + } + manager, err := NewWatcherNamespaceManager(ctx, config.Namespaces, NamespaceSourceEnv, time.Now().UTC(), config.Subscriber) + handlers := NewNamespaceWatcherEventHandlers(ctx, logger, config.Component, manager, strategy) + LogNamespaceManagerSummary(logger, config.Component+": prepared namespace manager", manager.Summary()) return manager, handlers, err } -func RunManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, component string, kubeClient kubernetes.Interface, mgr managerPkg.Interface, namespaces []string, removalStrategy NamespaceRemovalStrategy, subscriber NamespaceSubscriber) (NamespaceManager, error) { - manager, handlers, err := PrepareManagedNamespaceWatcher(ctx, logger, component, namespaces, removalStrategy, subscriber) - StartManagedNamespaceWatcher(ctx, logger, component, kubeClient, mgr, handlers) +func RunManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, kubeClient kubernetes.Interface, mgr managerPkg.Interface, config ManagedNamespaceWatcherConfig) (NamespaceManager, error) { + manager, handlers, err := PrepareManagedNamespaceWatcher(ctx, logger, config) + StartManagedNamespaceWatcher(ctx, logger, config.Component, kubeClient, mgr, handlers) return manager, err } diff --git a/pkg/utils/namespace_manager_model.go b/pkg/utils/namespace_manager_model.go index 0e935842..d0b13243 100644 --- a/pkg/utils/namespace_manager_model.go +++ b/pkg/utils/namespace_manager_model.go @@ -81,6 +81,13 @@ type NamespaceManagerSummary struct { Subscribers []string } +type ManagedNamespaceWatcherConfig struct { + Component string + Namespaces []string + RemovalStrategy NamespaceRemovalStrategy + Subscriber NamespaceSubscriber +} + func NewNamespaceEvent(eventType NamespaceEventType, name string, labels map[string]string, source NamespaceSource, observedAt time.Time) NamespaceEvent { return NamespaceEvent{ Type: eventType, diff --git a/pkg/utils/namespace_manager_test.go b/pkg/utils/namespace_manager_test.go index c5163256..7ef7d63d 100644 --- a/pkg/utils/namespace_manager_test.go +++ b/pkg/utils/namespace_manager_test.go @@ -445,7 +445,12 @@ func TestNewNamespaceWatcherEventHandlers(t *testing.T) { func TestPrepareManagedNamespaceWatcher(t *testing.T) { router := &testNamespaceSubscriber{name: "router"} logger := zap.NewNop() - manager, handlers, err := PrepareManagedNamespaceWatcher(context.Background(), logger, "router.NSWatcher", []string{"tenant-a"}, NamespaceRemovalStrategyTrackOnly, router) + manager, handlers, err := PrepareManagedNamespaceWatcher(context.Background(), logger, ManagedNamespaceWatcherConfig{ + Component: "router.NSWatcher", + Namespaces: []string{"tenant-a"}, + RemovalStrategy: NamespaceRemovalStrategyTrackOnly, + Subscriber: router, + }) if err != nil { t.Fatalf("expected watcher preparation success: %v", err) } @@ -466,7 +471,12 @@ func TestRunManagedNamespaceWatcher(t *testing.T) { defer cancel() router := &testNamespaceSubscriber{name: "router"} logger := zap.NewNop() - manager, err := RunManagedNamespaceWatcher(ctx, logger, "router.NSWatcher", k8sfake.NewSimpleClientset(), managerPkg.New(), []string{"tenant-a"}, NamespaceRemovalStrategyTrackOnly, router) + manager, err := RunManagedNamespaceWatcher(ctx, logger, k8sfake.NewSimpleClientset(), managerPkg.New(), ManagedNamespaceWatcherConfig{ + Component: "router.NSWatcher", + Namespaces: []string{"tenant-a"}, + RemovalStrategy: NamespaceRemovalStrategyTrackOnly, + Subscriber: router, + }) if err != nil { t.Fatalf("expected managed namespace watcher run success: %v", err) } @@ -475,6 +485,30 @@ func TestRunManagedNamespaceWatcher(t *testing.T) { } } +func TestPrepareManagedNamespaceWatcherDefaultsToTrackOnly(t *testing.T) { + router := &testNamespaceSubscriber{name: "router"} + logger := zap.NewNop() + manager, handlers, err := PrepareManagedNamespaceWatcher(context.Background(), logger, ManagedNamespaceWatcherConfig{ + Component: "router.NSWatcher", + Namespaces: []string{"tenant-a"}, + Subscriber: router, + }) + if err != nil { + t.Fatalf("expected watcher preparation success: %v", err) + } + namespace := &corev1.Namespace{} + namespace.Name = "tenant-a" + namespace.Labels = map[string]string{ManagedNamespaceLabelKey: ManagedNamespaceLabelValue} + handlers.DeleteFunc(k8sCache.DeletedFinalStateUnknown{Obj: namespace}) + record, ok := manager.Get("tenant-a") + if !ok || record.Phase != NamespacePhaseRemoved { + t.Fatalf("expected default strategy to keep track-only removal semantics") + } + if router.removeCalls != 0 { + t.Fatalf("expected default strategy not to dispatch remove") + } +} + func TestNamespaceManagerSummary(t *testing.T) { manager := NewNamespaceManager() manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})