...

Source file src/k8s.io/client-go/tools/clientcmd/merged_client_builder.go

Documentation: k8s.io/client-go/tools/clientcmd

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package clientcmd
    18  
    19  import (
    20  	"io"
    21  	"sync"
    22  
    23  	"k8s.io/klog/v2"
    24  
    25  	restclient "k8s.io/client-go/rest"
    26  	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
    27  )
    28  
    29  // DeferredLoadingClientConfig is a ClientConfig interface that is backed by a client config loader.
    30  // It is used in cases where the loading rules may change after you've instantiated them and you want to be sure that
    31  // the most recent rules are used.  This is useful in cases where you bind flags to loading rule parameters before
    32  // the parse happens and you want your calling code to be ignorant of how the values are being mutated to avoid
    33  // passing extraneous information down a call stack
    34  type DeferredLoadingClientConfig struct {
    35  	loader         ClientConfigLoader
    36  	overrides      *ConfigOverrides
    37  	fallbackReader io.Reader
    38  
    39  	clientConfig ClientConfig
    40  	loadingLock  sync.Mutex
    41  
    42  	// provided for testing
    43  	icc InClusterConfig
    44  }
    45  
    46  // InClusterConfig abstracts details of whether the client is running in a cluster for testing.
    47  type InClusterConfig interface {
    48  	ClientConfig
    49  	Possible() bool
    50  }
    51  
    52  // NewNonInteractiveDeferredLoadingClientConfig creates a ClientConfig using the passed context name
    53  func NewNonInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides) ClientConfig {
    54  	return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, icc: &inClusterClientConfig{overrides: overrides}}
    55  }
    56  
    57  // NewInteractiveDeferredLoadingClientConfig creates a ClientConfig using the passed context name and the fallback auth reader
    58  func NewInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides, fallbackReader io.Reader) ClientConfig {
    59  	return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, icc: &inClusterClientConfig{overrides: overrides}, fallbackReader: fallbackReader}
    60  }
    61  
    62  func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) {
    63  	config.loadingLock.Lock()
    64  	defer config.loadingLock.Unlock()
    65  
    66  	if config.clientConfig != nil {
    67  		return config.clientConfig, nil
    68  	}
    69  	mergedConfig, err := config.loader.Load()
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	var currentContext string
    75  	if config.overrides != nil {
    76  		currentContext = config.overrides.CurrentContext
    77  	}
    78  	if config.fallbackReader != nil {
    79  		config.clientConfig = NewInteractiveClientConfig(*mergedConfig, currentContext, config.overrides, config.fallbackReader, config.loader)
    80  	} else {
    81  		config.clientConfig = NewNonInteractiveClientConfig(*mergedConfig, currentContext, config.overrides, config.loader)
    82  	}
    83  	return config.clientConfig, nil
    84  }
    85  
    86  func (config *DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, error) {
    87  	mergedConfig, err := config.createClientConfig()
    88  	if err != nil {
    89  		return clientcmdapi.Config{}, err
    90  	}
    91  
    92  	return mergedConfig.RawConfig()
    93  }
    94  
    95  // ClientConfig implements ClientConfig
    96  func (config *DeferredLoadingClientConfig) ClientConfig() (*restclient.Config, error) {
    97  	mergedClientConfig, err := config.createClientConfig()
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	// load the configuration and return on non-empty errors and if the
   103  	// content differs from the default config
   104  	mergedConfig, err := mergedClientConfig.ClientConfig()
   105  	switch {
   106  	case err != nil:
   107  		if !IsEmptyConfig(err) {
   108  			// return on any error except empty config
   109  			return nil, err
   110  		}
   111  	case mergedConfig != nil:
   112  		// the configuration is valid, but if this is equal to the defaults we should try
   113  		// in-cluster configuration
   114  		if !config.loader.IsDefaultConfig(mergedConfig) {
   115  			return mergedConfig, nil
   116  		}
   117  	}
   118  
   119  	// check for in-cluster configuration and use it
   120  	if config.icc.Possible() {
   121  		klog.V(4).Infof("Using in-cluster configuration")
   122  		return config.icc.ClientConfig()
   123  	}
   124  
   125  	// return the result of the merged client config
   126  	return mergedConfig, err
   127  }
   128  
   129  // Namespace implements KubeConfig
   130  func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) {
   131  	mergedKubeConfig, err := config.createClientConfig()
   132  	if err != nil {
   133  		return "", false, err
   134  	}
   135  
   136  	ns, overridden, err := mergedKubeConfig.Namespace()
   137  	// if we get an error and it is not empty config, or if the merged config defined an explicit namespace, or
   138  	// if in-cluster config is not possible, return immediately
   139  	if (err != nil && !IsEmptyConfig(err)) || overridden || !config.icc.Possible() {
   140  		// return on any error except empty config
   141  		return ns, overridden, err
   142  	}
   143  
   144  	if len(ns) > 0 {
   145  		// if we got a non-default namespace from the kubeconfig, use it
   146  		if ns != "default" {
   147  			return ns, false, nil
   148  		}
   149  
   150  		// if we got a default namespace, determine whether it was explicit or implicit
   151  		if raw, err := mergedKubeConfig.RawConfig(); err == nil {
   152  			// determine the current context
   153  			currentContext := raw.CurrentContext
   154  			if config.overrides != nil && len(config.overrides.CurrentContext) > 0 {
   155  				currentContext = config.overrides.CurrentContext
   156  			}
   157  			if context := raw.Contexts[currentContext]; context != nil && len(context.Namespace) > 0 {
   158  				return ns, false, nil
   159  			}
   160  		}
   161  	}
   162  
   163  	klog.V(4).Infof("Using in-cluster namespace")
   164  
   165  	// allow the namespace from the service account token directory to be used.
   166  	return config.icc.Namespace()
   167  }
   168  
   169  // ConfigAccess implements ClientConfig
   170  func (config *DeferredLoadingClientConfig) ConfigAccess() ConfigAccess {
   171  	return config.loader
   172  }
   173  

View as plain text