k8s.io/client-go: add OverridingClientConfig overriding RawConfig

Kubernetes-commit: 740b4c456d731922196f8231df9ab585198696d6
This commit is contained in:
Ivo Gosemann 2023-07-18 13:40:12 +02:00 committed by Kubernetes Publisher
parent 17b5405ddb
commit 89528c43be
2 changed files with 58 additions and 68 deletions

View File

@ -72,6 +72,13 @@ type ClientConfig interface {
ConfigAccess() ConfigAccess 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 PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister
type promptedCredentials struct { type promptedCredentials struct {
@ -91,22 +98,22 @@ type DirectClientConfig struct {
} }
// NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name // 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{}} 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 // 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{}} 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 // 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{}} return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess, promptedCredentials{}}
} }
// NewClientConfigFromBytes takes your kubeconfig and gives you back a ClientConfig // 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) config, err := Load(configBytes)
if err != nil { if err != nil {
return nil, err return nil, err
@ -115,19 +122,6 @@ func NewClientConfigFromBytes(configBytes []byte) (ClientConfig, error) {
return &DirectClientConfig{*config, "", &ConfigOverrides{}, nil, nil, promptedCredentials{}}, nil 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. // 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 // For programmatic access, this is what you want 80% of the time
func RESTConfigFromKubeConfig(configBytes []byte) (*restclient.Config, error) { func RESTConfigFromKubeConfig(configBytes []byte) (*restclient.Config, error) {
@ -142,12 +136,12 @@ func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
return config.config, nil return config.config, nil
} }
// getMergedRawConfig returns the raw kube config merged with the overrides // MergedRawConfig returns the raw kube config merged with the overrides
func (config *DirectClientConfig) getMergedRawConfig() (clientcmdapi.Config, error) { func (config *DirectClientConfig) MergedRawConfig() (clientcmdapi.Config, error) {
if err := config.ConfirmUsable(); err != nil { if err := config.ConfirmUsable(); err != nil {
return clientcmdapi.Config{}, err return clientcmdapi.Config{}, err
} }
merged := clientcmdapi.NewConfig() merged := config.config.DeepCopy()
// set the AuthInfo merged with overrides in the merged config // set the AuthInfo merged with overrides in the merged config
mergedAuthInfo, err := config.getAuthInfo() mergedAuthInfo, err := config.getAuthInfo()

View File

@ -1015,70 +1015,66 @@ func TestCleanANSIEscapeCodes(t *testing.T) {
} }
func TestMergeRawConfigDoOverride(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{ overrides := &ConfigOverrides{
ClusterInfo: clientcmdapi.Cluster{ ClusterInfo: clientcmdapi.Cluster{
Server: "http://localhost:8081", Server: modifiedServer,
}, },
Context: clientcmdapi.Context{ Context: clientcmdapi.Context{
Namespace: "foobar", Namespace: "foobar",
Cluster: "clean", Cluster: "modify",
AuthInfo: "clean", AuthInfo: "modify",
}, },
AuthInfo: clientcmdapi.AuthInfo{ AuthInfo: clientcmdapi.AuthInfo{
Token: "modified-token", Token: modifiedToken,
}, },
CurrentContext: "clean", CurrentContext: "modify",
} }
cut, err := NewClientConfigWithMergedRawConfig(*cfg, overrides) cut := NewDefaultClientConfig(*config, overrides)
if err != nil { act, err := cut.MergedRawConfig()
t.Fatalf("Unexpected error: %v", err)
}
act, err := cut.RawConfig()
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if act.Clusters["clean"].Server != "http://localhost:8081" { // ensure overrides were applied to "modify"
t.Errorf("Expected server %v, got %v", "http://localhost:8081", act.Clusters["clean"].Server) 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" { // ensure context "clean" was not touched
t.Errorf("Expected namespace %v, got %v", "foobar", act.Contexts["clean"].Namespace) 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 {
func TestMergeRawConfigDoNotOverride(t *testing.T) { t.Errorf("Expected namespace %v, got %v", config.Contexts["clean"].Namespace, act.Contexts["clean"].Namespace)
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)
} }
} }