1
16
17 package version
18
19 import (
20 "encoding/json"
21 "errors"
22 "fmt"
23 "runtime/debug"
24
25 "github.com/spf13/cobra"
26 "sigs.k8s.io/yaml"
27
28 apimachineryversion "k8s.io/apimachinery/pkg/version"
29 "k8s.io/cli-runtime/pkg/genericiooptions"
30 "k8s.io/client-go/discovery"
31 "k8s.io/client-go/tools/clientcmd"
32 "k8s.io/component-base/version"
33 cmdutil "k8s.io/kubectl/pkg/cmd/util"
34 "k8s.io/kubectl/pkg/util/i18n"
35 "k8s.io/kubectl/pkg/util/templates"
36 )
37
38
39 const kustomizeVersion = "v5.0.1"
40
41
42 type Version struct {
43 ClientVersion *apimachineryversion.Info `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"`
44 KustomizeVersion string `json:"kustomizeVersion,omitempty" yaml:"kustomizeVersion,omitempty"`
45 ServerVersion *apimachineryversion.Info `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"`
46 }
47
48 var (
49 versionExample = templates.Examples(i18n.T(`
50 # Print the client and server versions for the current context
51 kubectl version`))
52 )
53
54
55 type Options struct {
56 ClientOnly bool
57 Output string
58
59 args []string
60
61 discoveryClient discovery.CachedDiscoveryInterface
62
63 genericiooptions.IOStreams
64 }
65
66
67 func NewOptions(ioStreams genericiooptions.IOStreams) *Options {
68 return &Options{
69 IOStreams: ioStreams,
70 }
71
72 }
73
74
75 func NewCmdVersion(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command {
76 o := NewOptions(ioStreams)
77 cmd := &cobra.Command{
78 Use: "version",
79 Short: i18n.T("Print the client and server version information"),
80 Long: i18n.T("Print the client and server version information for the current context."),
81 Example: versionExample,
82 Run: func(cmd *cobra.Command, args []string) {
83 cmdutil.CheckErr(o.Complete(f, cmd, args))
84 cmdutil.CheckErr(o.Validate())
85 cmdutil.CheckErr(o.Run())
86 },
87 }
88 cmd.Flags().BoolVar(&o.ClientOnly, "client", o.ClientOnly, "If true, shows client version only (no server required).")
89 cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "One of 'yaml' or 'json'.")
90 return cmd
91 }
92
93
94 func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
95 var err error
96 if o.ClientOnly {
97 return nil
98 }
99 o.discoveryClient, err = f.ToDiscoveryClient()
100
101
102 if err != nil && !clientcmd.IsEmptyConfig(err) {
103 return err
104 }
105
106 o.args = args
107 return nil
108 }
109
110
111 func (o *Options) Validate() error {
112 if len(o.args) != 0 {
113 return errors.New(fmt.Sprintf("extra arguments: %v", o.args))
114 }
115
116 if o.Output != "" && o.Output != "yaml" && o.Output != "json" {
117 return errors.New(`--output must be 'yaml' or 'json'`)
118 }
119
120 return nil
121 }
122
123
124 func (o *Options) Run() error {
125 var (
126 serverErr error
127 versionInfo Version
128 )
129
130 versionInfo.ClientVersion = func() *apimachineryversion.Info { v := version.Get(); return &v }()
131 versionInfo.KustomizeVersion = getKustomizeVersion()
132
133 if !o.ClientOnly && o.discoveryClient != nil {
134
135 o.discoveryClient.Invalidate()
136 versionInfo.ServerVersion, serverErr = o.discoveryClient.ServerVersion()
137 }
138
139 switch o.Output {
140 case "":
141 fmt.Fprintf(o.Out, "Client Version: %s\n", versionInfo.ClientVersion.GitVersion)
142 fmt.Fprintf(o.Out, "Kustomize Version: %s\n", versionInfo.KustomizeVersion)
143 if versionInfo.ServerVersion != nil {
144 fmt.Fprintf(o.Out, "Server Version: %s\n", versionInfo.ServerVersion.GitVersion)
145 }
146 case "yaml":
147 marshalled, err := yaml.Marshal(&versionInfo)
148 if err != nil {
149 return err
150 }
151 fmt.Fprintln(o.Out, string(marshalled))
152 case "json":
153 marshalled, err := json.MarshalIndent(&versionInfo, "", " ")
154 if err != nil {
155 return err
156 }
157 fmt.Fprintln(o.Out, string(marshalled))
158 default:
159
160
161 return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.Output)
162 }
163
164 if versionInfo.ServerVersion != nil {
165 if err := printVersionSkewWarning(o.ErrOut, *versionInfo.ClientVersion, *versionInfo.ServerVersion); err != nil {
166 return err
167 }
168 }
169
170 return serverErr
171 }
172
173 func getKustomizeVersion() string {
174 if modVersion, ok := GetKustomizeModVersion(); ok {
175 return modVersion
176 }
177 return kustomizeVersion
178 }
179
180 func GetKustomizeModVersion() (string, bool) {
181 info, ok := debug.ReadBuildInfo()
182 if !ok {
183 return "", false
184 }
185 for _, dep := range info.Deps {
186 if dep.Path == "sigs.k8s.io/kustomize/kustomize/v4" || dep.Path == "sigs.k8s.io/kustomize/kustomize/v5" {
187 return dep.Version, true
188 }
189 }
190 return "", false
191 }
192
View as plain text