From 1b562b0d2cbb1d0376fe91ee80aa315d1ec168ac Mon Sep 17 00:00:00 2001 From: SinghaAnirban005 Date: Mon, 14 Jul 2025 19:27:17 +0530 Subject: [PATCH 1/4] backend: cmd: Extract logStartupInfo from createHeadlampHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Dudfield --- backend/cmd/headlamp.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/backend/cmd/headlamp.go b/backend/cmd/headlamp.go index 36dc659ea59..5a1007ddd52 100644 --- a/backend/cmd/headlamp.go +++ b/backend/cmd/headlamp.go @@ -406,14 +406,7 @@ func createHeadlampHandler(config *HeadlampConfig) http.Handler { config.StaticPluginDir = os.Getenv("HEADLAMP_STATIC_PLUGINS_DIR") - logger.Log(logger.LevelInfo, nil, nil, "Creating Headlamp handler") - logger.Log(logger.LevelInfo, nil, nil, "Listen address: "+fmt.Sprintf("%s:%d", config.ListenAddr, config.Port)) - logger.Log(logger.LevelInfo, nil, nil, "Kubeconfig path: "+kubeConfigPath) - logger.Log(logger.LevelInfo, nil, nil, "Static plugin dir: "+config.StaticPluginDir) - logger.Log(logger.LevelInfo, nil, nil, "Plugins dir: "+config.PluginDir) - logger.Log(logger.LevelInfo, nil, nil, "Dynamic clusters support: "+fmt.Sprint(config.EnableDynamicClusters)) - logger.Log(logger.LevelInfo, nil, nil, "Helm support: "+fmt.Sprint(config.EnableHelm)) - logger.Log(logger.LevelInfo, nil, nil, "Proxy URLs: "+fmt.Sprint(config.ProxyURLs)) + logStartupInfo(config); plugins.PopulatePluginsCache(config.StaticPluginDir, config.PluginDir, config.cache) @@ -838,6 +831,18 @@ func createHeadlampHandler(config *HeadlampConfig) http.Handler { return r } +// logStartupInfo logs config information of the Headlamp server. +func logStartupInfo(config *HeadlampConfig) { + logger.Log(logger.LevelInfo, nil, nil, "Creating Headlamp handler") + logger.Log(logger.LevelInfo, nil, nil, "Listen address: "+fmt.Sprintf("%s:%d", config.ListenAddr, config.Port)) + logger.Log(logger.LevelInfo, nil, nil, "Kubeconfig path: "+config.KubeConfigPath) + logger.Log(logger.LevelInfo, nil, nil, "Static plugin dir: "+config.StaticPluginDir) + logger.Log(logger.LevelInfo, nil, nil, "Plugins dir: "+config.PluginDir) + logger.Log(logger.LevelInfo, nil, nil, "Dynamic clusters support: "+fmt.Sprint(config.EnableDynamicClusters)) + logger.Log(logger.LevelInfo, nil, nil, "Helm support: "+fmt.Sprint(config.EnableHelm)) + logger.Log(logger.LevelInfo, nil, nil, "Proxy URLs: "+fmt.Sprint(config.ProxyURLs)) +} + func parseClusterAndToken(r *http.Request) (string, string) { cluster := "" re := regexp.MustCompile(`^/clusters/([^/]+)/.*`) From 69f76a701efaceaa32d6ac22d4808c3f60281835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Dudfield?= Date: Mon, 21 Jul 2025 14:14:18 +0200 Subject: [PATCH 2/4] backend: kubeconfig: Export ShouldBeSkippedFunc --- backend/pkg/kubeconfig/kubeconfig.go | 6 +++--- backend/pkg/kubeconfig/watcher.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/pkg/kubeconfig/kubeconfig.go b/backend/pkg/kubeconfig/kubeconfig.go index e9cf13796a7..6c58b53026b 100644 --- a/backend/pkg/kubeconfig/kubeconfig.go +++ b/backend/pkg/kubeconfig/kubeconfig.go @@ -969,7 +969,7 @@ func GetInClusterContext(oidcIssuerURL string, // Func type for context filter, if the func return true, // the context will be skipped otherwise the context will be used. -type shouldBeSkippedFunc = func(kubeContext Context) bool +type ShouldBeSkippedFunc = func(kubeContext Context) bool // AllowAllKubeContext will keep all contexts. func AllowAllKubeContext(_ Context) bool { @@ -980,7 +980,7 @@ func AllowAllKubeContext(_ Context) bool { // whose names are in the given comma-separated string. // For example, if pass the "a,b" for blackKubeContextNameStr, // the contexts named "a" and "b" will be skipped. -func SkipKubeContextInCommaSeparatedString(blackKubeContextNameStr string) shouldBeSkippedFunc { +func SkipKubeContextInCommaSeparatedString(blackKubeContextNameStr string) ShouldBeSkippedFunc { blackKubeContextNameList := strings.Split(blackKubeContextNameStr, ",") blackKubeContextNameMap := map[string]bool{} @@ -999,7 +999,7 @@ func SkipKubeContextInCommaSeparatedString(blackKubeContextNameStr string) shoul // Note: No need to remove contexts from the store, since // adding a context with the same name will overwrite the old one. func LoadAndStoreKubeConfigs(kubeConfigStore ContextStore, kubeConfigs string, source int, - ignoreFunc shouldBeSkippedFunc, + ignoreFunc ShouldBeSkippedFunc, ) error { var errs []error //nolint:prealloc diff --git a/backend/pkg/kubeconfig/watcher.go b/backend/pkg/kubeconfig/watcher.go index adb31cd6ab9..6200a00ac4d 100644 --- a/backend/pkg/kubeconfig/watcher.go +++ b/backend/pkg/kubeconfig/watcher.go @@ -14,7 +14,7 @@ import ( const watchInterval = 10 * time.Second // LoadAndWatchFiles loads kubeconfig files and watches them for changes. -func LoadAndWatchFiles(kubeConfigStore ContextStore, paths string, source int, ignoreFunc shouldBeSkippedFunc) { +func LoadAndWatchFiles(kubeConfigStore ContextStore, paths string, source int, ignoreFunc ShouldBeSkippedFunc) { // create ticker ticker := time.NewTicker(watchInterval) @@ -106,7 +106,7 @@ func addFilesToWatcher(watcher *fsnotify.Watcher, paths []string) { } // syncContexts synchronizes the contexts in the store with the ones in the kubeconfig files. -func syncContexts(kubeConfigStore ContextStore, paths string, source int, ignoreFunc shouldBeSkippedFunc) error { +func syncContexts(kubeConfigStore ContextStore, paths string, source int, ignoreFunc ShouldBeSkippedFunc) error { // First read all kubeconfig files to get new contexts newContexts, _, err := LoadContextsFromMultipleFiles(paths, source) if err != nil { From 83c653a2545f0a56b96347fd9914e9f472297a7b Mon Sep 17 00:00:00 2001 From: SinghaAnirban005 Date: Mon, 14 Jul 2025 19:31:13 +0530 Subject: [PATCH 3/4] backend: cmd: Extract setupPluginHandler from createHeadlampHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Dudfield --- backend/cmd/headlamp.go | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/backend/cmd/headlamp.go b/backend/cmd/headlamp.go index 5a1007ddd52..25807dbedfa 100644 --- a/backend/cmd/headlamp.go +++ b/backend/cmd/headlamp.go @@ -400,26 +400,27 @@ func addPluginListRoute(config *HeadlampConfig, r *mux.Router) { }).Methods("GET") } -//nolint:gocognit,funlen,gocyclo -func createHeadlampHandler(config *HeadlampConfig) http.Handler { - kubeConfigPath := config.KubeConfigPath - - config.StaticPluginDir = os.Getenv("HEADLAMP_STATIC_PLUGINS_DIR") - - logStartupInfo(config); - +// setupPluginHandlers initializes the plugin cache and sets up handlers for plugins. +func setupPluginHandlers(config *HeadlampConfig, skipFunc kubeconfig.ShouldBeSkippedFunc) { plugins.PopulatePluginsCache(config.StaticPluginDir, config.PluginDir, config.cache) - skipFunc := kubeconfig.SkipKubeContextInCommaSeparatedString(config.SkippedKubeContexts) - if !config.UseInCluster || config.WatchPluginsChanges { - // in-cluster mode is unlikely to want reloading plugins. pluginEventChan := make(chan string) go plugins.Watch(config.PluginDir, pluginEventChan) go plugins.HandlePluginEvents(config.StaticPluginDir, config.PluginDir, pluginEventChan, config.cache) - // in-cluster mode is unlikely to want reloading kubeconfig. - go kubeconfig.LoadAndWatchFiles(config.KubeConfigStore, kubeConfigPath, kubeconfig.KubeConfig, skipFunc) + go kubeconfig.LoadAndWatchFiles(config.KubeConfigStore, config.KubeConfigPath, kubeconfig.KubeConfig, skipFunc) } +} + +//nolint:gocognit,funlen,gocyclo +func createHeadlampHandler(config *HeadlampConfig) http.Handler { + kubeConfigPath := config.KubeConfigPath + + config.StaticPluginDir = os.Getenv("HEADLAMP_STATIC_PLUGINS_DIR") + + logStartupInfo(config) + skipFunc := kubeconfig.SkipKubeContextInCommaSeparatedString(config.SkippedKubeContexts) + setupPluginHandlers(config, skipFunc) // In-cluster if config.UseInCluster { From f3391322af9427ea65f46c41610124841de23a40 Mon Sep 17 00:00:00 2001 From: SinghaAnirban005 Date: Mon, 14 Jul 2025 19:42:31 +0530 Subject: [PATCH 4/4] backend: cmd: Extract setupInClusterContext from createHeadlampHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Dudfield --- backend/cmd/headlamp.go | 52 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/backend/cmd/headlamp.go b/backend/cmd/headlamp.go index 25807dbedfa..3c3e728ea8d 100644 --- a/backend/cmd/headlamp.go +++ b/backend/cmd/headlamp.go @@ -421,30 +421,7 @@ func createHeadlampHandler(config *HeadlampConfig) http.Handler { logStartupInfo(config) skipFunc := kubeconfig.SkipKubeContextInCommaSeparatedString(config.SkippedKubeContexts) setupPluginHandlers(config, skipFunc) - - // In-cluster - if config.UseInCluster { - context, err := kubeconfig.GetInClusterContext(config.oidcIdpIssuerURL, - config.oidcClientID, config.oidcClientSecret, - strings.Join(config.oidcScopes, ","), - config.oidcSkipTLSVerify, - config.oidcCACert) - if err != nil { - logger.Log(logger.LevelError, nil, err, "Failed to get in-cluster context") - } - - context.Source = kubeconfig.InCluster - - err = context.SetupProxy() - if err != nil { - logger.Log(logger.LevelError, nil, err, "Failed to setup proxy for in-cluster context") - } - - err = config.KubeConfigStore.AddContext(context) - if err != nil { - logger.Log(logger.LevelError, nil, err, "Failed to add in-cluster context") - } - } + setupInClusterContext(config) if config.StaticDir != "" { baseURLReplace(config.StaticDir, config.BaseURL) @@ -844,6 +821,33 @@ func logStartupInfo(config *HeadlampConfig) { logger.Log(logger.LevelInfo, nil, nil, "Proxy URLs: "+fmt.Sprint(config.ProxyURLs)) } +// setupInClusterContext prepares in-cluster context with OIDC authentication, +// sets up a proxy and adds it to the kubeconfig store. +func setupInClusterContext(config *HeadlampConfig) { + if config.UseInCluster { + context, err := kubeconfig.GetInClusterContext(config.oidcIdpIssuerURL, + config.oidcClientID, config.oidcClientSecret, + strings.Join(config.oidcScopes, ","), + config.oidcSkipTLSVerify, + config.oidcCACert) + if err != nil { + logger.Log(logger.LevelError, nil, err, "Failed to get in-cluster context") + } + + context.Source = kubeconfig.InCluster + + err = context.SetupProxy() + if err != nil { + logger.Log(logger.LevelError, nil, err, "Failed to setup proxy for in-cluster context") + } + + err = config.KubeConfigStore.AddContext(context) + if err != nil { + logger.Log(logger.LevelError, nil, err, "Failed to add in-cluster context") + } + } +} + func parseClusterAndToken(r *http.Request) (string, string) { cluster := "" re := regexp.MustCompile(`^/clusters/([^/]+)/.*`)