version.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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 version
  14. import (
  15. "encoding/json"
  16. "errors"
  17. "fmt"
  18. "github.com/spf13/cobra"
  19. "sigs.k8s.io/yaml"
  20. apimachineryversion "k8s.io/apimachinery/pkg/version"
  21. "k8s.io/cli-runtime/pkg/genericclioptions"
  22. "k8s.io/client-go/discovery"
  23. "k8s.io/client-go/tools/clientcmd"
  24. cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
  25. "k8s.io/kubernetes/pkg/kubectl/util/i18n"
  26. "k8s.io/kubernetes/pkg/kubectl/util/templates"
  27. "k8s.io/kubernetes/pkg/kubectl/version"
  28. )
  29. // Version is a struct for version information
  30. type Version struct {
  31. ClientVersion *apimachineryversion.Info `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"`
  32. ServerVersion *apimachineryversion.Info `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"`
  33. }
  34. var (
  35. versionExample = templates.Examples(i18n.T(`
  36. # Print the client and server versions for the current context
  37. kubectl version`))
  38. )
  39. // Options is a struct to support version command
  40. type Options struct {
  41. ClientOnly bool
  42. Short bool
  43. Output string
  44. discoveryClient discovery.CachedDiscoveryInterface
  45. genericclioptions.IOStreams
  46. }
  47. // NewOptions returns initialized Options
  48. func NewOptions(ioStreams genericclioptions.IOStreams) *Options {
  49. return &Options{
  50. IOStreams: ioStreams,
  51. }
  52. }
  53. // NewCmdVersion returns a cobra command for fetching versions
  54. func NewCmdVersion(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
  55. o := NewOptions(ioStreams)
  56. cmd := &cobra.Command{
  57. Use: "version",
  58. Short: i18n.T("Print the client and server version information"),
  59. Long: "Print the client and server version information for the current context",
  60. Example: versionExample,
  61. Run: func(cmd *cobra.Command, args []string) {
  62. cmdutil.CheckErr(o.Complete(f, cmd))
  63. cmdutil.CheckErr(o.Validate())
  64. cmdutil.CheckErr(o.Run())
  65. },
  66. }
  67. cmd.Flags().BoolVar(&o.ClientOnly, "client", o.ClientOnly, "Client version only (no server required).")
  68. cmd.Flags().BoolVar(&o.Short, "short", o.Short, "Print just the version number.")
  69. cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "One of 'yaml' or 'json'.")
  70. return cmd
  71. }
  72. // Complete completes all the required options
  73. func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
  74. var err error
  75. if o.ClientOnly {
  76. return nil
  77. }
  78. o.discoveryClient, err = f.ToDiscoveryClient()
  79. // if we had an empty rest.Config, continue and just print out client information.
  80. // if we had an error other than being unable to build a rest.Config, fail.
  81. if err != nil && !clientcmd.IsEmptyConfig(err) {
  82. return err
  83. }
  84. return nil
  85. }
  86. // Validate validates the provided options
  87. func (o *Options) Validate() error {
  88. if o.Output != "" && o.Output != "yaml" && o.Output != "json" {
  89. return errors.New(`--output must be 'yaml' or 'json'`)
  90. }
  91. return nil
  92. }
  93. // Run executes version command
  94. func (o *Options) Run() error {
  95. var (
  96. serverVersion *apimachineryversion.Info
  97. serverErr error
  98. versionInfo Version
  99. )
  100. clientVersion := version.Get()
  101. versionInfo.ClientVersion = &clientVersion
  102. if !o.ClientOnly && o.discoveryClient != nil {
  103. // Always request fresh data from the server
  104. o.discoveryClient.Invalidate()
  105. serverVersion, serverErr = o.discoveryClient.ServerVersion()
  106. versionInfo.ServerVersion = serverVersion
  107. }
  108. switch o.Output {
  109. case "":
  110. if o.Short {
  111. fmt.Fprintf(o.Out, "Client Version: %s\n", clientVersion.GitVersion)
  112. if serverVersion != nil {
  113. fmt.Fprintf(o.Out, "Server Version: %s\n", serverVersion.GitVersion)
  114. }
  115. } else {
  116. fmt.Fprintf(o.Out, "Client Version: %s\n", fmt.Sprintf("%#v", clientVersion))
  117. if serverVersion != nil {
  118. fmt.Fprintf(o.Out, "Server Version: %s\n", fmt.Sprintf("%#v", *serverVersion))
  119. }
  120. }
  121. case "yaml":
  122. marshalled, err := yaml.Marshal(&versionInfo)
  123. if err != nil {
  124. return err
  125. }
  126. fmt.Fprintln(o.Out, string(marshalled))
  127. case "json":
  128. marshalled, err := json.MarshalIndent(&versionInfo, "", " ")
  129. if err != nil {
  130. return err
  131. }
  132. fmt.Fprintln(o.Out, string(marshalled))
  133. default:
  134. // There is a bug in the program if we hit this case.
  135. // However, we follow a policy of never panicking.
  136. return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.Output)
  137. }
  138. return serverErr
  139. }