Skip to content

Commit

Permalink
Merge pull request kubevirt#7024 from fossedihelm/virctl_print_versio…
Browse files Browse the repository at this point in the history
…n_not_aligned

[virtctl] Warning message for client and server versions not aligned
  • Loading branch information
kubevirt-bot authored Apr 1, 2022
2 parents fa12cd7 + 260f160 commit 836afc8
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 17 deletions.
4 changes: 2 additions & 2 deletions cmd/virt-chroot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func main() {

},
Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
cmd.Printf(cmd.UsageString())
},
}

Expand Down Expand Up @@ -169,7 +169,7 @@ func main() {
Short: "run selinux operations in specific namespaces",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
cmd.Printf(cmd.UsageString())
},
}

Expand Down
1 change: 1 addition & 0 deletions pkg/virtctl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ go_library(
"//staging/src/kubevirt.io/client-go/log:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
],
)

Expand Down
14 changes: 9 additions & 5 deletions pkg/virtctl/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"path/filepath"
"strings"

"k8s.io/client-go/tools/clientcmd"

"github.com/spf13/cobra"

"kubevirt.io/client-go/kubecli"
Expand All @@ -28,7 +30,7 @@ import (

var programName string

func NewVirtctlCommand() *cobra.Command {
func NewVirtctlCommand() (*cobra.Command, clientcmd.ClientConfig) {

programName := GetProgramName(filepath.Base(os.Args[0]))

Expand All @@ -55,22 +57,23 @@ func NewVirtctlCommand() *cobra.Command {
SilenceUsage: true,
SilenceErrors: true,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
cmd.Printf(cmd.UsageString())
},
}

optionsCmd := &cobra.Command{
Use: "options",
Hidden: true,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
cmd.Printf(cmd.UsageString())
},
}
optionsCmd.SetUsageTemplate(templates.OptionsUsageTemplate())
//TODO: Add a ClientConfigFactory which allows substituting the KubeVirt client with a mock for unit testing
clientConfig := kubecli.DefaultClientConfig(rootCmd.PersistentFlags())
AddGlogFlags(rootCmd.PersistentFlags())
rootCmd.SetUsageTemplate(templates.MainUsageTemplate())
rootCmd.SetOut(os.Stdout)
rootCmd.AddCommand(
configuration.NewListPermittedDevices(clientConfig),
console.NewCommand(clientConfig),
Expand All @@ -97,7 +100,7 @@ func NewVirtctlCommand() *cobra.Command {
guestfs.NewGuestfsShellCommand(clientConfig),
optionsCmd,
)
return rootCmd
return rootCmd, clientConfig
}

// GetProgramName returns the command name to display in help texts.
Expand All @@ -115,8 +118,9 @@ func GetProgramName(binary string) string {

func Execute() {
log.InitializeLogging(programName)
cmd := NewVirtctlCommand()
cmd, clientConfig := NewVirtctlCommand()
if err := cmd.Execute(); err != nil {
version.CheckClientServerVersion(&clientConfig)
fmt.Fprintln(cmd.Root().ErrOrStderr(), strings.TrimSpace(err.Error()))
os.Exit(1)
}
Expand Down
23 changes: 22 additions & 1 deletion pkg/virtctl/version/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
load("//staging/src/kubevirt.io/client-go/version:def.bzl", "version_x_defs")

go_library(
name = "go_default_library",
Expand All @@ -9,7 +10,27 @@ go_library(
"//pkg/virtctl/templates:go_default_library",
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
"//staging/src/kubevirt.io/client-go/version:go_default_library",
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
],
)

go_test(
name = "go_default_test",
srcs = [
"version_suite_test.go",
"version_test.go",
],
x_defs = version_x_defs(),
deps = [
":go_default_library",
"//pkg/virtctl:go_default_library",
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
"//staging/src/kubevirt.io/client-go/testutils:go_default_library",
"//staging/src/kubevirt.io/client-go/version:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/onsi/ginkgo/v2:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
],
)
49 changes: 45 additions & 4 deletions pkg/virtctl/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package version

import (
"fmt"
"strings"

"github.com/blang/semver"

"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
Expand All @@ -11,10 +14,15 @@ import (
"kubevirt.io/kubevirt/pkg/virtctl/templates"
)

var clientOnly bool
var (
cmd *cobra.Command
clientOnly bool
)

const versionsNotAlignedWarnMessage = "You are using a client virtctl version that is different from the KubeVirt version running in the cluster\nClient Version: %s\nServer Version: %s\n"

func VersionCommand(clientConfig clientcmd.ClientConfig) *cobra.Command {
cmd := &cobra.Command{
cmd = &cobra.Command{
Use: "version",
Short: "Print the client and server version information.",
Example: usage(),
Expand All @@ -40,7 +48,7 @@ type Version struct {
}

func (v *Version) Run() error {
fmt.Printf("Client Version: %s\n", fmt.Sprintf("%#v", version.Get()))
cmd.Printf("Client Version: %s\n", fmt.Sprintf("%#v", version.Get()))

if !clientOnly {
virCli, err := kubecli.GetKubevirtClientFromClientConfig(v.clientConfig)
Expand All @@ -53,8 +61,41 @@ func (v *Version) Run() error {
return err
}

fmt.Printf("Server Version: %s\n", fmt.Sprintf("%#v", *serverInfo))
cmd.Printf("Server Version: %s\n", fmt.Sprintf("%#v", *serverInfo))
}

return nil
}

func CheckClientServerVersion(clientConfig *clientcmd.ClientConfig) {
clientVersion := version.Get()
virCli, err := kubecli.GetKubevirtClientFromClientConfig(*clientConfig)
if err != nil {
cmd.Println(err)
return
}

serverVersion, err := virCli.ServerVersion().Get()
if err != nil {
cmd.Println(err)
return
}

clientGitVersion := strings.TrimPrefix(clientVersion.GitVersion, "v")
serverGitVersion := strings.TrimPrefix(serverVersion.GitVersion, "v")
client, err := semver.Make(clientGitVersion)
if err != nil {
cmd.Println(err)
return
}

server, err := semver.Make(serverGitVersion)
if err != nil {
cmd.Println(err)
return
}

if client.Major != server.Major || client.Minor != server.Minor {
cmd.Printf(versionsNotAlignedWarnMessage, clientVersion, *serverVersion)
}
}
11 changes: 11 additions & 0 deletions pkg/virtctl/version/version_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package version_test

import (
"testing"

"kubevirt.io/client-go/testutils"
)

func TestVersion(t *testing.T) {
testutils.KubeVirtTestSuiteSetup(t)
}
54 changes: 54 additions & 0 deletions pkg/virtctl/version/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package version_test

import (
"bytes"
"fmt"
goruntime "runtime"
"time"

"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"kubevirt.io/client-go/kubecli"
virt_version "kubevirt.io/client-go/version"
"kubevirt.io/kubevirt/pkg/virtctl"
"kubevirt.io/kubevirt/pkg/virtctl/version"
)

var _ = Describe("Version", func() {

var ctrl *gomock.Controller

BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
kubecli.GetKubevirtClientFromClientConfig = kubecli.GetMockKubevirtClientFromClientConfig
kubecli.MockKubevirtClientInstance = kubecli.NewMockKubevirtClient(ctrl)
serverVersionInterface := kubecli.NewMockServerVersionInterface(ctrl)
kubecli.MockKubevirtClientInstance.EXPECT().ServerVersion().Return(serverVersionInterface).AnyTimes()
serverVersionInterface.EXPECT().Get().Return(&virt_version.Info{
GitVersion: "v0.46.1",
GitCommit: "fda30004223b51f9e604276419a2b376652cb5ad",
GitTreeState: "clear",
BuildDate: time.Now().Format("%Y-%m-%dT%H:%M:%SZ"),
GoVersion: goruntime.Version(),
Compiler: goruntime.Compiler,
Platform: fmt.Sprintf("%s/%s", goruntime.GOOS, goruntime.GOARCH),
}, nil,
).AnyTimes()
})

Context("should print a message if server and client virtctl versions are different", func() {
It("in version command", func() {
var buf bytes.Buffer
cmd, clientConfig := virtctl.NewVirtctlCommand()
cmd.SetOut(&buf)
version.CheckClientServerVersion(&clientConfig)
//Print out the captured output to show the test output also in the console
fmt.Printf(buf.String())
Expect(buf.String()).To(ContainSubstring("You are using a client virtctl version that is different from the KubeVirt version running in the cluster"),
"Warning message was not shown or has been changed")
})

})
})
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import (
v1alpha18 "kubevirt.io/client-go/generated/kubevirt/clientset/versioned/typed/snapshot/v1alpha1"
versioned2 "kubevirt.io/client-go/generated/network-attachment-definition-client/clientset/versioned"
versioned3 "kubevirt.io/client-go/generated/prometheus-operator/clientset/versioned"
version "kubevirt.io/client-go/version"
)

// Mock of KubevirtClient interface
Expand Down Expand Up @@ -226,9 +227,9 @@ func (_mr *_MockKubevirtClientRecorder) MigrationPolicy() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "MigrationPolicy")
}

func (_m *MockKubevirtClient) ServerVersion() *ServerVersion {
func (_m *MockKubevirtClient) ServerVersion() ServerVersionInterface {
ret := _m.ctrl.Call(_m, "ServerVersion")
ret0, _ := ret[0].(*ServerVersion)
ret0, _ := ret[0].(ServerVersionInterface)
return ret0
}

Expand Down Expand Up @@ -1781,3 +1782,35 @@ func (_m *MockKubeVirtInterface) PatchStatus(name string, pt types.PatchType, da
func (_mr *_MockKubeVirtInterfaceRecorder) PatchStatus(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "PatchStatus", arg0, arg1, arg2, arg3)
}

// Mock of ServerVersionInterface interface
type MockServerVersionInterface struct {
ctrl *gomock.Controller
recorder *_MockServerVersionInterfaceRecorder
}

// Recorder for MockServerVersionInterface (not exported)
type _MockServerVersionInterfaceRecorder struct {
mock *MockServerVersionInterface
}

func NewMockServerVersionInterface(ctrl *gomock.Controller) *MockServerVersionInterface {
mock := &MockServerVersionInterface{ctrl: ctrl}
mock.recorder = &_MockServerVersionInterfaceRecorder{mock}
return mock
}

func (_m *MockServerVersionInterface) EXPECT() *_MockServerVersionInterfaceRecorder {
return _m.recorder
}

func (_m *MockServerVersionInterface) Get() (*version.Info, error) {
ret := _m.ctrl.Call(_m, "Get")
ret0, _ := ret[0].(*version.Info)
ret1, _ := ret[1].(error)
return ret0, ret1
}

func (_mr *_MockServerVersionInterfaceRecorder) Get() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Get")
}
8 changes: 7 additions & 1 deletion staging/src/kubevirt.io/client-go/kubecli/kubevirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
"net"
"time"

"kubevirt.io/client-go/version"

migrationsv1 "kubevirt.io/client-go/generated/kubevirt/clientset/versioned/typed/migrations/v1alpha1"

secv1 "github.com/openshift/client-go/security/clientset/versioned/typed/security/v1"
Expand Down Expand Up @@ -69,7 +71,7 @@ type KubevirtClient interface {
VirtualMachineFlavor(namespace string) flavorv1alpha1.VirtualMachineFlavorInterface
VirtualMachineClusterFlavor() flavorv1alpha1.VirtualMachineClusterFlavorInterface
MigrationPolicy() migrationsv1.MigrationPolicyInterface
ServerVersion() *ServerVersion
ServerVersion() ServerVersionInterface
ClusterProfiler() *ClusterProfiler
GuestfsVersion() *GuestfsVersion
RestClient() *rest.RESTClient
Expand Down Expand Up @@ -280,3 +282,7 @@ type KubeVirtInterface interface {
UpdateStatus(*v1.KubeVirt) (*v1.KubeVirt, error)
PatchStatus(name string, pt types.PatchType, data []byte, patchOptions *metav1.PatchOptions) (result *v1.KubeVirt, err error)
}

type ServerVersionInterface interface {
Get() (*version.Info, error)
}
2 changes: 1 addition & 1 deletion staging/src/kubevirt.io/client-go/kubecli/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const (
ApiGroupName = "/apis/" + v1.SubresourceGroupName
)

func (k *kubevirt) ServerVersion() *ServerVersion {
func (k *kubevirt) ServerVersion() ServerVersionInterface {
return &ServerVersion{
restClient: k.restClient,
resource: "version",
Expand Down
2 changes: 1 addition & 1 deletion tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3164,7 +3164,7 @@ func NewVirtctlCommand(args ...string) *cobra.Command {
if kubeconfig != nil && kubeconfig.String() != "" {
commandline = append(commandline, "--kubeconfig", kubeconfig.String())
}
cmd := virtctl.NewVirtctlCommand()
cmd, _ := virtctl.NewVirtctlCommand()
cmd.SetArgs(append(commandline, args...))
return cmd
}
Expand Down

0 comments on commit 836afc8

Please sign in to comment.