client_config.go 23 KB

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