merged_client_builder.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. "github.com/golang/glog"
  18. "k8s.io/client-go/pkg/api"
  19. restclient "k8s.io/client-go/rest"
  20. clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
  21. )
  22. // DeferredLoadingClientConfig is a ClientConfig interface that is backed by a client config loader.
  23. // It is used in cases where the loading rules may change after you've instantiated them and you want to be sure that
  24. // the most recent rules are used. This is useful in cases where you bind flags to loading rule parameters before
  25. // the parse happens and you want your calling code to be ignorant of how the values are being mutated to avoid
  26. // passing extraneous information down a call stack
  27. type DeferredLoadingClientConfig struct {
  28. loader ClientConfigLoader
  29. overrides *ConfigOverrides
  30. fallbackReader io.Reader
  31. clientConfig ClientConfig
  32. loadingLock sync.Mutex
  33. // provided for testing
  34. icc InClusterConfig
  35. }
  36. // InClusterConfig abstracts details of whether the client is running in a cluster for testing.
  37. type InClusterConfig interface {
  38. ClientConfig
  39. Possible() bool
  40. }
  41. // NewNonInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name
  42. func NewNonInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides) ClientConfig {
  43. return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, icc: &inClusterClientConfig{overrides: overrides}}
  44. }
  45. // NewInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name and the fallback auth reader
  46. func NewInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides, fallbackReader io.Reader) ClientConfig {
  47. return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, icc: &inClusterClientConfig{overrides: overrides}, fallbackReader: fallbackReader}
  48. }
  49. func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) {
  50. if config.clientConfig == nil {
  51. config.loadingLock.Lock()
  52. defer config.loadingLock.Unlock()
  53. if config.clientConfig == nil {
  54. mergedConfig, err := config.loader.Load()
  55. if err != nil {
  56. return nil, err
  57. }
  58. var mergedClientConfig ClientConfig
  59. if config.fallbackReader != nil {
  60. mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader, config.loader)
  61. } else {
  62. mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.loader)
  63. }
  64. config.clientConfig = mergedClientConfig
  65. }
  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. glog.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 != api.NamespaceDefault {
  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. if context := raw.Contexts[raw.CurrentContext]; context != nil && len(context.Namespace) > 0 {
  127. return ns, false, nil
  128. }
  129. }
  130. }
  131. glog.V(4).Infof("Using in-cluster namespace")
  132. // allow the namespace from the service account token directory to be used.
  133. return config.icc.Namespace()
  134. }
  135. // ConfigAccess implements ClientConfig
  136. func (config *DeferredLoadingClientConfig) ConfigAccess() ConfigAccess {
  137. return config.loader
  138. }