Merge pull request #21266 from deads2k/only-load-kubeconfig-once

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2016-02-20 14:00:38 -08:00
commit 3efdc1e08b
3 changed files with 68 additions and 56 deletions

View File

@ -67,25 +67,25 @@ type DirectClientConfig struct {
// NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name
func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) ClientConfig {
return DirectClientConfig{config, config.CurrentContext, overrides, nil}
return &DirectClientConfig{config, config.CurrentContext, overrides, nil}
}
// 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) ClientConfig {
return DirectClientConfig{config, contextName, overrides, nil}
return &DirectClientConfig{config, contextName, overrides, nil}
}
// 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) ClientConfig {
return DirectClientConfig{config, contextName, overrides, fallbackReader}
return &DirectClientConfig{config, contextName, overrides, fallbackReader}
}
func (config DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
return config.config, nil
}
// ClientConfig implements ClientConfig
func (config DirectClientConfig) ClientConfig() (*client.Config, error) {
func (config *DirectClientConfig) ClientConfig() (*client.Config, error) {
if err := config.ConfirmUsable(); err != nil {
return nil, err
}
@ -217,7 +217,7 @@ func canIdentifyUser(config client.Config) bool {
}
// Namespace implements KubeConfig
func (config DirectClientConfig) Namespace() (string, bool, error) {
func (config *DirectClientConfig) Namespace() (string, bool, error) {
if err := config.ConfirmUsable(); err != nil {
return "", false, err
}
@ -237,7 +237,7 @@ func (config DirectClientConfig) Namespace() (string, bool, error) {
// ConfirmUsable looks a particular context and determines if that particular part of the config is useable. There might still be errors in the config,
// but no errors in the sections requested or referenced. It does not return early so that it can find as many errors as possible.
func (config DirectClientConfig) ConfirmUsable() error {
func (config *DirectClientConfig) ConfirmUsable() error {
validationErrors := make([]error, 0)
validationErrors = append(validationErrors, validateAuthInfo(config.getAuthInfoName(), config.getAuthInfo())...)
validationErrors = append(validationErrors, validateClusterInfo(config.getClusterName(), config.getCluster())...)
@ -249,7 +249,7 @@ func (config DirectClientConfig) ConfirmUsable() error {
return newErrConfigurationInvalid(validationErrors)
}
func (config DirectClientConfig) getContextName() string {
func (config *DirectClientConfig) getContextName() string {
if len(config.overrides.CurrentContext) != 0 {
return config.overrides.CurrentContext
}
@ -260,21 +260,21 @@ func (config DirectClientConfig) getContextName() string {
return config.config.CurrentContext
}
func (config DirectClientConfig) getAuthInfoName() string {
func (config *DirectClientConfig) getAuthInfoName() string {
if len(config.overrides.Context.AuthInfo) != 0 {
return config.overrides.Context.AuthInfo
}
return config.getContext().AuthInfo
}
func (config DirectClientConfig) getClusterName() string {
func (config *DirectClientConfig) getClusterName() string {
if len(config.overrides.Context.Cluster) != 0 {
return config.overrides.Context.Cluster
}
return config.getContext().Cluster
}
func (config DirectClientConfig) getContext() clientcmdapi.Context {
func (config *DirectClientConfig) getContext() clientcmdapi.Context {
contexts := config.config.Contexts
contextName := config.getContextName()
@ -287,7 +287,7 @@ func (config DirectClientConfig) getContext() clientcmdapi.Context {
return mergedContext
}
func (config DirectClientConfig) getAuthInfo() clientcmdapi.AuthInfo {
func (config *DirectClientConfig) getAuthInfo() clientcmdapi.AuthInfo {
authInfos := config.config.AuthInfos
authInfoName := config.getAuthInfoName()
@ -300,7 +300,7 @@ func (config DirectClientConfig) getAuthInfo() clientcmdapi.AuthInfo {
return mergedAuthInfo
}
func (config DirectClientConfig) getCluster() clientcmdapi.Cluster {
func (config *DirectClientConfig) getCluster() clientcmdapi.Cluster {
clusterInfos := config.config.Clusters
clusterInfoName := config.getClusterName()

View File

@ -117,23 +117,41 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
} else {
kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)
}
kubeconfigs := []*clientcmdapi.Config{}
// read and cache the config files so that we only look at them once
for _, filename := range kubeConfigFiles {
if len(filename) == 0 {
// no work to do
continue
}
config, err := LoadFromFile(filename)
if os.IsNotExist(err) {
// skip missing files
continue
}
if err != nil {
errlist = append(errlist, fmt.Errorf("Error loading config file \"%s\": %v", filename, err))
continue
}
kubeconfigs = append(kubeconfigs, config)
}
// first merge all of our maps
mapConfig := clientcmdapi.NewConfig()
for _, file := range kubeConfigFiles {
if err := mergeConfigWithFile(mapConfig, file); err != nil {
errlist = append(errlist, err)
}
for _, kubeconfig := range kubeconfigs {
mergo.Merge(mapConfig, kubeconfig)
}
// merge all of the struct values in the reverse order so that priority is given correctly
// errors are not added to the list the second time
nonMapConfig := clientcmdapi.NewConfig()
for i := len(kubeConfigFiles) - 1; i >= 0; i-- {
file := kubeConfigFiles[i]
mergeConfigWithFile(nonMapConfig, file)
for i := len(kubeconfigs) - 1; i >= 0; i-- {
kubeconfig := kubeconfigs[i]
mergo.Merge(nonMapConfig, kubeconfig)
}
// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
@ -198,25 +216,6 @@ func (rules *ClientConfigLoadingRules) Migrate() error {
return nil
}
func mergeConfigWithFile(startingConfig *clientcmdapi.Config, filename string) error {
if len(filename) == 0 {
// no work to do
return nil
}
config, err := LoadFromFile(filename)
if os.IsNotExist(err) {
return nil
}
if err != nil {
return fmt.Errorf("Error loading config file \"%s\": %v", filename, err)
}
mergo.Merge(startingConfig, config)
return nil
}
// LoadFromFile takes a filename and deserializes the contents into Config object
func LoadFromFile(filename string) (*clientcmdapi.Config, error) {
kubeconfigBytes, err := ioutil.ReadFile(filename)

View File

@ -19,6 +19,7 @@ package clientcmd
import (
"io"
"reflect"
"sync"
"github.com/golang/glog"
@ -35,35 +36,47 @@ type DeferredLoadingClientConfig struct {
loadingRules *ClientConfigLoadingRules
overrides *ConfigOverrides
fallbackReader io.Reader
clientConfig ClientConfig
loadingLock sync.Mutex
}
// NewNonInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name
func NewNonInteractiveDeferredLoadingClientConfig(loadingRules *ClientConfigLoadingRules, overrides *ConfigOverrides) ClientConfig {
return DeferredLoadingClientConfig{loadingRules, overrides, nil}
return &DeferredLoadingClientConfig{loadingRules: loadingRules, overrides: overrides}
}
// NewInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name and the fallback auth reader
func NewInteractiveDeferredLoadingClientConfig(loadingRules *ClientConfigLoadingRules, overrides *ConfigOverrides, fallbackReader io.Reader) ClientConfig {
return DeferredLoadingClientConfig{loadingRules, overrides, fallbackReader}
return &DeferredLoadingClientConfig{loadingRules: loadingRules, overrides: overrides, fallbackReader: fallbackReader}
}
func (config DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) {
mergedConfig, err := config.loadingRules.Load()
if err != nil {
return nil, err
func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) {
if config.clientConfig == nil {
config.loadingLock.Lock()
defer config.loadingLock.Unlock()
if config.clientConfig == nil {
mergedConfig, err := config.loadingRules.Load()
if err != nil {
return nil, err
}
var mergedClientConfig ClientConfig
if config.fallbackReader != nil {
mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader)
} else {
mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides)
}
config.clientConfig = mergedClientConfig
}
}
var mergedClientConfig ClientConfig
if config.fallbackReader != nil {
mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader)
} else {
mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides)
}
return mergedClientConfig, nil
return config.clientConfig, nil
}
func (config DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, error) {
func (config *DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, error) {
mergedConfig, err := config.createClientConfig()
if err != nil {
return clientcmdapi.Config{}, err
@ -73,7 +86,7 @@ func (config DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, erro
}
// ClientConfig implements ClientConfig
func (config DeferredLoadingClientConfig) ClientConfig() (*client.Config, error) {
func (config *DeferredLoadingClientConfig) ClientConfig() (*client.Config, error) {
mergedClientConfig, err := config.createClientConfig()
if err != nil {
return nil, err
@ -94,7 +107,7 @@ func (config DeferredLoadingClientConfig) ClientConfig() (*client.Config, error)
}
// Namespace implements KubeConfig
func (config DeferredLoadingClientConfig) Namespace() (string, bool, error) {
func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) {
mergedKubeConfig, err := config.createClientConfig()
if err != nil {
return "", false, err