From 19bc4734b64cd6761bf774c4db3251a4bf3790b1 Mon Sep 17 00:00:00 2001 From: JoshVanL Date: Sat, 21 Mar 2020 18:38:42 +0000 Subject: [PATCH] Adds cert-manager-ctl with version command Signed-off-by: JoshVanL --- cmd/ctl/BUILD.bazel | 40 ++++++++++++ cmd/ctl/cmd.go | 44 +++++++++++++ cmd/ctl/main.go | 53 ++++++++++++++++ cmd/ctl/pkg/version/BUILD.bazel | 29 +++++++++ cmd/ctl/pkg/version/version.go | 107 ++++++++++++++++++++++++++++++++ pkg/util/version.go | 25 +++++++- 6 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 cmd/ctl/BUILD.bazel create mode 100644 cmd/ctl/cmd.go create mode 100644 cmd/ctl/main.go create mode 100644 cmd/ctl/pkg/version/BUILD.bazel create mode 100644 cmd/ctl/pkg/version/version.go diff --git a/cmd/ctl/BUILD.bazel b/cmd/ctl/BUILD.bazel new file mode 100644 index 000000000..37d34ec76 --- /dev/null +++ b/cmd/ctl/BUILD.bazel @@ -0,0 +1,40 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "cmd.go", + "main.go", + ], + importpath = "github.com/jetstack/cert-manager/cmd/ctl", + visibility = ["//visibility:private"], + deps = [ + "//cmd/ctl/pkg/version:go_default_library", + "@com_github_spf13_cobra//:go_default_library", + "@io_k8s_cli_runtime//pkg/genericclioptions:go_default_library", + ], +) + +go_binary( + name = "ctl", + out = "cert-manager-ctl", + embed = [":go_default_library"], + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//cmd/ctl/pkg/version:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/cmd/ctl/cmd.go b/cmd/ctl/cmd.go new file mode 100644 index 000000000..179b57745 --- /dev/null +++ b/cmd/ctl/cmd.go @@ -0,0 +1,44 @@ +/* Copyright 2019 The Jetstack cert-manager contributors. + +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 ( + "io" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericclioptions" + + "github.com/jetstack/cert-manager/cmd/ctl/pkg/version" +) + +func NewCertManagerCtlCommand(in io.Reader, out, err io.Writer, stopCh <-chan struct{}) *cobra.Command { + cmds := &cobra.Command{ + Use: "cert-manager-ctl", + Short: "cert-manager CLI tool to manage and configure cert-manager resources", + Long: ` +cert-manager-ctl is a CLI tool managage and confiure cert-manager resources for Kubernetes`, + Run: runHelp, + } + + ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err} + cmds.AddCommand(version.NewCmdVersion(ioStreams)) + + return cmds +} + +func runHelp(cmd *cobra.Command, args []string) { + cmd.Help() +} diff --git a/cmd/ctl/main.go b/cmd/ctl/main.go new file mode 100644 index 000000000..90afe9e55 --- /dev/null +++ b/cmd/ctl/main.go @@ -0,0 +1,53 @@ +/* +Copyright 2019 The Jetstack cert-manager contributors. + +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 ( + "flag" + "fmt" + "os" + "os/signal" + "syscall" +) + +func main() { + stopCh := SetupSignalHandler() + cmd := NewCertManagerCtlCommand(os.Stdin, os.Stdout, os.Stderr, stopCh) + cmd.Flags().AddGoFlagSet(flag.CommandLine) + + flag.CommandLine.Parse([]string{}) + if err := cmd.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + } +} + +// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned +// which is closed on one of these signals. If a second signal is caught, the program +// is terminated with exit code 1. +func SetupSignalHandler() (stopCh <-chan struct{}) { + stop := make(chan struct{}) + c := make(chan os.Signal, 2) + signal.Notify(c, []os.Signal{os.Interrupt, syscall.SIGTERM}...) + go func() { + <-c + close(stop) + <-c + os.Exit(1) // second signal. Exit directly. + }() + + return stop +} diff --git a/cmd/ctl/pkg/version/BUILD.bazel b/cmd/ctl/pkg/version/BUILD.bazel new file mode 100644 index 000000000..904d6ea04 --- /dev/null +++ b/cmd/ctl/pkg/version/BUILD.bazel @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["version.go"], + importpath = "github.com/jetstack/cert-manager/cmd/ctl/pkg/version", + visibility = ["//visibility:public"], + deps = [ + "//pkg/util:go_default_library", + "@com_github_spf13_cobra//:go_default_library", + "@io_k8s_cli_runtime//pkg/genericclioptions:go_default_library", + "@io_k8s_kubectl//pkg/cmd/util:go_default_library", + "@io_k8s_sigs_yaml//:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/cmd/ctl/pkg/version/version.go b/cmd/ctl/pkg/version/version.go new file mode 100644 index 000000000..4c05c576f --- /dev/null +++ b/cmd/ctl/pkg/version/version.go @@ -0,0 +1,107 @@ +/* +Copyright 2019 The Jetstack cert-manager contributors. + +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 version + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/jetstack/cert-manager/pkg/util" + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericclioptions" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "sigs.k8s.io/yaml" +) + +// Options is a struct to support version command +type Options struct { + Output string + Short bool + + genericclioptions.IOStreams +} + +// NewOptions returns initialized Options +func NewOptions(ioStreams genericclioptions.IOStreams) *Options { + return &Options{ + IOStreams: ioStreams, + } +} + +// NewCmdVersion returns a cobra command for fetching versions +func NewCmdVersion(ioStreams genericclioptions.IOStreams) *cobra.Command { + o := NewOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "version", + Short: "Print the cert-manager-ctl version", + Long: "Print the cert-manager-ctl version", + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "One of 'yaml' or 'json'.") + cmd.Flags().BoolVar(&o.Short, "short", o.Short, "If true, print just the version number.") + + return cmd +} + +// Validate validates the provided options +func (o *Options) Validate() error { + if o.Output != "" && o.Output != "yaml" && o.Output != "json" { + return errors.New(`--output must be 'yaml' or 'json'`) + } + + return nil +} + +// Run executes version command +func (o *Options) Run() error { + var err error + + versionInfo := util.VersionInfo() + + switch o.Output { + case "": + if o.Short { + fmt.Fprintf(o.Out, "%s\n", versionInfo.GitVersion) + } else { + fmt.Fprintf(o.Out, "%#v\n", versionInfo) + } + case "yaml": + marshalled, err := yaml.Marshal(&versionInfo) + if err != nil { + return err + } + fmt.Fprint(o.Out, string(marshalled)) + case "json": + marshalled, err := json.MarshalIndent(&versionInfo, "", " ") + if err != nil { + return err + } + fmt.Fprintln(o.Out, string(marshalled)) + default: + // There is a bug in the program if we hit this case. + // However, we follow a policy of never panicking. + return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.Output) + } + + return err +} diff --git a/pkg/util/version.go b/pkg/util/version.go index 5b5a39ead..65a868e34 100644 --- a/pkg/util/version.go +++ b/pkg/util/version.go @@ -16,7 +16,19 @@ limitations under the License. package util -import "fmt" +import ( + "fmt" + "runtime" +) + +type Version struct { + GitVersion string `json:"gitVersion"` + GitCommit string `json:"gitCommit"` + GitTreeState string `json:"gitTreeState"` + GoVersion string `json:"goVersion"` + Compiler string `json:"compiler"` + Platform string `json:"platform"` +} // This variable block holds information used to build up the version string var ( @@ -25,6 +37,17 @@ var ( AppVersion = "canary" ) +func VersionInfo() Version { + return Version{ + GitVersion: AppVersion, + GitCommit: AppGitCommit, + GitTreeState: AppGitState, + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } +} + func version() string { v := AppVersion if AppVersion == "canary" && AppGitCommit != "" {