From 447133d5b2c18c1ebb1238794b409560b45d4655 Mon Sep 17 00:00:00 2001 From: Naeel Date: Sun, 26 Apr 2026 10:39:59 +0300 Subject: [PATCH] layer1: track namespace removals in manager --- .../2026-04-26-namespace-manager-step35.md | 20 ++++++++++++++++ pkg/buildermgr/ns_watcher.go | 24 +++++++++++++++++-- pkg/executor/multitenant/ns_watcher.go | 19 ++++++++++++++- pkg/router/ns_watcher.go | 24 +++++++++++++++++-- 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 doc/thinking/2026-04-26-namespace-manager-step35.md diff --git a/doc/thinking/2026-04-26-namespace-manager-step35.md b/doc/thinking/2026-04-26-namespace-manager-step35.md new file mode 100644 index 00000000..17c5d481 --- /dev/null +++ b/doc/thinking/2026-04-26-namespace-manager-step35.md @@ -0,0 +1,20 @@ +# 2026-04-26 — NamespaceManager rewrite, step 35 + +## Цель шага + +Научить watcher-ы фиксировать label-drop/delete в локальном `NamespaceManager`, не трогая реальные runtime регистрации. + +## Что меняем + +1. Во все три namespace watcher-а добавляем: + - `DeleteFunc` + - обработку `managed -> unmanaged` в `UpdateFunc` +2. При таком событии watcher: + - создаёт `NamespaceEventRemove` + - записывает его в manager через `Upsert()` + - пишет явный log, что runtime cleanup НЕ выполняется + +## Что НЕ меняем + +- не вызываем `DispatchRemove()` из watcher-ов; +- не удаляем informer-ы, resolver state или runtime registrations. \ No newline at end of file diff --git a/pkg/buildermgr/ns_watcher.go b/pkg/buildermgr/ns_watcher.go index 5b78898a..2df9b698 100644 --- a/pkg/buildermgr/ns_watcher.go +++ b/pkg/buildermgr/ns_watcher.go @@ -58,9 +58,20 @@ func StartNSWatcher( zap.String("namespace", nsObj.Name), zap.Error(err)) } }, - UpdateFunc: func(_, newObj interface{}) { + UpdateFunc: func(oldObj, newObj interface{}) { nsObj, ok := newObj.(*corev1.Namespace) - if !ok || !utils.IsManagedNamespace(nsObj.Labels) { + if !ok { + return + } + oldNSObj, _ := oldObj.(*corev1.Namespace) + if oldNSObj != nil && utils.IsManagedNamespace(oldNSObj.Labels) && !utils.IsManagedNamespace(nsObj.Labels) { + event := utils.NamespaceEventFromNamespace(utils.NamespaceEventRemove, nsObj, utils.NamespaceSourceWatcher, time.Now().UTC()) + nsManager.Upsert(event) + logger.Info("buildermgr.NSWatcher: namespace removed from manager state; runtime registrations kept", + zap.String("namespace", nsObj.Name)) + return + } + if !utils.IsManagedNamespace(nsObj.Labels) { return } nsManager.Upsert(utils.NamespaceEventFromNamespace(utils.NamespaceEventUpdate, nsObj, utils.NamespaceSourceWatcher, time.Now().UTC())) @@ -69,6 +80,15 @@ func StartNSWatcher( zap.String("namespace", nsObj.Name), zap.Error(err)) } }, + DeleteFunc: func(obj interface{}) { + event := utils.NamespaceEventFromObject(utils.NamespaceEventRemove, obj, utils.NamespaceSourceWatcher, time.Now().UTC()) + if event.Name == "" { + return + } + nsManager.Upsert(event) + logger.Info("buildermgr.NSWatcher: namespace deleted from manager state; runtime registrations kept", + zap.String("namespace", event.Name)) + }, }) mgr.Add(ctx, func(ctx context.Context) { diff --git a/pkg/executor/multitenant/ns_watcher.go b/pkg/executor/multitenant/ns_watcher.go index 973f43da..f9904e80 100644 --- a/pkg/executor/multitenant/ns_watcher.go +++ b/pkg/executor/multitenant/ns_watcher.go @@ -127,11 +127,19 @@ func StartNSWatcher( }, // UpdateFunc fires when an existing Namespace is updated — covers the case // where the label is added to a pre-existing Namespace. - UpdateFunc: func(_, newObj interface{}) { + UpdateFunc: func(oldObj, newObj interface{}) { nsObj, ok := newObj.(*corev1.Namespace) if !ok { return } + oldNSObj, _ := oldObj.(*corev1.Namespace) + if oldNSObj != nil && utils.IsManagedNamespace(oldNSObj.Labels) && !utils.IsManagedNamespace(nsObj.Labels) { + event := utils.NamespaceEventFromNamespace(utils.NamespaceEventRemove, nsObj, utils.NamespaceSourceWatcher, time.Now().UTC()) + nsManager.Upsert(event) + logger.Info("multitenant.NSWatcher: namespace removed from manager state; runtime registrations kept", + zap.String("namespace", nsObj.Name)) + return + } if !utils.IsManagedNamespace(nsObj.Labels) { return // label was removed — nothing to do (executor keeps existing registrations) } @@ -141,6 +149,15 @@ func StartNSWatcher( zap.String("namespace", nsObj.Name), zap.Error(err)) } }, + DeleteFunc: func(obj interface{}) { + event := utils.NamespaceEventFromObject(utils.NamespaceEventRemove, obj, utils.NamespaceSourceWatcher, time.Now().UTC()) + if event.Name == "" { + return + } + nsManager.Upsert(event) + logger.Info("multitenant.NSWatcher: namespace deleted from manager state; runtime registrations kept", + zap.String("namespace", event.Name)) + }, }) mgr.Add(ctx, func(ctx context.Context) { diff --git a/pkg/router/ns_watcher.go b/pkg/router/ns_watcher.go index 84591480..154ba451 100644 --- a/pkg/router/ns_watcher.go +++ b/pkg/router/ns_watcher.go @@ -58,9 +58,20 @@ func StartNSWatcher( zap.String("namespace", nsObj.Name), zap.Error(err)) } }, - UpdateFunc: func(_, newObj interface{}) { + UpdateFunc: func(oldObj, newObj interface{}) { nsObj, ok := newObj.(*corev1.Namespace) - if !ok || !utils.IsManagedNamespace(nsObj.Labels) { + if !ok { + return + } + oldNSObj, _ := oldObj.(*corev1.Namespace) + if oldNSObj != nil && utils.IsManagedNamespace(oldNSObj.Labels) && !utils.IsManagedNamespace(nsObj.Labels) { + event := utils.NamespaceEventFromNamespace(utils.NamespaceEventRemove, nsObj, utils.NamespaceSourceWatcher, time.Now().UTC()) + nsManager.Upsert(event) + logger.Info("router.NSWatcher: namespace removed from manager state; runtime registrations kept", + zap.String("namespace", nsObj.Name)) + return + } + if !utils.IsManagedNamespace(nsObj.Labels) { return } nsManager.Upsert(utils.NamespaceEventFromNamespace(utils.NamespaceEventUpdate, nsObj, utils.NamespaceSourceWatcher, time.Now().UTC())) @@ -69,6 +80,15 @@ func StartNSWatcher( zap.String("namespace", nsObj.Name), zap.Error(err)) } }, + DeleteFunc: func(obj interface{}) { + event := utils.NamespaceEventFromObject(utils.NamespaceEventRemove, obj, utils.NamespaceSourceWatcher, time.Now().UTC()) + if event.Name == "" { + return + } + nsManager.Upsert(event) + logger.Info("router.NSWatcher: namespace deleted from manager state; runtime registrations kept", + zap.String("namespace", event.Name)) + }, }) mgr.Add(ctx, func(ctx context.Context) {