layer1: share namespace watcher lifecycle helpers

This commit is contained in:
Naeel
2026-04-26 10:45:03 +03:00
parent 0e08664ef6
commit 4cd4bc9507
6 changed files with 129 additions and 33 deletions
+37
View File
@@ -6,6 +6,8 @@ import (
"sort"
"sync"
"time"
corev1 "k8s.io/api/core/v1"
)
type NamespaceSubscriber interface {
@@ -100,6 +102,41 @@ func NewWatcherNamespaceManager(ctx context.Context, namespaces []string, source
return manager, err
}
func NamespaceBecameUnmanaged(oldNamespace *corev1.Namespace, newNamespace *corev1.Namespace) bool {
if oldNamespace == nil || newNamespace == nil {
return false
}
return IsManagedNamespace(oldNamespace.Labels) && !IsManagedNamespace(newNamespace.Labels)
}
func DispatchNamespaceAdd(ctx context.Context, manager NamespaceManager, namespace *corev1.Namespace, source NamespaceSource, observedAt time.Time) (NamespaceRecord, bool, error) {
if manager == nil || namespace == nil || namespace.Name == "" {
return NamespaceRecord{}, false, nil
}
manager.Upsert(NamespaceEventFromNamespace(NamespaceEventAdd, namespace, source, observedAt))
return manager.DispatchAdd(ctx, namespace.Name)
}
func DispatchNamespaceResync(ctx context.Context, manager NamespaceManager, namespace *corev1.Namespace, source NamespaceSource, observedAt time.Time) (NamespaceRecord, bool, error) {
if manager == nil || namespace == nil || namespace.Name == "" {
return NamespaceRecord{}, false, nil
}
manager.Upsert(NamespaceEventFromNamespace(NamespaceEventUpdate, namespace, source, observedAt))
return manager.DispatchResync(ctx, namespace.Name)
}
func RecordNamespaceRemoval(manager NamespaceManager, obj interface{}, source NamespaceSource, observedAt time.Time) (NamespaceRecord, bool) {
if manager == nil {
return NamespaceRecord{}, false
}
event := NamespaceEventFromObject(NamespaceEventRemove, obj, source, observedAt)
if event.Name == "" {
return NamespaceRecord{}, false
}
record := manager.Upsert(event)
return record, true
}
func (m *inMemoryNamespaceManager) Subscribe(subscriber NamespaceSubscriber) {
m.mu.Lock()
defer m.mu.Unlock()
+52
View File
@@ -6,6 +6,9 @@ import (
"reflect"
"testing"
"time"
corev1 "k8s.io/api/core/v1"
k8sCache "k8s.io/client-go/tools/cache"
)
type testNamespaceSubscriber struct {
@@ -285,6 +288,55 @@ func TestNewWatcherNamespaceManager(t *testing.T) {
}
}
func TestNamespaceBecameUnmanaged(t *testing.T) {
oldNamespace := &corev1.Namespace{}
oldNamespace.Labels = map[string]string{ManagedNamespaceLabelKey: ManagedNamespaceLabelValue}
newNamespace := &corev1.Namespace{}
newNamespace.Labels = map[string]string{}
if !NamespaceBecameUnmanaged(oldNamespace, newNamespace) {
t.Fatalf("expected namespace to become unmanaged")
}
if NamespaceBecameUnmanaged(nil, newNamespace) {
t.Fatalf("expected nil old namespace to report false")
}
}
func TestDispatchNamespaceAddAndResync(t *testing.T) {
manager := NewNamespaceManager()
router := &testNamespaceSubscriber{name: "router"}
manager.Subscribe(router)
namespace := &corev1.Namespace{}
namespace.Name = "tenant-a"
namespace.Labels = map[string]string{ManagedNamespaceLabelKey: ManagedNamespaceLabelValue}
record, ok, err := DispatchNamespaceAdd(context.Background(), manager, namespace, NamespaceSourceWatcher, time.Now().UTC())
if !ok || err != nil || record.Phase != NamespacePhaseActive {
t.Fatalf("expected add dispatch success, ok=%v err=%v phase=%s", ok, err, record.Phase)
}
record, ok, err = DispatchNamespaceResync(context.Background(), manager, namespace, NamespaceSourceWatcher, time.Now().UTC())
if !ok || err != nil || record.Phase != NamespacePhaseActive {
t.Fatalf("expected resync dispatch success, ok=%v err=%v phase=%s", ok, err, record.Phase)
}
if router.addCalls != 1 || router.resyncCalls != 1 {
t.Fatalf("expected add and resync subscriber calls")
}
}
func TestRecordNamespaceRemoval(t *testing.T) {
manager := NewNamespaceManager()
manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})
namespace := &corev1.Namespace{}
namespace.Name = "tenant-a"
record, ok := RecordNamespaceRemoval(manager, k8sCache.DeletedFinalStateUnknown{Obj: namespace}, NamespaceSourceWatcher, time.Now().UTC())
if !ok {
t.Fatalf("expected removal bookkeeping to succeed")
}
if record.Phase != NamespacePhaseRemoved {
t.Fatalf("expected removed phase after bookkeeping, got %s", record.Phase)
}
}
func TestNamespaceManagerDispatchAdd(t *testing.T) {
manager := NewNamespaceManager()
manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})