layer1: harden namespace watcher logging path
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
# 2026-04-26 — NamespaceManager rewrite, step 52
|
||||||
|
|
||||||
|
## Цель шага
|
||||||
|
|
||||||
|
Убрать хрупкость общего watcher path, где `nil` logger мог привести к panic на error/info ветках.
|
||||||
|
|
||||||
|
## Что изменено
|
||||||
|
|
||||||
|
1. Введена централизованная нормализация logger-а к `zap.NewNop()`.
|
||||||
|
2. Hardening применён к prepare/run/start и watcher event handlers.
|
||||||
|
3. Добавлены regression tests на nil-logger path.
|
||||||
|
|
||||||
|
## Почему это важно
|
||||||
|
|
||||||
|
- это уже runtime hardening, а не декоративный cleanup;
|
||||||
|
- общий helper layer стал безопаснее для повторного использования;
|
||||||
|
- поведение watcher-ов не меняется, меняется только устойчивость logging path.
|
||||||
@@ -119,7 +119,15 @@ func NewDefaultManagedNamespaceWatcherConfig(component string, subscriber Namesp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func namespaceManagerLogger(logger *zap.Logger) *zap.Logger {
|
||||||
|
if logger != nil {
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
return zap.NewNop()
|
||||||
|
}
|
||||||
|
|
||||||
func PrepareManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, config ManagedNamespaceWatcherConfig) (NamespaceManager, k8sCache.ResourceEventHandlerFuncs, error) {
|
func PrepareManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, config ManagedNamespaceWatcherConfig) (NamespaceManager, k8sCache.ResourceEventHandlerFuncs, error) {
|
||||||
|
logger = namespaceManagerLogger(logger)
|
||||||
strategy := config.RemovalStrategy
|
strategy := config.RemovalStrategy
|
||||||
if strategy == "" {
|
if strategy == "" {
|
||||||
strategy = NamespaceRemovalStrategyTrackOnly
|
strategy = NamespaceRemovalStrategyTrackOnly
|
||||||
@@ -131,6 +139,7 @@ func PrepareManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RunManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, kubeClient kubernetes.Interface, mgr managerPkg.Interface, config ManagedNamespaceWatcherConfig) (NamespaceManager, error) {
|
func RunManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, kubeClient kubernetes.Interface, mgr managerPkg.Interface, config ManagedNamespaceWatcherConfig) (NamespaceManager, error) {
|
||||||
|
logger = namespaceManagerLogger(logger)
|
||||||
manager, handlers, err := PrepareManagedNamespaceWatcher(ctx, logger, config)
|
manager, handlers, err := PrepareManagedNamespaceWatcher(ctx, logger, config)
|
||||||
StartManagedNamespaceWatcher(ctx, logger, config.Component, kubeClient, mgr, handlers)
|
StartManagedNamespaceWatcher(ctx, logger, config.Component, kubeClient, mgr, handlers)
|
||||||
LogNamespaceManagerSummary(logger, config.Component+": started namespace watcher", manager.Summary())
|
LogNamespaceManagerSummary(logger, config.Component+": started namespace watcher", manager.Summary())
|
||||||
@@ -187,6 +196,7 @@ func RecordNamespaceRemoval(manager NamespaceManager, obj interface{}, source Na
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HandleWatcherNamespaceAdd(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, namespace *corev1.Namespace) {
|
func HandleWatcherNamespaceAdd(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, namespace *corev1.Namespace) {
|
||||||
|
logger = namespaceManagerLogger(logger)
|
||||||
if namespace == nil || namespace.Name == "" {
|
if namespace == nil || namespace.Name == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -198,6 +208,7 @@ func HandleWatcherNamespaceAdd(ctx context.Context, logger *zap.Logger, componen
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HandleWatcherNamespaceUpdate(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, oldNamespace *corev1.Namespace, newNamespace *corev1.Namespace, strategy NamespaceRemovalStrategy) {
|
func HandleWatcherNamespaceUpdate(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, oldNamespace *corev1.Namespace, newNamespace *corev1.Namespace, strategy NamespaceRemovalStrategy) {
|
||||||
|
logger = namespaceManagerLogger(logger)
|
||||||
if newNamespace == nil {
|
if newNamespace == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -220,6 +231,7 @@ func HandleWatcherNamespaceDelete(ctx context.Context, logger *zap.Logger, compo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HandleWatcherNamespaceRemoval(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, obj interface{}, strategy NamespaceRemovalStrategy) {
|
func HandleWatcherNamespaceRemoval(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, obj interface{}, strategy NamespaceRemovalStrategy) {
|
||||||
|
logger = namespaceManagerLogger(logger)
|
||||||
record, ok := RecordNamespaceRemoval(manager, obj, NamespaceSourceWatcher, time.Now().UTC())
|
record, ok := RecordNamespaceRemoval(manager, obj, NamespaceSourceWatcher, time.Now().UTC())
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@@ -240,6 +252,7 @@ func HandleWatcherNamespaceRemoval(ctx context.Context, logger *zap.Logger, comp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewNamespaceWatcherEventHandlers(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, strategy NamespaceRemovalStrategy) k8sCache.ResourceEventHandlerFuncs {
|
func NewNamespaceWatcherEventHandlers(ctx context.Context, logger *zap.Logger, component string, manager NamespaceManager, strategy NamespaceRemovalStrategy) k8sCache.ResourceEventHandlerFuncs {
|
||||||
|
logger = namespaceManagerLogger(logger)
|
||||||
return k8sCache.ResourceEventHandlerFuncs{
|
return k8sCache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
namespace, ok := obj.(*corev1.Namespace)
|
namespace, ok := obj.(*corev1.Namespace)
|
||||||
@@ -261,6 +274,7 @@ func NewNamespaceWatcherEventHandlers(ctx context.Context, logger *zap.Logger, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StartManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, component string, kubeClient kubernetes.Interface, mgr managerPkg.Interface, handlers k8sCache.ResourceEventHandlerFuncs) {
|
func StartManagedNamespaceWatcher(ctx context.Context, logger *zap.Logger, component string, kubeClient kubernetes.Interface, mgr managerPkg.Interface, handlers k8sCache.ResourceEventHandlerFuncs) {
|
||||||
|
logger = namespaceManagerLogger(logger)
|
||||||
factory := k8sInformers.NewSharedInformerFactoryWithOptions(
|
factory := k8sInformers.NewSharedInformerFactoryWithOptions(
|
||||||
kubeClient,
|
kubeClient,
|
||||||
30*time.Minute,
|
30*time.Minute,
|
||||||
|
|||||||
@@ -407,6 +407,28 @@ func TestHandleWatcherNamespaceAddLogsSummary(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHandleWatcherNamespaceAddWithNilLogger(t *testing.T) {
|
||||||
|
manager := NewNamespaceManager()
|
||||||
|
router := &testNamespaceSubscriber{name: "router", addErr: errors.New("add failed")}
|
||||||
|
manager.Subscribe(router)
|
||||||
|
namespace := &corev1.Namespace{}
|
||||||
|
namespace.Name = "tenant-a"
|
||||||
|
namespace.Labels = map[string]string{ManagedNamespaceLabelKey: ManagedNamespaceLabelValue}
|
||||||
|
|
||||||
|
HandleWatcherNamespaceAdd(context.Background(), nil, "router.NSWatcher", manager, namespace)
|
||||||
|
|
||||||
|
record, ok := manager.Get("tenant-a")
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected tenant-a to exist after add handling")
|
||||||
|
}
|
||||||
|
if record.Phase != NamespacePhaseFailed {
|
||||||
|
t.Fatalf("expected failed phase after subscriber error, got %s", record.Phase)
|
||||||
|
}
|
||||||
|
if router.addCalls != 1 {
|
||||||
|
t.Fatalf("expected failing subscriber to be called once")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandleWatcherNamespaceRemovalDispatch(t *testing.T) {
|
func TestHandleWatcherNamespaceRemovalDispatch(t *testing.T) {
|
||||||
manager := NewNamespaceManager()
|
manager := NewNamespaceManager()
|
||||||
router := &testNamespaceSubscriber{name: "router"}
|
router := &testNamespaceSubscriber{name: "router"}
|
||||||
@@ -554,6 +576,25 @@ func TestRunManagedNamespaceWatcherLogsStartedSummary(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunManagedNamespaceWatcherWithNilLogger(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
router := &testNamespaceSubscriber{name: "router"}
|
||||||
|
|
||||||
|
manager, err := RunManagedNamespaceWatcher(ctx, nil, 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)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual([]string{"tenant-a"}, manager.Snapshot()) {
|
||||||
|
t.Fatalf("expected watcher manager snapshot to contain bootstrapped namespace")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewDefaultManagedNamespaceWatcherConfig(t *testing.T) {
|
func TestNewDefaultManagedNamespaceWatcherConfig(t *testing.T) {
|
||||||
resolver := DefaultNSResolver()
|
resolver := DefaultNSResolver()
|
||||||
original := resolver.FissionResourceNS
|
original := resolver.FissionResourceNS
|
||||||
|
|||||||
Reference in New Issue
Block a user