layer1: share namespace watcher event handlers
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
# 2026-04-26 — NamespaceManager rewrite, step 42
|
||||||
|
|
||||||
|
## Цель шага
|
||||||
|
|
||||||
|
Убрать последний крупный слой дублирования в namespace watcher-ах: сами `ResourceEventHandlerFuncs`.
|
||||||
|
|
||||||
|
## Что меняем
|
||||||
|
|
||||||
|
1. В `utils` добавляем `NewNamespaceWatcherEventHandlers()`.
|
||||||
|
2. Конструктор собирает общий `Add/Update/Delete` flow на базе уже существующих handler helper-ов.
|
||||||
|
3. `buildermgr`, `router`, `executor/multitenant` используют общий конструктор.
|
||||||
|
|
||||||
|
## Что НЕ меняем
|
||||||
|
|
||||||
|
- не меняем label selector;
|
||||||
|
- не меняем manager semantics;
|
||||||
|
- не меняем removal policy по умолчанию.
|
||||||
@@ -45,24 +45,7 @@ func StartNSWatcher(
|
|||||||
|
|
||||||
nsInformer := factory.Core().V1().Namespaces().Informer()
|
nsInformer := factory.Core().V1().Namespaces().Informer()
|
||||||
|
|
||||||
_, _ = nsInformer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
|
_, _ = nsInformer.AddEventHandler(utils.NewNamespaceWatcherEventHandlers(ctx, logger, "buildermgr.NSWatcher", nsManager, utils.NamespaceRemovalStrategyTrackOnly))
|
||||||
AddFunc: func(obj interface{}) {
|
|
||||||
nsObj, ok := obj.(*corev1.Namespace)
|
|
||||||
if ok {
|
|
||||||
utils.HandleWatcherNamespaceAdd(ctx, logger, "buildermgr.NSWatcher", nsManager, nsObj)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
|
||||||
oldNSObj, _ := oldObj.(*corev1.Namespace)
|
|
||||||
nsObj, ok := newObj.(*corev1.Namespace)
|
|
||||||
if ok {
|
|
||||||
utils.HandleWatcherNamespaceUpdate(ctx, logger, "buildermgr.NSWatcher", nsManager, oldNSObj, nsObj, utils.NamespaceRemovalStrategyTrackOnly)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DeleteFunc: func(obj interface{}) {
|
|
||||||
utils.HandleWatcherNamespaceDelete(ctx, logger, "buildermgr.NSWatcher", nsManager, obj, utils.NamespaceRemovalStrategyTrackOnly)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
mgr.Add(ctx, func(ctx context.Context) {
|
mgr.Add(ctx, func(ctx context.Context) {
|
||||||
logger.Info("buildermgr.NSWatcher: started",
|
logger.Info("buildermgr.NSWatcher: started",
|
||||||
|
|||||||
@@ -110,27 +110,7 @@ func StartNSWatcher(
|
|||||||
|
|
||||||
nsInformer := factory.Core().V1().Namespaces().Informer()
|
nsInformer := factory.Core().V1().Namespaces().Informer()
|
||||||
|
|
||||||
_, _ = nsInformer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
|
_, _ = nsInformer.AddEventHandler(utils.NewNamespaceWatcherEventHandlers(ctx, logger, "multitenant.NSWatcher", nsManager, utils.NamespaceRemovalStrategyTrackOnly))
|
||||||
// AddFunc fires when a new Namespace with the label appears.
|
|
||||||
AddFunc: func(obj interface{}) {
|
|
||||||
nsObj, ok := obj.(*corev1.Namespace)
|
|
||||||
if ok {
|
|
||||||
utils.HandleWatcherNamespaceAdd(ctx, logger, "multitenant.NSWatcher", nsManager, nsObj)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// UpdateFunc fires when an existing Namespace is updated — covers the case
|
|
||||||
// where the label is added to a pre-existing Namespace.
|
|
||||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
|
||||||
oldNSObj, _ := oldObj.(*corev1.Namespace)
|
|
||||||
nsObj, ok := newObj.(*corev1.Namespace)
|
|
||||||
if ok {
|
|
||||||
utils.HandleWatcherNamespaceUpdate(ctx, logger, "multitenant.NSWatcher", nsManager, oldNSObj, nsObj, utils.NamespaceRemovalStrategyTrackOnly)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DeleteFunc: func(obj interface{}) {
|
|
||||||
utils.HandleWatcherNamespaceDelete(ctx, logger, "multitenant.NSWatcher", nsManager, obj, utils.NamespaceRemovalStrategyTrackOnly)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
mgr.Add(ctx, func(ctx context.Context) {
|
mgr.Add(ctx, func(ctx context.Context) {
|
||||||
logger.Info("multitenant.NSWatcher: started", zap.String("label", utils.ManagedNamespaceLabelSelector()))
|
logger.Info("multitenant.NSWatcher: started", zap.String("label", utils.ManagedNamespaceLabelSelector()))
|
||||||
|
|||||||
@@ -45,24 +45,7 @@ func StartNSWatcher(
|
|||||||
|
|
||||||
nsInformer := factory.Core().V1().Namespaces().Informer()
|
nsInformer := factory.Core().V1().Namespaces().Informer()
|
||||||
|
|
||||||
_, _ = nsInformer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
|
_, _ = nsInformer.AddEventHandler(utils.NewNamespaceWatcherEventHandlers(ctx, logger, "router.NSWatcher", nsManager, utils.NamespaceRemovalStrategyTrackOnly))
|
||||||
AddFunc: func(obj interface{}) {
|
|
||||||
nsObj, ok := obj.(*corev1.Namespace)
|
|
||||||
if ok {
|
|
||||||
utils.HandleWatcherNamespaceAdd(ctx, logger, "router.NSWatcher", nsManager, nsObj)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
|
||||||
oldNSObj, _ := oldObj.(*corev1.Namespace)
|
|
||||||
nsObj, ok := newObj.(*corev1.Namespace)
|
|
||||||
if ok {
|
|
||||||
utils.HandleWatcherNamespaceUpdate(ctx, logger, "router.NSWatcher", nsManager, oldNSObj, nsObj, utils.NamespaceRemovalStrategyTrackOnly)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DeleteFunc: func(obj interface{}) {
|
|
||||||
utils.HandleWatcherNamespaceDelete(ctx, logger, "router.NSWatcher", nsManager, obj, utils.NamespaceRemovalStrategyTrackOnly)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
mgr.Add(ctx, func(ctx context.Context) {
|
mgr.Add(ctx, func(ctx context.Context) {
|
||||||
logger.Info("router.NSWatcher: started",
|
logger.Info("router.NSWatcher: started",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
k8sCache "k8s.io/client-go/tools/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NamespaceSubscriber interface {
|
type NamespaceSubscriber interface {
|
||||||
@@ -185,6 +186,27 @@ func HandleWatcherNamespaceRemoval(ctx context.Context, logger *zap.Logger, comp
|
|||||||
zap.String("namespace", record.Name))
|
zap.String("namespace", record.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewNamespaceWatcherEventHandlers(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, strategy NamespaceRemovalStrategy) k8sCache.ResourceEventHandlerFuncs {
|
||||||
|
return k8sCache.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: func(obj interface{}) {
|
||||||
|
namespace, ok := obj.(*corev1.Namespace)
|
||||||
|
if ok {
|
||||||
|
HandleWatcherNamespaceAdd(ctx, logger, component, manager, namespace)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||||
|
oldNamespace, _ := oldObj.(*corev1.Namespace)
|
||||||
|
newNamespace, ok := newObj.(*corev1.Namespace)
|
||||||
|
if ok {
|
||||||
|
HandleWatcherNamespaceUpdate(ctx, logger, component, manager, oldNamespace, newNamespace, strategy)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DeleteFunc: func(obj interface{}) {
|
||||||
|
HandleWatcherNamespaceDelete(ctx, logger, component, manager, obj, strategy)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *inMemoryNamespaceManager) Subscribe(subscriber NamespaceSubscriber) {
|
func (m *inMemoryNamespaceManager) Subscribe(subscriber NamespaceSubscriber) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
|
|||||||
@@ -406,6 +406,29 @@ func TestHandleWatcherNamespaceUpdateDispatchRemoval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewNamespaceWatcherEventHandlers(t *testing.T) {
|
||||||
|
manager := NewNamespaceManager()
|
||||||
|
router := &testNamespaceSubscriber{name: "router"}
|
||||||
|
manager.Subscribe(router)
|
||||||
|
logger := zap.NewNop()
|
||||||
|
handlers := NewNamespaceWatcherEventHandlers(context.Background(), logger, "router.NSWatcher", manager, NamespaceRemovalStrategyTrackOnly)
|
||||||
|
namespace := &corev1.Namespace{}
|
||||||
|
namespace.Name = "tenant-a"
|
||||||
|
namespace.Labels = map[string]string{ManagedNamespaceLabelKey: ManagedNamespaceLabelValue}
|
||||||
|
|
||||||
|
handlers.AddFunc(namespace)
|
||||||
|
handlers.UpdateFunc(namespace, namespace)
|
||||||
|
handlers.DeleteFunc(k8sCache.DeletedFinalStateUnknown{Obj: namespace})
|
||||||
|
|
||||||
|
record, ok := manager.Get("tenant-a")
|
||||||
|
if !ok || record.Phase != NamespacePhaseRemoved {
|
||||||
|
t.Fatalf("expected watcher event handlers to drive namespace lifecycle")
|
||||||
|
}
|
||||||
|
if router.addCalls != 1 || router.resyncCalls != 1 {
|
||||||
|
t.Fatalf("expected add and resync calls through event handlers")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNamespaceManagerDispatchAdd(t *testing.T) {
|
func TestNamespaceManagerDispatchAdd(t *testing.T) {
|
||||||
manager := NewNamespaceManager()
|
manager := NewNamespaceManager()
|
||||||
manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})
|
manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})
|
||||||
|
|||||||
Reference in New Issue
Block a user