merged_client_builder.go 5.8 KB

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