kubectl_match_version.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. Copyright 2018 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 util
  14. import (
  15. "sync"
  16. "github.com/spf13/pflag"
  17. "k8s.io/apimachinery/pkg/api/meta"
  18. "k8s.io/apimachinery/pkg/runtime/schema"
  19. "k8s.io/client-go/discovery"
  20. "k8s.io/client-go/rest"
  21. "k8s.io/client-go/tools/clientcmd"
  22. "k8s.io/kubernetes/pkg/kubectl/scheme"
  23. "k8s.io/cli-runtime/pkg/genericclioptions"
  24. "k8s.io/kubernetes/pkg/kubectl/version"
  25. )
  26. const (
  27. flagMatchBinaryVersion = "match-server-version"
  28. )
  29. // MatchVersionFlags is for setting the "match server version" function.
  30. type MatchVersionFlags struct {
  31. Delegate genericclioptions.RESTClientGetter
  32. RequireMatchedServerVersion bool
  33. checkServerVersion sync.Once
  34. matchesServerVersionErr error
  35. }
  36. var _ genericclioptions.RESTClientGetter = &MatchVersionFlags{}
  37. func (f *MatchVersionFlags) checkMatchingServerVersion() error {
  38. f.checkServerVersion.Do(func() {
  39. if !f.RequireMatchedServerVersion {
  40. return
  41. }
  42. discoveryClient, err := f.Delegate.ToDiscoveryClient()
  43. if err != nil {
  44. f.matchesServerVersionErr = err
  45. return
  46. }
  47. f.matchesServerVersionErr = discovery.MatchesServerVersion(version.Get(), discoveryClient)
  48. })
  49. return f.matchesServerVersionErr
  50. }
  51. // ToRESTConfig implements RESTClientGetter.
  52. // Returns a REST client configuration based on a provided path
  53. // to a .kubeconfig file, loading rules, and config flag overrides.
  54. // Expects the AddFlags method to have been called.
  55. func (f *MatchVersionFlags) ToRESTConfig() (*rest.Config, error) {
  56. if err := f.checkMatchingServerVersion(); err != nil {
  57. return nil, err
  58. }
  59. clientConfig, err := f.Delegate.ToRESTConfig()
  60. if err != nil {
  61. return nil, err
  62. }
  63. // TODO we should not have to do this. It smacks of something going wrong.
  64. setKubernetesDefaults(clientConfig)
  65. return clientConfig, nil
  66. }
  67. func (f *MatchVersionFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig {
  68. return f.Delegate.ToRawKubeConfigLoader()
  69. }
  70. func (f *MatchVersionFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
  71. if err := f.checkMatchingServerVersion(); err != nil {
  72. return nil, err
  73. }
  74. return f.Delegate.ToDiscoveryClient()
  75. }
  76. // ToRESTMapper returns a mapper.
  77. func (f *MatchVersionFlags) ToRESTMapper() (meta.RESTMapper, error) {
  78. if err := f.checkMatchingServerVersion(); err != nil {
  79. return nil, err
  80. }
  81. return f.Delegate.ToRESTMapper()
  82. }
  83. func (f *MatchVersionFlags) AddFlags(flags *pflag.FlagSet) {
  84. flags.BoolVar(&f.RequireMatchedServerVersion, flagMatchBinaryVersion, f.RequireMatchedServerVersion, "Require server version to match client version")
  85. }
  86. func NewMatchVersionFlags(delegate genericclioptions.RESTClientGetter) *MatchVersionFlags {
  87. return &MatchVersionFlags{
  88. Delegate: delegate,
  89. }
  90. }
  91. // setKubernetesDefaults sets default values on the provided client config for accessing the
  92. // Kubernetes API or returns an error if any of the defaults are impossible or invalid.
  93. // TODO this isn't what we want. Each clientset should be setting defaults as it sees fit.
  94. func setKubernetesDefaults(config *rest.Config) error {
  95. // TODO remove this hack. This is allowing the GetOptions to be serialized.
  96. config.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
  97. if config.APIPath == "" {
  98. config.APIPath = "/api"
  99. }
  100. if config.NegotiatedSerializer == nil {
  101. // This codec factory ensures the resources are not converted. Therefore, resources
  102. // will not be round-tripped through internal versions. Defaulting does not happen
  103. // on the client.
  104. config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
  105. }
  106. return rest.SetKubernetesDefaults(config)
  107. }