Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/cmd/headlamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
auth "github.com/kubernetes-sigs/headlamp/backend/pkg/auth"
"github.com/kubernetes-sigs/headlamp/backend/pkg/cache"
cfg "github.com/kubernetes-sigs/headlamp/backend/pkg/config"
"github.com/kubernetes-sigs/headlamp/backend/pkg/k8cache"
"github.com/kubernetes-sigs/headlamp/backend/pkg/serviceproxy"

headlampcfg "github.com/kubernetes-sigs/headlamp/backend/pkg/headlampconfig"
Expand Down Expand Up @@ -444,6 +445,8 @@ func createHeadlampHandler(config *HeadlampConfig) http.Handler {
pluginEventChan,
config.cache,
)
// Set the function to stop kubeconfig context watchers
kubeconfig.StopContextWatcher = k8cache.StopWatcher
// in-cluster mode is unlikely to want reloading kubeconfig.
go kubeconfig.LoadAndWatchFiles(config.KubeConfigStore, kubeConfigPath, kubeconfig.KubeConfig, skipFunc)
}
Expand Down
11 changes: 11 additions & 0 deletions backend/pkg/k8cache/cacheInvalidation.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@ func CheckForChanges(
go runWatcher(ctx, k8scache, contextKey, kContext)
}

// StopWatcher stops and cleans up the watcher for a given contextKey.
func StopWatcher(contextKey string) {
logger.Log(logger.LevelInfo, nil, nil, "stopping watcher for context: "+contextKey)

if cancelAny, ok := contextCancel.Load(contextKey); ok {
cancelAny.(context.CancelFunc)()
contextCancel.Delete(contextKey)
watcherRegistry.Delete(contextKey)
}
}
Comment on lines 164 to 173
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new StopWatcher function lacks unit tests even though cacheInvalidation.go already has tests for related behavior (e.g. RunInformerToWatch in cacheInvalidation_test.go). Given that this function is responsible for cancelling contexts and cleaning up watcherRegistry/contextCancel, adding tests to verify that it correctly removes entries, is safe when called for unknown contextKeys, and is idempotent would help ensure the watcher lifecycle behavior stays correct.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. but the thing is watchregistery is package bound … can’t import it in test file for unit test this function


// runWatcher is a long-lived goroutine that sets up and runs Kubernetes informers.
// It watches for resource changes and invalidates corresponding cache entries.
// This function will only exit when its context is cancelled.
Expand Down
6 changes: 6 additions & 0 deletions backend/pkg/kubeconfig/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (

const watchInterval = 10 * time.Second

var StopContextWatcher func(contextName string)

// LoadAndWatchFiles loads kubeconfig files and watches them for changes.
func LoadAndWatchFiles(kubeConfigStore ContextStore, paths string, source int, ignoreFunc shouldBeSkippedFunc) {
// create ticker
Expand Down Expand Up @@ -138,6 +140,10 @@ func syncContexts(kubeConfigStore ContextStore, paths string, source int, ignore
}

if !found {
if StopContextWatcher != nil {
StopContextWatcher(existingCtx.Name)
}

err := kubeConfigStore.RemoveContext(existingCtx.Name)
if err != nil {
logger.Log(logger.LevelError, nil, err, "error removing context")
Expand Down
Loading