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  }