merged_client_builder.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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"
  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. if config.clientConfig == nil {
  50. config.loadingLock.Lock()
  51. defer config.loadingLock.Unlock()
  52. if config.clientConfig == nil {
  53. mergedConfig, err := config.loader.Load()
  54. if err != nil {
  55. return nil, err
  56. }
  57. var mergedClientConfig ClientConfig
  58. if config.fallbackReader != nil {
  59. mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader, config.loader)
  60. } else {
  61. mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.loader)
  62. }
  63. config.clientConfig = mergedClientConfig
  64. }
  65. }
  66. return config.clientConfig, nil
  67. }
  68. func (config *DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, error) {
  69. mergedConfig, err := config.createClientConfig()
  70. if err != nil {
  71. return clientcmdapi.Config{}, err
  72. }
  73. return mergedConfig.RawConfig()
  74. }
  75. // ClientConfig implements ClientConfig
  76. func (config *DeferredLoadingClientConfig) ClientConfig() (*restclient.Config, error) {
  77. mergedClientConfig, err := config.createClientConfig()
  78. if err != nil {
  79. return nil, err
  80. }
  81. // load the configuration and return on non-empty errors and if the
  82. // content differs from the default config
  83. mergedConfig, err := mergedClientConfig.ClientConfig()
  84. switch {
  85. case err != nil:
  86. if !IsEmptyConfig(err) {
  87. // return on any error except empty config
  88. return nil, err
  89. }
  90. case mergedConfig != nil:
  91. // the configuration is valid, but if this is equal to the defaults we should try
  92. // in-cluster configuration
  93. if !config.loader.IsDefaultConfig(mergedConfig) {
  94. return mergedConfig, nil
  95. }
  96. }
  97. // check for in-cluster configuration and use it
  98. if config.icc.Possible() {
  99. klog.V(4).Infof("Using in-cluster configuration")
  100. return config.icc.ClientConfig()
  101. }
  102. // return the result of the merged client config
  103. return mergedConfig, err
  104. }
  105. // Namespace implements KubeConfig
  106. func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) {
  107. mergedKubeConfig, err := config.createClientConfig()
  108. if err != nil {
  109. return "", false, err
  110. }
  111. ns, overridden, err := mergedKubeConfig.Namespace()
  112. // if we get an error and it is not empty config, or if the merged config defined an explicit namespace, or
  113. // if in-cluster config is not possible, return immediately
  114. if (err != nil && !IsEmptyConfig(err)) || overridden || !config.icc.Possible() {
  115. // return on any error except empty config
  116. return ns, overridden, err
  117. }
  118. if len(ns) > 0 {
  119. // if we got a non-default namespace from the kubeconfig, use it
  120. if ns != "default" {
  121. return ns, false, nil
  122. }
  123. // if we got a default namespace, determine whether it was explicit or implicit
  124. if raw, err := mergedKubeConfig.RawConfig(); err == nil {
  125. // determine the current context
  126. currentContext := raw.CurrentContext
  127. if config.overrides != nil && len(config.overrides.CurrentContext) > 0 {
  128. currentContext = config.overrides.CurrentContext
  129. }
  130. if context := raw.Contexts[currentContext]; context != nil && len(context.Namespace) > 0 {
  131. return ns, false, nil
  132. }
  133. }
  134. }
  135. klog.V(4).Infof("Using in-cluster namespace")
  136. // allow the namespace from the service account token directory to be used.
  137. return config.icc.Namespace()
  138. }
  139. // ConfigAccess implements ClientConfig
  140. func (config *DeferredLoadingClientConfig) ConfigAccess() ConfigAccess {
  141. return config.loader
  142. }