From 3ee8747fdc2e1801a7ba377390e151c9b62f279a Mon Sep 17 00:00:00 2001 From: Somtochi Onyekwere Date: Mon, 4 Oct 2021 14:39:22 +0100 Subject: [PATCH] Add flux version command Signed-off-by: Somtochi Onyekwere --- cmd/flux/version.go | 129 +++++++++++++++++++++++++++------ cmd/flux/version_test.go | 15 ---- cmd/flux/version_utils.go | 58 +++++++++++++++ cmd/flux/version_utils_test.go | 55 ++++++++++++++ 4 files changed, 221 insertions(+), 36 deletions(-) delete mode 100644 cmd/flux/version_test.go create mode 100644 cmd/flux/version_utils.go create mode 100644 cmd/flux/version_utils_test.go diff --git a/cmd/flux/version.go b/cmd/flux/version.go index cbbcf2b6..7a0b9f9d 100644 --- a/cmd/flux/version.go +++ b/cmd/flux/version.go @@ -1,42 +1,129 @@ +/* +Copyright 2021 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package main import ( + "context" + "encoding/json" "fmt" + "strings" + + "github.com/spf13/cobra" + v1 "k8s.io/api/apps/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" "github.com/fluxcd/flux2/internal/utils" - "github.com/fluxcd/flux2/pkg/manifestgen/install" ) -func getVersion(input string) (string, error) { - if input == "" { - return rootArgs.defaults.Version, nil - } +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the client and server-side components version information.", + Long: "Print the client and server-side components version information for the current context.", + Example: `# Print client and server-side version + flux version + + # Print only client version + flux version --client + + # Print information in json format + flux version -o json +`, + RunE: versionCmdRun, +} + +type versionFlags struct { + client bool + output string +} + +var versionArgs versionFlags - if isEmbeddedVersion(input) { - return input, nil +func init() { + versionCmd.Flags().BoolVar(&versionArgs.client, "client", false, + "print only client version") + versionCmd.Flags().StringVarP(&versionArgs.output, "output", "o", "yaml", + "the format in which the information should be printed. can be 'json' or 'yaml'") + rootCmd.AddCommand(versionCmd) +} + +func versionCmdRun(cmd *cobra.Command, args []string) error { + if versionArgs.output != "yaml" && versionArgs.output != "json" { + return fmt.Errorf("--output must be json or yaml, not %s", versionArgs.output) } - var err error - if input == install.MakeDefaultOptions().Version { - input, err = install.GetLatestVersion() + ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) + defer cancel() + + info := map[string]string{} + info["flux"] = rootArgs.defaults.Version + + if !versionArgs.client { + kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) if err != nil { - return "", err + return err } - } else { - if ok, err := install.ExistingVersion(input); err != nil || !ok { - if err == nil { - err = fmt.Errorf("targeted version '%s' does not exist", input) + + selector := client.MatchingLabels{"app.kubernetes.io/instance": rootArgs.namespace} + var list v1.DeploymentList + if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace), selector); err != nil { + return err + } + + if len(list.Items) == 0 { + return fmt.Errorf("no deployments found in %s namespace", rootArgs.namespace) + } + + for _, d := range list.Items { + for _, c := range d.Spec.Template.Spec.Containers { + name, tag, err := splitImageStr(c.Image) + if err != nil { + return err + } + info[name] = tag } - return "", err } } - if !utils.CompatibleVersion(VERSION, input) { - return "", fmt.Errorf("targeted version '%s' is not compatible with your current version of flux (%s)", input, VERSION) + var marshalled []byte + var err error + + if versionArgs.output == "json" { + marshalled, err = json.MarshalIndent(&info, "", " ") + marshalled = append(marshalled, "\n"...) + } else { + marshalled, err = yaml.Marshal(&info) + } + + if err != nil { + return err } - return input, nil + + rootCmd.Print(string(marshalled)) + return nil } -func isEmbeddedVersion(input string) bool { - return input == rootArgs.defaults.Version +func splitImageStr(image string) (string, string, error) { + imageArr := strings.Split(image, ":") + if len(imageArr) < 2 { + return "", "", fmt.Errorf("missing image tag in image %s", image) + } + + name, tag := imageArr[0], imageArr[1] + nameArr := strings.Split(name, "/") + return nameArr[len(nameArr)-1], tag, nil } diff --git a/cmd/flux/version_test.go b/cmd/flux/version_test.go deleted file mode 100644 index e477707e..00000000 --- a/cmd/flux/version_test.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build unit - -package main - -import ( - "testing" -) - -func TestVersion(t *testing.T) { - cmd := cmdTestCase{ - args: "--version", - assert: assertGoldenValue("flux version 0.0.0-dev.0\n"), - } - cmd.runTestCmd(t) -} diff --git a/cmd/flux/version_utils.go b/cmd/flux/version_utils.go new file mode 100644 index 00000000..8f64ebf3 --- /dev/null +++ b/cmd/flux/version_utils.go @@ -0,0 +1,58 @@ +/* +Copyright 2020 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + + "github.com/fluxcd/flux2/internal/utils" + "github.com/fluxcd/flux2/pkg/manifestgen/install" +) + +func getVersion(input string) (string, error) { + if input == "" { + return rootArgs.defaults.Version, nil + } + + if isEmbeddedVersion(input) { + return input, nil + } + + var err error + if input == install.MakeDefaultOptions().Version { + input, err = install.GetLatestVersion() + if err != nil { + return "", err + } + } else { + if ok, err := install.ExistingVersion(input); err != nil || !ok { + if err == nil { + err = fmt.Errorf("targeted version '%s' does not exist", input) + } + return "", err + } + } + + if !utils.CompatibleVersion(VERSION, input) { + return "", fmt.Errorf("targeted version '%s' is not compatible with your current version of flux (%s)", input, VERSION) + } + return input, nil +} + +func isEmbeddedVersion(input string) bool { + return input == rootArgs.defaults.Version +} diff --git a/cmd/flux/version_utils_test.go b/cmd/flux/version_utils_test.go new file mode 100644 index 00000000..0aab01d9 --- /dev/null +++ b/cmd/flux/version_utils_test.go @@ -0,0 +1,55 @@ +// +build unit + +/* +Copyright 2021 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "testing" +) + +func TestVersion(t *testing.T) { + cmd := cmdTestCase{ + args: "--version", + assert: assertGoldenValue("flux version 0.0.0-dev.0\n"), + } + cmd.runTestCmd(t) +} + +func TestVersionCmd(t *testing.T) { + tests := []struct { + args string + expected string + }{ + { + args: "version --client", + expected: "flux: v0.0.0-dev.0\n", + }, + { + args: "version --client -o json", + expected: "{\n \"flux\": \"v0.0.0-dev.0\"\n}\n", + }, + } + + for _, tt := range tests { + cmd := cmdTestCase{ + args: tt.args, + assert: assertGoldenValue(tt.expected), + } + cmd.runTestCmd(t) + } +}