Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / k8s.io / client-go / tools / clientcmd / client_config.go
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         "fmt"
21         "io"
22         "io/ioutil"
23         "net/url"
24         "os"
25         "strings"
26
27         "github.com/imdario/mergo"
28         "k8s.io/klog"
29
30         restclient "k8s.io/client-go/rest"
31         clientauth "k8s.io/client-go/tools/auth"
32         clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
33 )
34
35 var (
36         // ClusterDefaults has the same behavior as the old EnvVar and DefaultCluster fields
37         // DEPRECATED will be replaced
38         ClusterDefaults = clientcmdapi.Cluster{Server: getDefaultServer()}
39         // DefaultClientConfig represents the legacy behavior of this package for defaulting
40         // DEPRECATED will be replace
41         DefaultClientConfig = DirectClientConfig{*clientcmdapi.NewConfig(), "", &ConfigOverrides{
42                 ClusterDefaults: ClusterDefaults,
43         }, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}}
44 )
45
46 // getDefaultServer returns a default setting for DefaultClientConfig
47 // DEPRECATED
48 func getDefaultServer() string {
49         if server := os.Getenv("KUBERNETES_MASTER"); len(server) > 0 {
50                 return server
51         }
52         return "http://localhost:8080"
53 }
54
55 // ClientConfig is used to make it easy to get an api server client
56 type ClientConfig interface {
57         // RawConfig returns the merged result of all overrides
58         RawConfig() (clientcmdapi.Config, error)
59         // ClientConfig returns a complete client config
60         ClientConfig() (*restclient.Config, error)
61         // Namespace returns the namespace resulting from the merged
62         // result of all overrides and a boolean indicating if it was
63         // overridden
64         Namespace() (string, bool, error)
65         // ConfigAccess returns the rules for loading/persisting the config.
66         ConfigAccess() ConfigAccess
67 }
68
69 type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister
70
71 type promptedCredentials struct {
72         username string
73         password string
74 }
75
76 // DirectClientConfig is a ClientConfig interface that is backed by a clientcmdapi.Config, options overrides, and an optional fallbackReader for auth information
77 type DirectClientConfig struct {
78         config         clientcmdapi.Config
79         contextName    string
80         overrides      *ConfigOverrides
81         fallbackReader io.Reader
82         configAccess   ConfigAccess
83         // promptedCredentials store the credentials input by the user
84         promptedCredentials promptedCredentials
85 }
86
87 // NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name
88 func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) ClientConfig {
89         return &DirectClientConfig{config, config.CurrentContext, overrides, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}}
90 }
91
92 // NewNonInteractiveClientConfig creates a DirectClientConfig using the passed context name and does not have a fallback reader for auth information
93 func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) ClientConfig {
94         return &DirectClientConfig{config, contextName, overrides, nil, configAccess, promptedCredentials{}}
95 }
96
97 // NewInteractiveClientConfig creates a DirectClientConfig using the passed context name and a reader in case auth information is not provided via files or flags
98 func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) ClientConfig {
99         return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess, promptedCredentials{}}
100 }
101
102 // NewClientConfigFromBytes takes your kubeconfig and gives you back a ClientConfig
103 func NewClientConfigFromBytes(configBytes []byte) (ClientConfig, error) {
104         config, err := Load(configBytes)
105         if err != nil {
106                 return nil, err
107         }
108
109         return &DirectClientConfig{*config, "", &ConfigOverrides{}, nil, nil, promptedCredentials{}}, nil
110 }
111
112 // RESTConfigFromKubeConfig is a convenience method to give back a restconfig from your kubeconfig bytes.
113 // For programmatic access, this is what you want 80% of the time
114 func RESTConfigFromKubeConfig(configBytes []byte) (*restclient.Config, error) {
115         clientConfig, err := NewClientConfigFromBytes(configBytes)
116         if err != nil {
117                 return nil, err
118         }
119         return clientConfig.ClientConfig()
120 }
121
122 func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
123         return config.config, nil
124 }
125
126 // ClientConfig implements ClientConfig
127 func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
128         // check that getAuthInfo, getContext, and getCluster do not return an error.
129         // Do this before checking if the current config is usable in the event that an
130         // AuthInfo, Context, or Cluster config with user-defined names are not found.
131         // This provides a user with the immediate cause for error if one is found
132         configAuthInfo, err := config.getAuthInfo()
133         if err != nil {
134                 return nil, err
135         }
136
137         _, err = config.getContext()
138         if err != nil {
139                 return nil, err
140         }
141
142         configClusterInfo, err := config.getCluster()
143         if err != nil {
144                 return nil, err
145         }
146
147         if err := config.ConfirmUsable(); err != nil {
148                 return nil, err
149         }
150
151         clientConfig := &restclient.Config{}
152         clientConfig.Host = configClusterInfo.Server
153
154         if len(config.overrides.Timeout) > 0 {
155                 timeout, err := ParseTimeout(config.overrides.Timeout)
156                 if err != nil {
157                         return nil, err
158                 }
159                 clientConfig.Timeout = timeout
160         }
161
162         if u, err := url.ParseRequestURI(clientConfig.Host); err == nil && u.Opaque == "" && len(u.Path) > 1 {
163                 u.RawQuery = ""
164                 u.Fragment = ""
165                 clientConfig.Host = u.String()
166         }
167         if len(configAuthInfo.Impersonate) > 0 {
168                 clientConfig.Impersonate = restclient.ImpersonationConfig{
169                         UserName: configAuthInfo.Impersonate,
170                         Groups:   configAuthInfo.ImpersonateGroups,
171                         Extra:    configAuthInfo.ImpersonateUserExtra,
172                 }
173         }
174
175         // only try to read the auth information if we are secure
176         if restclient.IsConfigTransportTLS(*clientConfig) {
177                 var err error
178                 var persister restclient.AuthProviderConfigPersister
179                 if config.configAccess != nil {
180                         authInfoName, _ := config.getAuthInfoName()
181                         persister = PersisterForUser(config.configAccess, authInfoName)
182                 }
183                 userAuthPartialConfig, err := config.getUserIdentificationPartialConfig(configAuthInfo, config.fallbackReader, persister)
184                 if err != nil {
185                         return nil, err
186                 }
187                 mergo.MergeWithOverwrite(clientConfig, userAuthPartialConfig)
188
189                 serverAuthPartialConfig, err := getServerIdentificationPartialConfig(configAuthInfo, configClusterInfo)
190                 if err != nil {
191                         return nil, err
192                 }
193                 mergo.MergeWithOverwrite(clientConfig, serverAuthPartialConfig)
194         }
195
196         return clientConfig, nil
197 }
198
199 // clientauth.Info object contain both user identification and server identification.  We want different precedence orders for
200 // both, so we have to split the objects and merge them separately
201 // we want this order of precedence for the server identification
202 // 1.  configClusterInfo (the final result of command line flags and merged .kubeconfig files)
203 // 2.  configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
204 // 3.  load the ~/.kubernetes_auth file as a default
205 func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*restclient.Config, error) {
206         mergedConfig := &restclient.Config{}
207
208         // configClusterInfo holds the information identify the server provided by .kubeconfig
209         configClientConfig := &restclient.Config{}
210         configClientConfig.CAFile = configClusterInfo.CertificateAuthority
211         configClientConfig.CAData = configClusterInfo.CertificateAuthorityData
212         configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
213         mergo.MergeWithOverwrite(mergedConfig, configClientConfig)
214
215         return mergedConfig, nil
216 }
217
218 // clientauth.Info object contain both user identification and server identification.  We want different precedence orders for
219 // both, so we have to split the objects and merge them separately
220 // we want this order of precedence for user identification
221 // 1.  configAuthInfo minus auth-path (the final result of command line flags and merged .kubeconfig files)
222 // 2.  configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
223 // 3.  if there is not enough information to identify the user, load try the ~/.kubernetes_auth file
224 // 4.  if there is not enough information to identify the user, prompt if possible
225 func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader, persistAuthConfig restclient.AuthProviderConfigPersister) (*restclient.Config, error) {
226         mergedConfig := &restclient.Config{}
227
228         // blindly overwrite existing values based on precedence
229         if len(configAuthInfo.Token) > 0 {
230                 mergedConfig.BearerToken = configAuthInfo.Token
231         } else if len(configAuthInfo.TokenFile) > 0 {
232                 tokenBytes, err := ioutil.ReadFile(configAuthInfo.TokenFile)
233                 if err != nil {
234                         return nil, err
235                 }
236                 mergedConfig.BearerToken = string(tokenBytes)
237                 mergedConfig.BearerTokenFile = configAuthInfo.TokenFile
238         }
239         if len(configAuthInfo.Impersonate) > 0 {
240                 mergedConfig.Impersonate = restclient.ImpersonationConfig{
241                         UserName: configAuthInfo.Impersonate,
242                         Groups:   configAuthInfo.ImpersonateGroups,
243                         Extra:    configAuthInfo.ImpersonateUserExtra,
244                 }
245         }
246         if len(configAuthInfo.ClientCertificate) > 0 || len(configAuthInfo.ClientCertificateData) > 0 {
247                 mergedConfig.CertFile = configAuthInfo.ClientCertificate
248                 mergedConfig.CertData = configAuthInfo.ClientCertificateData
249                 mergedConfig.KeyFile = configAuthInfo.ClientKey
250                 mergedConfig.KeyData = configAuthInfo.ClientKeyData
251         }
252         if len(configAuthInfo.Username) > 0 || len(configAuthInfo.Password) > 0 {
253                 mergedConfig.Username = configAuthInfo.Username
254                 mergedConfig.Password = configAuthInfo.Password
255         }
256         if configAuthInfo.AuthProvider != nil {
257                 mergedConfig.AuthProvider = configAuthInfo.AuthProvider
258                 mergedConfig.AuthConfigPersister = persistAuthConfig
259         }
260         if configAuthInfo.Exec != nil {
261                 mergedConfig.ExecProvider = configAuthInfo.Exec
262         }
263
264         // if there still isn't enough information to authenticate the user, try prompting
265         if !canIdentifyUser(*mergedConfig) && (fallbackReader != nil) {
266                 if len(config.promptedCredentials.username) > 0 && len(config.promptedCredentials.password) > 0 {
267                         mergedConfig.Username = config.promptedCredentials.username
268                         mergedConfig.Password = config.promptedCredentials.password
269                         return mergedConfig, nil
270                 }
271                 prompter := NewPromptingAuthLoader(fallbackReader)
272                 promptedAuthInfo, err := prompter.Prompt()
273                 if err != nil {
274                         return nil, err
275                 }
276                 promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo)
277                 previouslyMergedConfig := mergedConfig
278                 mergedConfig = &restclient.Config{}
279                 mergo.MergeWithOverwrite(mergedConfig, promptedConfig)
280                 mergo.MergeWithOverwrite(mergedConfig, previouslyMergedConfig)
281                 config.promptedCredentials.username = mergedConfig.Username
282                 config.promptedCredentials.password = mergedConfig.Password
283         }
284
285         return mergedConfig, nil
286 }
287
288 // makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only user identification information
289 func makeUserIdentificationConfig(info clientauth.Info) *restclient.Config {
290         config := &restclient.Config{}
291         config.Username = info.User
292         config.Password = info.Password
293         config.CertFile = info.CertFile
294         config.KeyFile = info.KeyFile
295         config.BearerToken = info.BearerToken
296         return config
297 }
298
299 // makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only server identification information
300 func makeServerIdentificationConfig(info clientauth.Info) restclient.Config {
301         config := restclient.Config{}
302         config.CAFile = info.CAFile
303         if info.Insecure != nil {
304                 config.Insecure = *info.Insecure
305         }
306         return config
307 }
308
309 func canIdentifyUser(config restclient.Config) bool {
310         return len(config.Username) > 0 ||
311                 (len(config.CertFile) > 0 || len(config.CertData) > 0) ||
312                 len(config.BearerToken) > 0 ||
313                 config.AuthProvider != nil ||
314                 config.ExecProvider != nil
315 }
316
317 // Namespace implements ClientConfig
318 func (config *DirectClientConfig) Namespace() (string, bool, error) {
319         if config.overrides != nil && config.overrides.Context.Namespace != "" {
320                 // In the event we have an empty config but we do have a namespace override, we should return
321                 // the namespace override instead of having config.ConfirmUsable() return an error. This allows
322                 // things like in-cluster clients to execute `kubectl get pods --namespace=foo` and have the
323                 // --namespace flag honored instead of being ignored.
324                 return config.overrides.Context.Namespace, true, nil
325         }
326
327         if err := config.ConfirmUsable(); err != nil {
328                 return "", false, err
329         }
330
331         configContext, err := config.getContext()
332         if err != nil {
333                 return "", false, err
334         }
335
336         if len(configContext.Namespace) == 0 {
337                 return "default", false, nil
338         }
339
340         return configContext.Namespace, false, nil
341 }
342
343 // ConfigAccess implements ClientConfig
344 func (config *DirectClientConfig) ConfigAccess() ConfigAccess {
345         return config.configAccess
346 }
347
348 // ConfirmUsable looks a particular context and determines if that particular part of the config is useable.  There might still be errors in the config,
349 // but no errors in the sections requested or referenced.  It does not return early so that it can find as many errors as possible.
350 func (config *DirectClientConfig) ConfirmUsable() error {
351         validationErrors := make([]error, 0)
352
353         var contextName string
354         if len(config.contextName) != 0 {
355                 contextName = config.contextName
356         } else {
357                 contextName = config.config.CurrentContext
358         }
359
360         if len(contextName) > 0 {
361                 _, exists := config.config.Contexts[contextName]
362                 if !exists {
363                         validationErrors = append(validationErrors, &errContextNotFound{contextName})
364                 }
365         }
366
367         authInfoName, _ := config.getAuthInfoName()
368         authInfo, _ := config.getAuthInfo()
369         validationErrors = append(validationErrors, validateAuthInfo(authInfoName, authInfo)...)
370         clusterName, _ := config.getClusterName()
371         cluster, _ := config.getCluster()
372         validationErrors = append(validationErrors, validateClusterInfo(clusterName, cluster)...)
373         // when direct client config is specified, and our only error is that no server is defined, we should
374         // return a standard "no config" error
375         if len(validationErrors) == 1 && validationErrors[0] == ErrEmptyCluster {
376                 return newErrConfigurationInvalid([]error{ErrEmptyConfig})
377         }
378         return newErrConfigurationInvalid(validationErrors)
379 }
380
381 // getContextName returns the default, or user-set context name, and a boolean that indicates
382 // whether the default context name has been overwritten by a user-set flag, or left as its default value
383 func (config *DirectClientConfig) getContextName() (string, bool) {
384         if len(config.overrides.CurrentContext) != 0 {
385                 return config.overrides.CurrentContext, true
386         }
387         if len(config.contextName) != 0 {
388                 return config.contextName, false
389         }
390
391         return config.config.CurrentContext, false
392 }
393
394 // getAuthInfoName returns a string containing the current authinfo name for the current context,
395 // and a boolean indicating  whether the default authInfo name is overwritten by a user-set flag, or
396 // left as its default value
397 func (config *DirectClientConfig) getAuthInfoName() (string, bool) {
398         if len(config.overrides.Context.AuthInfo) != 0 {
399                 return config.overrides.Context.AuthInfo, true
400         }
401         context, _ := config.getContext()
402         return context.AuthInfo, false
403 }
404
405 // getClusterName returns a string containing the default, or user-set cluster name, and a boolean
406 // indicating whether the default clusterName has been overwritten by a user-set flag, or left as
407 // its default value
408 func (config *DirectClientConfig) getClusterName() (string, bool) {
409         if len(config.overrides.Context.Cluster) != 0 {
410                 return config.overrides.Context.Cluster, true
411         }
412         context, _ := config.getContext()
413         return context.Cluster, false
414 }
415
416 // getContext returns the clientcmdapi.Context, or an error if a required context is not found.
417 func (config *DirectClientConfig) getContext() (clientcmdapi.Context, error) {
418         contexts := config.config.Contexts
419         contextName, required := config.getContextName()
420
421         mergedContext := clientcmdapi.NewContext()
422         if configContext, exists := contexts[contextName]; exists {
423                 mergo.MergeWithOverwrite(mergedContext, configContext)
424         } else if required {
425                 return clientcmdapi.Context{}, fmt.Errorf("context %q does not exist", contextName)
426         }
427         mergo.MergeWithOverwrite(mergedContext, config.overrides.Context)
428
429         return *mergedContext, nil
430 }
431
432 // getAuthInfo returns the clientcmdapi.AuthInfo, or an error if a required auth info is not found.
433 func (config *DirectClientConfig) getAuthInfo() (clientcmdapi.AuthInfo, error) {
434         authInfos := config.config.AuthInfos
435         authInfoName, required := config.getAuthInfoName()
436
437         mergedAuthInfo := clientcmdapi.NewAuthInfo()
438         if configAuthInfo, exists := authInfos[authInfoName]; exists {
439                 mergo.MergeWithOverwrite(mergedAuthInfo, configAuthInfo)
440         } else if required {
441                 return clientcmdapi.AuthInfo{}, fmt.Errorf("auth info %q does not exist", authInfoName)
442         }
443         mergo.MergeWithOverwrite(mergedAuthInfo, config.overrides.AuthInfo)
444
445         return *mergedAuthInfo, nil
446 }
447
448 // getCluster returns the clientcmdapi.Cluster, or an error if a required cluster is not found.
449 func (config *DirectClientConfig) getCluster() (clientcmdapi.Cluster, error) {
450         clusterInfos := config.config.Clusters
451         clusterInfoName, required := config.getClusterName()
452
453         mergedClusterInfo := clientcmdapi.NewCluster()
454         mergo.MergeWithOverwrite(mergedClusterInfo, config.overrides.ClusterDefaults)
455         if configClusterInfo, exists := clusterInfos[clusterInfoName]; exists {
456                 mergo.MergeWithOverwrite(mergedClusterInfo, configClusterInfo)
457         } else if required {
458                 return clientcmdapi.Cluster{}, fmt.Errorf("cluster %q does not exist", clusterInfoName)
459         }
460         mergo.MergeWithOverwrite(mergedClusterInfo, config.overrides.ClusterInfo)
461         // An override of --insecure-skip-tls-verify=true and no accompanying CA/CA data should clear already-set CA/CA data
462         // otherwise, a kubeconfig containing a CA reference would return an error that "CA and insecure-skip-tls-verify couldn't both be set"
463         caLen := len(config.overrides.ClusterInfo.CertificateAuthority)
464         caDataLen := len(config.overrides.ClusterInfo.CertificateAuthorityData)
465         if config.overrides.ClusterInfo.InsecureSkipTLSVerify && caLen == 0 && caDataLen == 0 {
466                 mergedClusterInfo.CertificateAuthority = ""
467                 mergedClusterInfo.CertificateAuthorityData = nil
468         }
469
470         return *mergedClusterInfo, nil
471 }
472
473 // inClusterClientConfig makes a config that will work from within a kubernetes cluster container environment.
474 // Can take options overrides for flags explicitly provided to the command inside the cluster container.
475 type inClusterClientConfig struct {
476         overrides               *ConfigOverrides
477         inClusterConfigProvider func() (*restclient.Config, error)
478 }
479
480 var _ ClientConfig = &inClusterClientConfig{}
481
482 func (config *inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) {
483         return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters")
484 }
485
486 func (config *inClusterClientConfig) ClientConfig() (*restclient.Config, error) {
487         if config.inClusterConfigProvider == nil {
488                 config.inClusterConfigProvider = restclient.InClusterConfig
489         }
490
491         icc, err := config.inClusterConfigProvider()
492         if err != nil {
493                 return nil, err
494         }
495
496         // in-cluster configs only takes a host, token, or CA file
497         // if any of them were individually provided, overwrite anything else
498         if config.overrides != nil {
499                 if server := config.overrides.ClusterInfo.Server; len(server) > 0 {
500                         icc.Host = server
501                 }
502                 if token := config.overrides.AuthInfo.Token; len(token) > 0 {
503                         icc.BearerToken = token
504                 }
505                 if certificateAuthorityFile := config.overrides.ClusterInfo.CertificateAuthority; len(certificateAuthorityFile) > 0 {
506                         icc.TLSClientConfig.CAFile = certificateAuthorityFile
507                 }
508         }
509
510         return icc, err
511 }
512
513 func (config *inClusterClientConfig) Namespace() (string, bool, error) {
514         // This way assumes you've set the POD_NAMESPACE environment variable using the downward API.
515         // This check has to be done first for backwards compatibility with the way InClusterConfig was originally set up
516         if ns := os.Getenv("POD_NAMESPACE"); ns != "" {
517                 return ns, false, nil
518         }
519
520         // Fall back to the namespace associated with the service account token, if available
521         if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil {
522                 if ns := strings.TrimSpace(string(data)); len(ns) > 0 {
523                         return ns, false, nil
524                 }
525         }
526
527         return "default", false, nil
528 }
529
530 func (config *inClusterClientConfig) ConfigAccess() ConfigAccess {
531         return NewDefaultClientConfigLoadingRules()
532 }
533
534 // Possible returns true if loading an inside-kubernetes-cluster is possible.
535 func (config *inClusterClientConfig) Possible() bool {
536         fi, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token")
537         return os.Getenv("KUBERNETES_SERVICE_HOST") != "" &&
538                 os.Getenv("KUBERNETES_SERVICE_PORT") != "" &&
539                 err == nil && !fi.IsDir()
540 }
541
542 // BuildConfigFromFlags is a helper function that builds configs from a master
543 // url or a kubeconfig filepath. These are passed in as command line flags for cluster
544 // components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath
545 // are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback
546 // to the default config.
547 func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
548         if kubeconfigPath == "" && masterUrl == "" {
549                 klog.Warningf("Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.")
550                 kubeconfig, err := restclient.InClusterConfig()
551                 if err == nil {
552                         return kubeconfig, nil
553                 }
554                 klog.Warning("error creating inClusterConfig, falling back to default config: ", err)
555         }
556         return NewNonInteractiveDeferredLoadingClientConfig(
557                 &ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
558                 &ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig()
559 }
560
561 // BuildConfigFromKubeconfigGetter is a helper function that builds configs from a master
562 // url and a kubeconfigGetter.
563 func BuildConfigFromKubeconfigGetter(masterUrl string, kubeconfigGetter KubeconfigGetter) (*restclient.Config, error) {
564         // TODO: We do not need a DeferredLoader here. Refactor code and see if we can use DirectClientConfig here.
565         cc := NewNonInteractiveDeferredLoadingClientConfig(
566                 &ClientConfigGetter{kubeconfigGetter: kubeconfigGetter},
567                 &ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}})
568         return cc.ClientConfig()
569 }