From 89528c43bed409de8fb91acf8a8c9c39f301666e Mon Sep 17 00:00:00 2001 From: Ivo Gosemann Date: Tue, 18 Jul 2023 13:40:12 +0200 Subject: [PATCH] k8s.io/client-go: add OverridingClientConfig overriding RawConfig Kubernetes-commit: 740b4c456d731922196f8231df9ab585198696d6 --- tools/clientcmd/client_config.go | 34 ++++------ tools/clientcmd/client_config_test.go | 92 +++++++++++++-------------- 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/tools/clientcmd/client_config.go b/tools/clientcmd/client_config.go index 0880adfd..952f6d7e 100644 --- a/tools/clientcmd/client_config.go +++ b/tools/clientcmd/client_config.go @@ -72,6 +72,13 @@ type ClientConfig interface { ConfigAccess() ConfigAccess } +// OverridingClientConfig is used to enable overrriding the raw KubeConfig +type OverridingClientConfig interface { + ClientConfig + // MergedRawConfig return the RawConfig merged with all overrides. + MergedRawConfig() (clientcmdapi.Config, error) +} + type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister type promptedCredentials struct { @@ -91,22 +98,22 @@ type DirectClientConfig struct { } // NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name -func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) ClientConfig { +func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) OverridingClientConfig { return &DirectClientConfig{config, config.CurrentContext, overrides, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}} } // NewNonInteractiveClientConfig creates a DirectClientConfig using the passed context name and does not have a fallback reader for auth information -func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) ClientConfig { +func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) OverridingClientConfig { return &DirectClientConfig{config, contextName, overrides, nil, configAccess, promptedCredentials{}} } // NewInteractiveClientConfig creates a DirectClientConfig using the passed context name and a reader in case auth information is not provided via files or flags -func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) ClientConfig { +func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) OverridingClientConfig { return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess, promptedCredentials{}} } // NewClientConfigFromBytes takes your kubeconfig and gives you back a ClientConfig -func NewClientConfigFromBytes(configBytes []byte) (ClientConfig, error) { +func NewClientConfigFromBytes(configBytes []byte) (OverridingClientConfig, error) { config, err := Load(configBytes) if err != nil { return nil, err @@ -115,19 +122,6 @@ func NewClientConfigFromBytes(configBytes []byte) (ClientConfig, error) { return &DirectClientConfig{*config, "", &ConfigOverrides{}, nil, nil, promptedCredentials{}}, nil } -// NewClientConfigWithMergedRawConfig acts like a NewDefaultClientConfig but merges the RawConfig with the overrides -func NewClientConfigWithMergedRawConfig(config clientcmdapi.Config, overrides *ConfigOverrides) (ClientConfig, error) { - clientCfg := &DirectClientConfig{config, config.CurrentContext, overrides, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}} - - mergedRawCfg, err := clientCfg.getMergedRawConfig() - clientCfg.config = mergedRawCfg - if err != nil { - return nil, err - } - return clientCfg, nil - -} - // RESTConfigFromKubeConfig is a convenience method to give back a restconfig from your kubeconfig bytes. // For programmatic access, this is what you want 80% of the time func RESTConfigFromKubeConfig(configBytes []byte) (*restclient.Config, error) { @@ -142,12 +136,12 @@ func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) { return config.config, nil } -// getMergedRawConfig returns the raw kube config merged with the overrides -func (config *DirectClientConfig) getMergedRawConfig() (clientcmdapi.Config, error) { +// MergedRawConfig returns the raw kube config merged with the overrides +func (config *DirectClientConfig) MergedRawConfig() (clientcmdapi.Config, error) { if err := config.ConfirmUsable(); err != nil { return clientcmdapi.Config{}, err } - merged := clientcmdapi.NewConfig() + merged := config.config.DeepCopy() // set the AuthInfo merged with overrides in the merged config mergedAuthInfo, err := config.getAuthInfo() diff --git a/tools/clientcmd/client_config_test.go b/tools/clientcmd/client_config_test.go index ac68a4af..17d1b7b2 100644 --- a/tools/clientcmd/client_config_test.go +++ b/tools/clientcmd/client_config_test.go @@ -1015,70 +1015,66 @@ func TestCleanANSIEscapeCodes(t *testing.T) { } func TestMergeRawConfigDoOverride(t *testing.T) { - cfg := createValidTestConfig() + const ( + server = "https://anything.com:8080" + token = "the-token" + modifiedServer = "http://localhost:8081" + modifiedToken = "modified-token" + ) + config := createValidTestConfig() + // add another context which to modify with overrides + config.Clusters["modify"] = &clientcmdapi.Cluster{ + Server: server, + } + config.AuthInfos["modify"] = &clientcmdapi.AuthInfo{ + Token: token, + } + config.Contexts["modify"] = &clientcmdapi.Context{ + Cluster: "modify", + AuthInfo: "modify", + Namespace: "modify", + } + + // create overrides for the modify context overrides := &ConfigOverrides{ ClusterInfo: clientcmdapi.Cluster{ - Server: "http://localhost:8081", + Server: modifiedServer, }, Context: clientcmdapi.Context{ Namespace: "foobar", - Cluster: "clean", - AuthInfo: "clean", + Cluster: "modify", + AuthInfo: "modify", }, AuthInfo: clientcmdapi.AuthInfo{ - Token: "modified-token", + Token: modifiedToken, }, - CurrentContext: "clean", + CurrentContext: "modify", } - cut, err := NewClientConfigWithMergedRawConfig(*cfg, overrides) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - act, err := cut.RawConfig() + cut := NewDefaultClientConfig(*config, overrides) + act, err := cut.MergedRawConfig() if err != nil { t.Fatalf("Unexpected error: %v", err) } - if act.Clusters["clean"].Server != "http://localhost:8081" { - t.Errorf("Expected server %v, got %v", "http://localhost:8081", act.Clusters["clean"].Server) + // ensure overrides were applied to "modify" + actContext := act.CurrentContext + if actContext != "modify" { + t.Errorf("Expected context %v, got %v", "modify", actContext) + } + if act.Clusters[actContext].Server != "http://localhost:8081" { + t.Errorf("Expected server %v, got %v", "http://localhost:8081", act.Clusters[actContext].Server) + } + if act.Contexts[actContext].Namespace != "foobar" { + t.Errorf("Expected namespace %v, got %v", "foobar", act.Contexts[actContext].Namespace) } - if act.Contexts["clean"].Namespace != "foobar" { - t.Errorf("Expected namespace %v, got %v", "foobar", act.Contexts["clean"].Namespace) - } -} - -func TestMergeRawConfigDoNotOverride(t *testing.T) { - cfg := createValidTestConfig() - - overrides := &ConfigOverrides{ - ClusterInfo: clientcmdapi.Cluster{ - Server: "http://localhost:8081", - }, - Context: clientcmdapi.Context{ - Namespace: "foobar", - Cluster: "clean", - AuthInfo: "clean", - }, - AuthInfo: clientcmdapi.AuthInfo{ - Token: "modified-token", - }, - CurrentContext: "clean", - } - - cut := NewDefaultClientConfig(*cfg, overrides) - act, err := cut.RawConfig() - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - - if act.Clusters["clean"].Server != cfg.Clusters["clean"].Server { - t.Errorf("Expected server %v, got %v", cfg.Clusters["clean"].Server, act.Clusters["clean"].Server) - } - - if act.Contexts["clean"].Namespace != cfg.Contexts["clean"].Namespace { - t.Errorf("Expected namespace %v, got %v", cfg.Contexts["clean"].Namespace, act.Contexts["clean"].Namespace) + // ensure context "clean" was not touched + if act.Clusters["clean"].Server != config.Clusters["clean"].Server { + t.Errorf("Expected server %v, got %v", config.Clusters["clean"].Server, act.Clusters["clean"].Server) + } + if act.Contexts["clean"].Namespace != config.Contexts["clean"].Namespace { + t.Errorf("Expected namespace %v, got %v", config.Contexts["clean"].Namespace, act.Contexts["clean"].Namespace) } }