github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/tools/version.go (about) 1 /* 2 Copyright 2018 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tools 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "errors" 23 "fmt" 24 "io" 25 "os" 26 "strings" 27 28 "github.com/Mirantis/virtlet/pkg/version" 29 "github.com/spf13/cobra" 30 ) 31 32 type versionCommand struct { 33 client KubeClient 34 out io.Writer 35 format string 36 short bool 37 clientOnly bool 38 info version.Info 39 } 40 41 // NewVersionCommand returns a cobra.Command that prints Virtlet 42 // version info 43 func NewVersionCommand(client KubeClient, out io.Writer, info *version.Info) *cobra.Command { 44 v := &versionCommand{client: client, out: out} 45 if info == nil { 46 v.info = version.Get() 47 } else { 48 v.info = *info 49 } 50 cmd := &cobra.Command{ 51 Use: "version", 52 Short: "Display Virtlet version information", 53 Long: "Display information about virtletctl version and Virtlet versions on the nodes", 54 RunE: func(cmd *cobra.Command, args []string) error { 55 if len(args) != 0 { 56 return errors.New("This command does not accept arguments") 57 } 58 return v.Run() 59 }, 60 } 61 cmd.Flags().StringVarP(&v.format, "output", "o", "text", "One of 'text', 'short', 'yaml' or 'json'") 62 cmd.Flags().BoolVar(&v.short, "short", false, "Print just the version number(s) (same as -o short)") 63 cmd.Flags().BoolVar(&v.clientOnly, "client", false, "Print virtletctl version only") 64 return cmd 65 } 66 67 func (v *versionCommand) getVersions() (version.ClusterVersionInfo, error) { 68 vi := version.ClusterVersionInfo{ClientVersion: v.info} 69 if v.clientOnly { 70 return vi, nil 71 } 72 73 podNames, nodeNames, err := v.client.GetVirtletPodAndNodeNames() 74 if err != nil { 75 return vi, err 76 } 77 78 var errors []string 79 for n, podName := range podNames { 80 nodeName := nodeNames[n] 81 var buf bytes.Buffer 82 exitCode, err := v.client.ExecInContainer( 83 podName, "virtlet", "kube-system", 84 nil, &buf, os.Stderr, 85 []string{"virtlet", "--version", "--version-format", "json"}) 86 switch { 87 case err != nil: 88 errors = append(errors, fmt.Sprintf("node %q: error getting version from Virtlet pod %q: %v", nodeName, podName, err)) 89 continue 90 case exitCode != 0: 91 errors = append(errors, fmt.Sprintf("node %q: error getting version from Virtlet pod %q: exit code %d", nodeName, podName, exitCode)) 92 continue 93 } 94 var nv version.Info 95 if err := json.Unmarshal(buf.Bytes(), &nv); err != nil { 96 errors = append(errors, fmt.Sprintf("node %q: error unmarshalling version info from Virtlet pod %q: %v", nodeName, podName, err)) 97 continue 98 } 99 nv.NodeName = nodeName 100 vi.NodeVersions = append(vi.NodeVersions, nv) 101 } 102 if !vi.AreNodesConsistent() { 103 errors = append(errors, "some of the nodes have inconsistent Virtlet builds") 104 } 105 if len(errors) != 0 { 106 return vi, fmt.Errorf("error encountered on some of the nodes:\n%s", strings.Join(errors, "\n")) 107 } 108 return vi, nil 109 } 110 111 func (v *versionCommand) Run() error { 112 if v.short { 113 v.format = "short" 114 } 115 vi, collectErr := v.getVersions() 116 bs, err := vi.ToBytes(v.format) 117 if err == nil { 118 _, err = v.out.Write(bs) 119 } 120 if err != nil { 121 return err 122 } 123 return collectErr 124 }