2 Copyright 2014 The Kubernetes Authors.
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
25 restclient "k8s.io/client-go/rest"
26 clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
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
39 clientConfig ClientConfig
40 loadingLock sync.Mutex
42 // provided for testing
46 // InClusterConfig abstracts details of whether the client is running in a cluster for testing.
47 type InClusterConfig interface {
52 // NewNonInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name
53 func NewNonInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides) ClientConfig {
54 return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, icc: &inClusterClientConfig{overrides: overrides}}
57 // NewInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig 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}
62 func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) {
63 if config.clientConfig == nil {
64 config.loadingLock.Lock()
65 defer config.loadingLock.Unlock()
67 if config.clientConfig == nil {
68 mergedConfig, err := config.loader.Load()
73 var mergedClientConfig ClientConfig
74 if config.fallbackReader != nil {
75 mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader, config.loader)
77 mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.loader)
80 config.clientConfig = mergedClientConfig
84 return config.clientConfig, nil
87 func (config *DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, error) {
88 mergedConfig, err := config.createClientConfig()
90 return clientcmdapi.Config{}, err
93 return mergedConfig.RawConfig()
96 // ClientConfig implements ClientConfig
97 func (config *DeferredLoadingClientConfig) ClientConfig() (*restclient.Config, error) {
98 mergedClientConfig, err := config.createClientConfig()
103 // load the configuration and return on non-empty errors and if the
104 // content differs from the default config
105 mergedConfig, err := mergedClientConfig.ClientConfig()
108 if !IsEmptyConfig(err) {
109 // return on any error except empty config
112 case mergedConfig != nil:
113 // the configuration is valid, but if this is equal to the defaults we should try
114 // in-cluster configuration
115 if !config.loader.IsDefaultConfig(mergedConfig) {
116 return mergedConfig, nil
120 // check for in-cluster configuration and use it
121 if config.icc.Possible() {
122 klog.V(4).Infof("Using in-cluster configuration")
123 return config.icc.ClientConfig()
126 // return the result of the merged client config
127 return mergedConfig, err
130 // Namespace implements KubeConfig
131 func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) {
132 mergedKubeConfig, err := config.createClientConfig()
134 return "", false, err
137 ns, overridden, err := mergedKubeConfig.Namespace()
138 // if we get an error and it is not empty config, or if the merged config defined an explicit namespace, or
139 // if in-cluster config is not possible, return immediately
140 if (err != nil && !IsEmptyConfig(err)) || overridden || !config.icc.Possible() {
141 // return on any error except empty config
142 return ns, overridden, err
146 // if we got a non-default namespace from the kubeconfig, use it
148 return ns, false, nil
151 // if we got a default namespace, determine whether it was explicit or implicit
152 if raw, err := mergedKubeConfig.RawConfig(); err == nil {
153 if context := raw.Contexts[raw.CurrentContext]; context != nil && len(context.Namespace) > 0 {
154 return ns, false, nil
159 klog.V(4).Infof("Using in-cluster namespace")
161 // allow the namespace from the service account token directory to be used.
162 return config.icc.Namespace()
165 // ConfigAccess implements ClientConfig
166 func (config *DeferredLoadingClientConfig) ConfigAccess() ConfigAccess {