From a30c19d40c06f30568e57094b7541e37eb7d8af5 Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Mon, 19 Jun 2023 16:32:43 +0530 Subject: [PATCH 1/7] Show podman version in odo version; TODO: fix test and implement json Signed-off-by: Parthvi Vala --- pkg/odo/cli/version/version.go | 47 ++++++++++++++++++++----------- tests/integration/generic_test.go | 22 +++++++++------ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index e8acb137100..c505cca6bdf 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -3,6 +3,7 @@ package version import ( "context" "fmt" + "github.com/redhat-developer/odo/pkg/podman" "os" "strings" @@ -39,8 +40,8 @@ type VersionOptions struct { // serverInfo contains the remote server information if the user asked for it, nil otherwise serverInfo *kclient.ServerInfo - - clientset *clientset.Clientset + podmanInfo podman.SystemVersionReport + clientset *clientset.Clientset } var _ genericclioptions.Runnable = (*VersionOptions)(nil) @@ -58,14 +59,20 @@ func (o *VersionOptions) SetClientset(clientset *clientset.Clientset) { func (o *VersionOptions) Complete(ctx context.Context, cmdline cmdline.Cmdline, args []string) (err error) { if !o.clientFlag { // Let's fetch the info about the server, ignoring errors - client, err := kclient.New() - - if err == nil { - o.serverInfo, err = client.GetServerVersion(o.clientset.PreferenceClient.GetTimeout()) + if o.clientset.KubernetesClient != nil { + o.serverInfo, err = o.clientset.KubernetesClient.GetServerVersion(o.clientset.PreferenceClient.GetTimeout()) if err != nil { klog.V(4).Info("unable to fetch the server version: ", err) } } + + if o.clientset.PodmanClient != nil { + o.podmanInfo, err = o.clientset.PodmanClient.Version(ctx) + if err != nil { + klog.V(4).Info("unable to fetch the podman version: ", err) + } + } + } return nil } @@ -87,21 +94,27 @@ func (o *VersionOptions) Run(ctx context.Context) (err error) { fmt.Println("odo " + odoversion.VERSION + " (" + odoversion.GITCOMMIT + ")") - if !o.clientFlag && o.serverInfo != nil { + if o.clientFlag { + return nil + } + + message := "\n" + if o.serverInfo != nil { + message = fmt.Sprintf("Server: %v\n", o.serverInfo.Address) + // make sure we only include OpenShift info if we actually have it - openshiftStr := "" if len(o.serverInfo.OpenShiftVersion) > 0 { - openshiftStr = fmt.Sprintf("OpenShift: %v\n", o.serverInfo.OpenShiftVersion) + message += fmt.Sprintf("OpenShift: %v\n", o.serverInfo.OpenShiftVersion) } - fmt.Printf("\n"+ - "Server: %v\n"+ - "%v"+ - "Kubernetes: %v\n", - o.serverInfo.Address, - openshiftStr, - o.serverInfo.KubernetesVersion) + message += fmt.Sprintf("Kubernetes: %v\n", o.serverInfo.KubernetesVersion) } + if o.podmanInfo.Client != nil { + message += fmt.Sprintf("Podman (Client): %v\n", o.podmanInfo.Client.Version) + } + + fmt.Printf(message) + return nil } @@ -118,7 +131,7 @@ func NewCmdVersion(name, fullName string, testClientset clientset.Clientset) *co return genericclioptions.GenericRun(o, testClientset, cmd, args) }, } - clientset.Add(versionCmd, clientset.PREFERENCE) + clientset.Add(versionCmd, clientset.PREFERENCE, clientset.KUBERNETES_NULLABLE, clientset.PODMAN_NULLABLE) util.SetCommandGroup(versionCmd, util.UtilityGroup) versionCmd.SetUsageTemplate(util.CmdUsageTemplate) diff --git a/tests/integration/generic_test.go b/tests/integration/generic_test.go index b76873c8f2b..e0afe0f7e2b 100644 --- a/tests/integration/generic_test.go +++ b/tests/integration/generic_test.go @@ -117,14 +117,20 @@ var _ = Describe("odo generic", func() { BeforeEach(func() { odoVersion = helper.Cmd("odo", "version").ShouldPass().Out() }) - - It("should show the version of odo major components including server login URL", func() { - reOdoVersion := `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` - rekubernetesVersion := `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` - Expect(odoVersion).Should(SatisfyAll(MatchRegexp(reOdoVersion), MatchRegexp(rekubernetesVersion))) - serverURL := oc.GetCurrentServerURL() - Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) - }) + for _, podman := range []bool{true, false} { + podman := podman + FIt("should show the version of odo major components including server login URL", helper.LabelPodmanIf(podman, func() { + reOdoVersion := `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` + rekubernetesVersion := `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + Expect(odoVersion).Should(SatisfyAll(MatchRegexp(reOdoVersion), MatchRegexp(rekubernetesVersion))) + if podman { + podmanVersion := `^Podman \(Client\):\s*[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` + Expect(odoVersion).Should(Satisfy(MatchRegexp(podmanVersion))) + } + serverURL := oc.GetCurrentServerURL() + Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) + })) + } It("should show the version of odo major components", Label(helper.LabelNoCluster), func() { reOdoVersion := `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` From b83399cac0b62ce012009e353198154d8a93681d Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Mon, 19 Jun 2023 17:59:13 +0530 Subject: [PATCH 2/7] Add integration test Signed-off-by: Parthvi Vala --- pkg/odo/cli/version/version.go | 2 +- tests/helper/helper_podman.go | 15 ++++++ tests/integration/cmd_dev_test.go | 9 +--- tests/integration/generic_test.go | 76 +++++++++++++++++++++---------- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index c505cca6bdf..115e9699cec 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -113,7 +113,7 @@ func (o *VersionOptions) Run(ctx context.Context) (err error) { message += fmt.Sprintf("Podman (Client): %v\n", o.podmanInfo.Client.Version) } - fmt.Printf(message) + fmt.Print(message) return nil } diff --git a/tests/helper/helper_podman.go b/tests/helper/helper_podman.go index e89b94ded6f..bbd957a96b6 100644 --- a/tests/helper/helper_podman.go +++ b/tests/helper/helper_podman.go @@ -74,3 +74,18 @@ func GetPodmanVersion() string { Expect(err).ToNot(HaveOccurred()) return result.Client.Version } + +// GenerateDelayedPodman returns a podman cmd that sleeps for delaySecond before responding; +// this function is usually used in combination with PODMAN_CMD_INIT_TIMEOUT odo preference +func GenerateDelayedPodman(commonVarContext string, delaySecond int) string { + delayer := filepath.Join(commonVarContext, "podman-cmd-delayer") + fileContent := fmt.Sprintf(`#!/bin/bash + +echo Delaying command execution... >&2 +sleep %d +echo "$@" +`, delaySecond) + err := CreateFileWithContentAndPerm(delayer, fileContent, 0755) + Expect(err).ToNot(HaveOccurred()) + return delayer +} diff --git a/tests/integration/cmd_dev_test.go b/tests/integration/cmd_dev_test.go index 14655c19d76..57bc3126803 100644 --- a/tests/integration/cmd_dev_test.go +++ b/tests/integration/cmd_dev_test.go @@ -100,14 +100,7 @@ var _ = Describe("odo dev command tests", func() { // odo dev on cluster should not wait for the Podman client to initialize properly, if this client takes very long. // See https://github.com/redhat-developer/odo/issues/6575. // StartDevMode will time out if Podman client takes too long to initialize. - delayer := filepath.Join(commonVar.Context, "podman-cmd-delayer") - err = helper.CreateFileWithContentAndPerm(delayer, `#!/bin/bash - -echo Delaying command execution... >&2 -sleep 10 -echo "$@" -`, 0755) - Expect(err).ShouldNot(HaveOccurred()) + delayer := helper.GenerateDelayedPodman(commonVar.Context, 10) var devSession helper.DevSession devSession, err = helper.StartDevMode(helper.DevSessionOpts{ diff --git a/tests/integration/generic_test.go b/tests/integration/generic_test.go index e0afe0f7e2b..1df847f74e0 100644 --- a/tests/integration/generic_test.go +++ b/tests/integration/generic_test.go @@ -3,7 +3,6 @@ package integration import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/tests/helper" ) @@ -112,33 +111,60 @@ var _ = Describe("odo generic", func() { }) }) - When("executing odo version command", func() { - var odoVersion string - BeforeEach(func() { - odoVersion = helper.Cmd("odo", "version").ShouldPass().Out() + Context("executing odo version command", func() { + const ( + reOdoVersion = `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` + rekubernetesVersion = `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + rePodmanVersion = `Podman \(Client\):\s*[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + ) + When("executing the complete command with server info", func() { + var odoVersion string + BeforeEach(func() { + odoVersion = helper.Cmd("odo", "version").ShouldPass().Out() + }) + for _, podman := range []bool{true, false} { + podman := podman + It("should show the version of odo major components including server login URL", helper.LabelPodmanIf(podman, func() { + Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + + // odo tests setup (CommonBeforeEach) is designed in a way that if a test is labelled with 'podman', it will not have cluster configuration + // so we only test podman info on podman labelled test, and clsuter info otherwise + // TODO (pvala): Change this behavior when we write tests that should be tested on both podman and cluster simultaneously + // Ref: https://github.com/redhat-developer/odo/issues/6719 + if podman { + Expect(odoVersion).Should(MatchRegexp(rePodmanVersion)) + Expect(odoVersion).To(ContainSubstring(helper.GetPodmanVersion())) + } else { + Expect(odoVersion).Should(MatchRegexp(rekubernetesVersion)) + serverURL := oc.GetCurrentServerURL() + Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) + } + })) + } + + for _, label := range []string{helper.LabelNoCluster, helper.LabelUnauth} { + label := label + It("should show the version of odo major components", Label(label), func() { + Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + }) + } }) - for _, podman := range []bool{true, false} { - podman := podman - FIt("should show the version of odo major components including server login URL", helper.LabelPodmanIf(podman, func() { - reOdoVersion := `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` - rekubernetesVersion := `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` - Expect(odoVersion).Should(SatisfyAll(MatchRegexp(reOdoVersion), MatchRegexp(rekubernetesVersion))) - if podman { - podmanVersion := `^Podman \(Client\):\s*[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` - Expect(odoVersion).Should(Satisfy(MatchRegexp(podmanVersion))) - } - serverURL := oc.GetCurrentServerURL() - Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) - })) - } - - It("should show the version of odo major components", Label(helper.LabelNoCluster), func() { - reOdoVersion := `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` - Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + + When("podman client is bound to delay and odo version is run", Label(helper.LabelPodman), func() { + var odoVersion string + BeforeEach(func() { + delayer := helper.GenerateDelayedPodman(commonVar.Context, 2) + odoVersion = helper.Cmd("odo", "version").WithEnv("PODMAN_CMD="+delayer, "PODMAN_CMD_INIT_TIMEOUT=1s").ShouldPass().Out() + }) + It("should not print podman version if podman cmd timeout has been reached", func() { + Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + Expect(odoVersion).ToNot(ContainSubstring("Podman (Client):")) + }) }) - It("should show the version of odo major components", Label(helper.LabelUnauth), func() { - reOdoVersion := `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` + It("should only print client info when asked for it", func() { + odoVersion := helper.Cmd("odo", "version", "--client").ShouldPass().Out() Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + Expect(odoVersion).ToNot(SatisfyAll(ContainSubstring("Server"), ContainSubstring("Kubernetes"), ContainSubstring("Podman (Client)"))) }) }) From 77143b2bc752490ecb230f725f7d6a9d516b9d38 Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Tue, 20 Jun 2023 15:21:54 +0530 Subject: [PATCH 3/7] Add support for JSON Signed-off-by: Parthvi Vala --- pkg/api/version.go | 47 ++++++++++++++++++++ pkg/odo/cli/version/version.go | 61 +++++++++++++++++++++----- tests/helper/helper_generic.go | 7 +++ tests/integration/generic_test.go | 71 ++++++++++++++++++++++--------- 4 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 pkg/api/version.go diff --git a/pkg/api/version.go b/pkg/api/version.go new file mode 100644 index 00000000000..672202fd1d3 --- /dev/null +++ b/pkg/api/version.go @@ -0,0 +1,47 @@ +package api + +/* +{ + "version": "v3.11.0", + "gitCommit": "0acf1a5af", + "cluster": { + "serverURL": "https://kubernetes.docker.internal:6443", + "kubernetes": { + "version": "v1.25.9" + }, + "openshift": { + "version": "4.13.0" + } + }, + "podman": { + "client": { + "version": "4.5.1" + } + } +} +*/ + +type OdoVersion struct { + Version string `json:"version"` + GitCommit string `json:"gitCommit"` + Cluster *ClusterInfo `json:"cluster,omitempty"` + Podman *PodmanInfo `json:"podman,omitempty"` +} + +type ClusterInfo struct { + ServerURL string `json:"serverURL,omitempty"` + Kubernetes ClusterClientInfo `json:"kubernetes,omitempty"` + OpenShift ClusterClientInfo `json:"openshift,omitempty"` +} + +type ClusterClientInfo struct { + Version string `json:"version,omitempty"` +} + +type PodmanInfo struct { + Client PodmanClientInfo `json:"client,omitempty"` +} + +type PodmanClientInfo struct { + Version string `json:"version,omitempty"` +} diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index 115e9699cec..e331bea3c87 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -3,6 +3,8 @@ package version import ( "context" "fmt" + "github.com/redhat-developer/odo/pkg/api" + "github.com/redhat-developer/odo/pkg/odo/commonflags" "github.com/redhat-developer/odo/pkg/podman" "os" "strings" @@ -45,6 +47,7 @@ type VersionOptions struct { } var _ genericclioptions.Runnable = (*VersionOptions)(nil) +var _ genericclioptions.JsonOutputter = (*VersionOptions)(nil) // NewVersionOptions creates a new VersionOptions instance func NewVersionOptions() *VersionOptions { @@ -69,7 +72,7 @@ func (o *VersionOptions) Complete(ctx context.Context, cmdline cmdline.Cmdline, if o.clientset.PodmanClient != nil { o.podmanInfo, err = o.clientset.PodmanClient.Version(ctx) if err != nil { - klog.V(4).Info("unable to fetch the podman version: ", err) + klog.V(4).Info("unable to fetch the podman client version: ", err) } } @@ -82,35 +85,70 @@ func (o *VersionOptions) Validate(ctx context.Context) (err error) { return nil } +func (o *VersionOptions) RunForJsonOutput(ctx context.Context) (out interface{}, err error) { + return o.run(), nil +} + +func (o *VersionOptions) run() api.OdoVersion { + result := api.OdoVersion{ + Version: odoversion.VERSION, + GitCommit: odoversion.GITCOMMIT, + } + + if o.clientFlag { + return result + } + + if o.serverInfo != nil { + clusterInfo := &api.ClusterInfo{ + ServerURL: o.serverInfo.Address, + Kubernetes: api.ClusterClientInfo{Version: o.serverInfo.KubernetesVersion}, + OpenShift: api.ClusterClientInfo{Version: o.serverInfo.OpenShiftVersion}, + } + result.Cluster = clusterInfo + } + + if o.podmanInfo.Client != nil { + podmanInfo := &api.PodmanInfo{Client: api.PodmanClientInfo{Version: o.podmanInfo.Client.Version}} + result.Podman = podmanInfo + } + + return result +} + // Run contains the logic for the odo service create command func (o *VersionOptions) Run(ctx context.Context) (err error) { - // If verbose mode is enabled, dump all KUBECLT_* env variables - // this is usefull for debuging oc plugin integration + // If verbose mode is enabled, dump all KUBECTL_* env variables + // this is useful for debugging oc plugin integration for _, v := range os.Environ() { if strings.HasPrefix(v, "KUBECTL_") { klog.V(4).Info(v) } } - fmt.Println("odo " + odoversion.VERSION + " (" + odoversion.GITCOMMIT + ")") + odoVersion := o.run() + fmt.Println("odo " + odoVersion.Version + " (" + odoVersion.GitCommit + ")") if o.clientFlag { return nil } message := "\n" - if o.serverInfo != nil { - message = fmt.Sprintf("Server: %v\n", o.serverInfo.Address) + if odoVersion.Cluster != nil { + cluster := odoVersion.Cluster + message = fmt.Sprintf("Server: %v\n", cluster.ServerURL) // make sure we only include OpenShift info if we actually have it - if len(o.serverInfo.OpenShiftVersion) > 0 { - message += fmt.Sprintf("OpenShift: %v\n", o.serverInfo.OpenShiftVersion) + if cluster.OpenShift.Version != "" { + message += fmt.Sprintf("OpenShift: %v\n", cluster.OpenShift.Version) } - message += fmt.Sprintf("Kubernetes: %v\n", o.serverInfo.KubernetesVersion) + + message += fmt.Sprintf("Kubernetes: %v\n", cluster.Kubernetes.Version) + } - if o.podmanInfo.Client != nil { - message += fmt.Sprintf("Podman (Client): %v\n", o.podmanInfo.Client.Version) + if odoVersion.Podman != nil { + message += fmt.Sprintf("Podman Client: %v\n", odoVersion.Podman.Client.Version) } fmt.Print(message) @@ -131,6 +169,7 @@ func NewCmdVersion(name, fullName string, testClientset clientset.Clientset) *co return genericclioptions.GenericRun(o, testClientset, cmd, args) }, } + commonflags.UseOutputFlag(versionCmd) clientset.Add(versionCmd, clientset.PREFERENCE, clientset.KUBERNETES_NULLABLE, clientset.PODMAN_NULLABLE) util.SetCommandGroup(versionCmd, util.UtilityGroup) diff --git a/tests/helper/helper_generic.go b/tests/helper/helper_generic.go index 9e74f10c7be..f0c0880a79a 100644 --- a/tests/helper/helper_generic.go +++ b/tests/helper/helper_generic.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/onsi/gomega/types" "os" "path/filepath" "regexp" @@ -324,6 +325,12 @@ func JsonPathContentContain(json string, path string, value string) { Expect(result.String()).To(ContainSubstring(value), fmt.Sprintf("content of path %q should contain %q but is %q", path, value, result.String())) } +// JsonPathSatisfies expects content of the path to satisfy all the matchers passed to it +func JsonPathSatisfies(json string, path string, matchers ...types.GomegaMatcher) { + result := gjson.Get(json, path) + Expect(result.String()).Should(SatisfyAll(matchers...)) +} + // JsonPathDoesNotExist expects that the content of the path does not exist in the JSON string func JsonPathDoesNotExist(json string, path string) { result := gjson.Get(json, path) diff --git a/tests/integration/generic_test.go b/tests/integration/generic_test.go index 1df847f74e0..6fb133cdb1d 100644 --- a/tests/integration/generic_test.go +++ b/tests/integration/generic_test.go @@ -114,8 +114,9 @@ var _ = Describe("odo generic", func() { Context("executing odo version command", func() { const ( reOdoVersion = `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` - rekubernetesVersion = `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` - rePodmanVersion = `Podman \(Client\):\s*[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + reKubernetesVersion = `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + rePodmanVersion = `Podman Client:\s*[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + reJSONVersion = `^v{0,1}[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` ) When("executing the complete command with server info", func() { var odoVersion string @@ -125,20 +126,37 @@ var _ = Describe("odo generic", func() { for _, podman := range []bool{true, false} { podman := podman It("should show the version of odo major components including server login URL", helper.LabelPodmanIf(podman, func() { - Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) - - // odo tests setup (CommonBeforeEach) is designed in a way that if a test is labelled with 'podman', it will not have cluster configuration - // so we only test podman info on podman labelled test, and clsuter info otherwise - // TODO (pvala): Change this behavior when we write tests that should be tested on both podman and cluster simultaneously - // Ref: https://github.com/redhat-developer/odo/issues/6719 - if podman { - Expect(odoVersion).Should(MatchRegexp(rePodmanVersion)) - Expect(odoVersion).To(ContainSubstring(helper.GetPodmanVersion())) - } else { - Expect(odoVersion).Should(MatchRegexp(rekubernetesVersion)) - serverURL := oc.GetCurrentServerURL() - Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) - } + By("checking the human readable output", func() { + Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + + // odo tests setup (CommonBeforeEach) is designed in a way that if a test is labelled with 'podman', it will not have cluster configuration + // so we only test podman info on podman labelled test, and clsuter info otherwise + // TODO (pvala): Change this behavior when we write tests that should be tested on both podman and cluster simultaneously + // Ref: https://github.com/redhat-developer/odo/issues/6719 + if podman { + Expect(odoVersion).Should(MatchRegexp(rePodmanVersion)) + Expect(odoVersion).To(ContainSubstring(helper.GetPodmanVersion())) + } else { + Expect(odoVersion).Should(MatchRegexp(reKubernetesVersion)) + serverURL := oc.GetCurrentServerURL() + Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) + } + }) + + By("checking the JSON output", func() { + odoVersion = helper.Cmd("odo", "version", "-o", "json").ShouldPass().Out() + Expect(helper.IsJSON(odoVersion)).To(BeTrue()) + helper.JsonPathSatisfies(odoVersion, "version", MatchRegexp(reJSONVersion)) + helper.JsonPathExist(odoVersion, "gitCommit") + if podman { + helper.JsonPathSatisfies(odoVersion, "podman.client.version", MatchRegexp(reJSONVersion), Equal(helper.GetPodmanVersion())) + } else { + helper.JsonPathSatisfies(odoVersion, "cluster.kubernetes.version", MatchRegexp(reJSONVersion)) + serverURL := oc.GetCurrentServerURL() + helper.JsonPathContentIs(odoVersion, "cluster.serverURL", serverURL) + helper.JsonPathExist(odoVersion, "cluster.openshift") + } + }) })) } @@ -158,13 +176,24 @@ var _ = Describe("odo generic", func() { }) It("should not print podman version if podman cmd timeout has been reached", func() { Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) - Expect(odoVersion).ToNot(ContainSubstring("Podman (Client):")) + Expect(odoVersion).ToNot(ContainSubstring("Podman Client:")) }) }) - It("should only print client info when asked for it", func() { - odoVersion := helper.Cmd("odo", "version", "--client").ShouldPass().Out() - Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) - Expect(odoVersion).ToNot(SatisfyAll(ContainSubstring("Server"), ContainSubstring("Kubernetes"), ContainSubstring("Podman (Client)"))) + It("should only print client info when using --client flag", func() { + By("checking human readable output", func() { + odoVersion := helper.Cmd("odo", "version", "--client").ShouldPass().Out() + Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + Expect(odoVersion).ToNot(SatisfyAll(ContainSubstring("Server"), ContainSubstring("Kubernetes"), ContainSubstring("Podman Client"))) + }) + + By("checking JSON output", func() { + odoVersion := helper.Cmd("odo", "version", "--client", "-o", "json").ShouldPass().Out() + Expect(helper.IsJSON(odoVersion)).To(BeTrue()) + helper.JsonPathSatisfies(odoVersion, "version", MatchRegexp(reJSONVersion)) + helper.JsonPathExist(odoVersion, "gitCommit") + helper.JsonPathSatisfies(odoVersion, "cluster", BeEmpty()) + helper.JsonPathSatisfies(odoVersion, "podman", BeEmpty()) + }) }) }) From 2410197c2eb58f5161f11697d4c19847cae0088a Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Tue, 20 Jun 2023 17:47:08 +0530 Subject: [PATCH 4/7] Add documentation Signed-off-by: Parthvi Vala --- .../docs/command-reference/json-output.md | 29 ++++++++++++++++++- .../website/docs/command-reference/version.md | 26 +++++++++++++++++ pkg/kclient/oc_server.go | 1 + pkg/odo/cli/version/version.go | 2 +- 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 docs/website/docs/command-reference/version.md diff --git a/docs/website/docs/command-reference/json-output.md b/docs/website/docs/command-reference/json-output.md index fb05ed65650..2d052d6dd43 100644 --- a/docs/website/docs/command-reference/json-output.md +++ b/docs/website/docs/command-reference/json-output.md @@ -906,4 +906,31 @@ If odo can't find any projects on the cluster that you have access to, it will s ```shell $ odo list projects -o json {} -``` \ No newline at end of file +``` + +## odo version -o json +The `odo version -o json` returns the version information about `odo`, cluster and podman client. +```shell +odo version -o json +``` +```shell +$ odo version -o json +{ + "version": "v3.11.0", + "gitCommit": "ea2d256e8", + "cluster": { + "serverURL": "https://kubernetes.docker.internal:6443", + "kubernetes": { + "version": "v1.25.9" + }, + "openshift": { + "version": "4.13.0" + }, + }, + "podman": { + "client": { + "version": "4.5.1" + } + } +} +``` diff --git a/docs/website/docs/command-reference/version.md b/docs/website/docs/command-reference/version.md new file mode 100644 index 00000000000..7b1807d6060 --- /dev/null +++ b/docs/website/docs/command-reference/version.md @@ -0,0 +1,26 @@ +--- +title: odo version +--- + +## Description +The `odo version` command returns the version information about `odo`, cluster and podman client. + +## Running the Command +The command takes an optional `--client` flag that only returns version information about `odo`. It will only print Openshift version if it is available. +```shell +odo version [--client] [-o json] +``` + +
+Example + +```shell +$ odo version +odo v3.11.0 (a9e6cdc34) + +Server: https://ab0bc42973f0043e7a2b9c24f5acddd6-9c1554c20c1ec323.elb.us-east-1.amazonaws.com:6443 +OpenShift: 4.13.0 +Kubernetes: v1.27.2+b451817 +Podman Client: 4.5.1 +``` +
diff --git a/pkg/kclient/oc_server.go b/pkg/kclient/oc_server.go index eb539246fa4..fc56d27352c 100644 --- a/pkg/kclient/oc_server.go +++ b/pkg/kclient/oc_server.go @@ -61,6 +61,7 @@ func (c *Client) GetServerVersion(timeout time.Duration) (*ServerInfo, error) { // This will fetch the information about OpenShift Version coreGet := c.GetClient().CoreV1().RESTClient().Get() + // TODO: Use this /apis/config.openshift.io/v1/clusterversions/version instead rawOpenShiftVersion, err := coreGet.AbsPath("/version/openshift").Do(context.TODO()).Raw() if err != nil { klog.V(3).Info("Unable to get OpenShift Version: ", err) diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index e331bea3c87..c905b6a8b23 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -136,7 +136,7 @@ func (o *VersionOptions) Run(ctx context.Context) (err error) { message := "\n" if odoVersion.Cluster != nil { cluster := odoVersion.Cluster - message = fmt.Sprintf("Server: %v\n", cluster.ServerURL) + message += fmt.Sprintf("Server: %v\n", cluster.ServerURL) // make sure we only include OpenShift info if we actually have it if cluster.OpenShift.Version != "" { From 145c12cbe831fd4256e4554e8596fc27647f4261 Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Tue, 20 Jun 2023 17:56:50 +0530 Subject: [PATCH 5/7] Fix missing OpenShift version Signed-off-by: Parthvi Vala --- pkg/kclient/oc_server.go | 7 +++---- tests/integration/generic_test.go | 6 ++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/kclient/oc_server.go b/pkg/kclient/oc_server.go index fc56d27352c..985c7d392f2 100644 --- a/pkg/kclient/oc_server.go +++ b/pkg/kclient/oc_server.go @@ -61,16 +61,15 @@ func (c *Client) GetServerVersion(timeout time.Duration) (*ServerInfo, error) { // This will fetch the information about OpenShift Version coreGet := c.GetClient().CoreV1().RESTClient().Get() - // TODO: Use this /apis/config.openshift.io/v1/clusterversions/version instead - rawOpenShiftVersion, err := coreGet.AbsPath("/version/openshift").Do(context.TODO()).Raw() + rawOpenShiftVersion, err := coreGet.AbsPath("/apis/config.openshift.io/v1/clusterversions/version").Do(context.TODO()).Raw() if err != nil { klog.V(3).Info("Unable to get OpenShift Version: ", err) } else { - var openShiftVersion version.Info + var openShiftVersion configv1.ClusterVersion if e := json.Unmarshal(rawOpenShiftVersion, &openShiftVersion); e != nil { return nil, fmt.Errorf("unable to unmarshal OpenShift version %v: %w", string(rawOpenShiftVersion), e) } - info.OpenShiftVersion = openShiftVersion.GitVersion + info.OpenShiftVersion = openShiftVersion.Status.Desired.Version } // This will fetch the information about Kubernetes Version diff --git a/tests/integration/generic_test.go b/tests/integration/generic_test.go index 6fb133cdb1d..13d45e4ebb5 100644 --- a/tests/integration/generic_test.go +++ b/tests/integration/generic_test.go @@ -140,6 +140,9 @@ var _ = Describe("odo generic", func() { Expect(odoVersion).Should(MatchRegexp(reKubernetesVersion)) serverURL := oc.GetCurrentServerURL() Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) + if !helper.IsKubernetesCluster() { + Expect(odoVersion).Should(ContainSubstring("OpenShift: ")) + } } }) @@ -155,6 +158,9 @@ var _ = Describe("odo generic", func() { serverURL := oc.GetCurrentServerURL() helper.JsonPathContentIs(odoVersion, "cluster.serverURL", serverURL) helper.JsonPathExist(odoVersion, "cluster.openshift") + if !helper.IsKubernetesCluster() { + helper.JsonPathSatisfies(odoVersion, "cluster.openshift", Not(BeEmpty())) + } } }) })) From b26605d2523ff5e4eb53100b2f02c55db797ec02 Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Wed, 21 Jun 2023 18:17:35 +0530 Subject: [PATCH 6/7] Add warnings when unable to fetch version information Signed-off-by: Parthvi Vala --- docs/website/docs/command-reference/json-output.md | 5 +++-- docs/website/docs/command-reference/version.md | 6 ++++-- pkg/odo/cli/version/version.go | 8 +++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/website/docs/command-reference/json-output.md b/docs/website/docs/command-reference/json-output.md index 2d052d6dd43..c389f7658dc 100644 --- a/docs/website/docs/command-reference/json-output.md +++ b/docs/website/docs/command-reference/json-output.md @@ -909,9 +909,10 @@ $ odo list projects -o json ``` ## odo version -o json -The `odo version -o json` returns the version information about `odo`, cluster and podman client. +The `odo version -o json` returns the version information about `odo`, cluster server and podman client. +Use `--client` flag to only obtain version information about `odo`. ```shell -odo version -o json +odo version -o json [--client] ``` ```shell $ odo version -o json diff --git a/docs/website/docs/command-reference/version.md b/docs/website/docs/command-reference/version.md index 7b1807d6060..6689e107e10 100644 --- a/docs/website/docs/command-reference/version.md +++ b/docs/website/docs/command-reference/version.md @@ -3,10 +3,12 @@ title: odo version --- ## Description -The `odo version` command returns the version information about `odo`, cluster and podman client. +The `odo version` command returns the version information about `odo`, cluster server and podman client. ## Running the Command -The command takes an optional `--client` flag that only returns version information about `odo`. It will only print Openshift version if it is available. +The command takes an optional `--client` flag that only returns version information about `odo`. + +The command will only print Openshift version if it is available. ```shell odo version [--client] [-o json] ``` diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index c905b6a8b23..91fb009506c 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "github.com/redhat-developer/odo/pkg/api" + "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/odo/commonflags" "github.com/redhat-developer/odo/pkg/podman" "os" @@ -75,7 +76,13 @@ func (o *VersionOptions) Complete(ctx context.Context, cmdline cmdline.Cmdline, klog.V(4).Info("unable to fetch the podman client version: ", err) } } + } + if o.serverInfo == nil { + log.Warning("unable to fetch the cluster server version") + } + if o.podmanInfo.Client == nil { + log.Warning("unable to fetch the podman client version") } return nil } @@ -144,7 +151,6 @@ func (o *VersionOptions) Run(ctx context.Context) (err error) { } message += fmt.Sprintf("Kubernetes: %v\n", cluster.Kubernetes.Version) - } if odoVersion.Podman != nil { From 93618ebeaecc20e673ef9ee2f3455e521270da33 Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Thu, 22 Jun 2023 14:57:38 +0530 Subject: [PATCH 7/7] Do not print warning when --client is used and review Signed-off-by: Parthvi Vala --- pkg/api/version.go | 8 +++--- pkg/odo/cli/version/version.go | 43 +++++++++++++++++-------------- tests/integration/generic_test.go | 1 - 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/pkg/api/version.go b/pkg/api/version.go index 672202fd1d3..9df9ef11ed3 100644 --- a/pkg/api/version.go +++ b/pkg/api/version.go @@ -29,9 +29,9 @@ type OdoVersion struct { } type ClusterInfo struct { - ServerURL string `json:"serverURL,omitempty"` - Kubernetes ClusterClientInfo `json:"kubernetes,omitempty"` - OpenShift ClusterClientInfo `json:"openshift,omitempty"` + ServerURL string `json:"serverURL,omitempty"` + Kubernetes *ClusterClientInfo `json:"kubernetes,omitempty"` + OpenShift *ClusterClientInfo `json:"openshift,omitempty"` } type ClusterClientInfo struct { @@ -39,7 +39,7 @@ type ClusterClientInfo struct { } type PodmanInfo struct { - Client PodmanClientInfo `json:"client,omitempty"` + Client *PodmanClientInfo `json:"client,omitempty"` } type PodmanClientInfo struct { diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index 91fb009506c..054c889fa7c 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -61,20 +61,22 @@ func (o *VersionOptions) SetClientset(clientset *clientset.Clientset) { // Complete completes VersionOptions after they have been created func (o *VersionOptions) Complete(ctx context.Context, cmdline cmdline.Cmdline, args []string) (err error) { - if !o.clientFlag { - // Let's fetch the info about the server, ignoring errors - if o.clientset.KubernetesClient != nil { - o.serverInfo, err = o.clientset.KubernetesClient.GetServerVersion(o.clientset.PreferenceClient.GetTimeout()) - if err != nil { - klog.V(4).Info("unable to fetch the server version: ", err) - } + if o.clientFlag { + return nil + } + + // Fetch the info about the server, ignoring errors + if o.clientset.KubernetesClient != nil { + o.serverInfo, err = o.clientset.KubernetesClient.GetServerVersion(o.clientset.PreferenceClient.GetTimeout()) + if err != nil { + klog.V(4).Info("unable to fetch the server version: ", err) } + } - if o.clientset.PodmanClient != nil { - o.podmanInfo, err = o.clientset.PodmanClient.Version(ctx) - if err != nil { - klog.V(4).Info("unable to fetch the podman client version: ", err) - } + if o.clientset.PodmanClient != nil { + o.podmanInfo, err = o.clientset.PodmanClient.Version(ctx) + if err != nil { + klog.V(4).Info("unable to fetch the podman client version: ", err) } } @@ -109,14 +111,16 @@ func (o *VersionOptions) run() api.OdoVersion { if o.serverInfo != nil { clusterInfo := &api.ClusterInfo{ ServerURL: o.serverInfo.Address, - Kubernetes: api.ClusterClientInfo{Version: o.serverInfo.KubernetesVersion}, - OpenShift: api.ClusterClientInfo{Version: o.serverInfo.OpenShiftVersion}, + Kubernetes: &api.ClusterClientInfo{Version: o.serverInfo.KubernetesVersion}, + } + if o.serverInfo.OpenShiftVersion != "" { + clusterInfo.OpenShift = &api.ClusterClientInfo{Version: o.serverInfo.OpenShiftVersion} } result.Cluster = clusterInfo } if o.podmanInfo.Client != nil { - podmanInfo := &api.PodmanInfo{Client: api.PodmanClientInfo{Version: o.podmanInfo.Client.Version}} + podmanInfo := &api.PodmanInfo{Client: &api.PodmanClientInfo{Version: o.podmanInfo.Client.Version}} result.Podman = podmanInfo } @@ -146,14 +150,15 @@ func (o *VersionOptions) Run(ctx context.Context) (err error) { message += fmt.Sprintf("Server: %v\n", cluster.ServerURL) // make sure we only include OpenShift info if we actually have it - if cluster.OpenShift.Version != "" { + if cluster.OpenShift != nil && cluster.OpenShift.Version != "" { message += fmt.Sprintf("OpenShift: %v\n", cluster.OpenShift.Version) } - - message += fmt.Sprintf("Kubernetes: %v\n", cluster.Kubernetes.Version) + if cluster.Kubernetes != nil { + message += fmt.Sprintf("Kubernetes: %v\n", cluster.Kubernetes.Version) + } } - if odoVersion.Podman != nil { + if odoVersion.Podman != nil && odoVersion.Podman.Client != nil { message += fmt.Sprintf("Podman Client: %v\n", odoVersion.Podman.Client.Version) } diff --git a/tests/integration/generic_test.go b/tests/integration/generic_test.go index 13d45e4ebb5..4a03c015875 100644 --- a/tests/integration/generic_test.go +++ b/tests/integration/generic_test.go @@ -157,7 +157,6 @@ var _ = Describe("odo generic", func() { helper.JsonPathSatisfies(odoVersion, "cluster.kubernetes.version", MatchRegexp(reJSONVersion)) serverURL := oc.GetCurrentServerURL() helper.JsonPathContentIs(odoVersion, "cluster.serverURL", serverURL) - helper.JsonPathExist(odoVersion, "cluster.openshift") if !helper.IsKubernetesCluster() { helper.JsonPathSatisfies(odoVersion, "cluster.openshift", Not(BeEmpty())) }