From 6e012c90359a0ee357ab75afeefb239b0bedc51e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 20 Apr 2021 10:28:34 -0700 Subject: [PATCH 1/3] internal/cli: version shows Waypoint server version --- internal/cli/base.go | 2 +- internal/cli/base_init.go | 12 ++++++++++-- internal/cli/init.go | 2 +- internal/cli/version.go | 29 +++++++++++++++++++++++++---- internal/client/project.go | 6 ++++++ internal/client/server.go | 3 +++ internal/serverclient/client.go | 7 ++++++- internal/version/version.go | 2 +- 8 files changed, 53 insertions(+), 10 deletions(-) diff --git a/internal/cli/base.go b/internal/cli/base.go index de55285e45a..b47aea3e3a4 100644 --- a/internal/cli/base.go +++ b/internal/cli/base.go @@ -237,7 +237,7 @@ func (c *baseCommand) Init(opts ...Option) error { // Create our client if baseCfg.Client { - c.project, err = c.initClient() + c.project, err = c.initClient(nil) if err != nil { c.logError(c.Log, "failed to create client", err) return err diff --git a/internal/cli/base_init.go b/internal/cli/base_init.go index 2e595e1d29f..6581b41fe45 100644 --- a/internal/cli/base_init.go +++ b/internal/cli/base_init.go @@ -1,6 +1,7 @@ package cli import ( + "context" "errors" "fmt" "path/filepath" @@ -64,7 +65,10 @@ func (c *baseCommand) initConfigLoad(path string) (*configpkg.Config, error) { } // initClient initializes the client. -func (c *baseCommand) initClient() (*clientpkg.Project, error) { +// +// If ctx is nil, c.Ctx will be used. If ctx is non-nil, that context will be +// used and c.Ctx will be ignored. +func (c *baseCommand) initClient(ctx context.Context) (*clientpkg.Project, error) { // We use our flag-based connection info if the user set an addr. var flagConnection *clicontext.Config if v := c.flagConnection; v.Server.Address != "" { @@ -102,6 +106,10 @@ func (c *baseCommand) initClient() (*clientpkg.Project, error) { opts = append(opts, clientpkg.WithUI(c.ui)) } + if ctx == nil { + ctx = c.Ctx + } + // Create our client - return clientpkg.New(c.Ctx, opts...) + return clientpkg.New(ctx, opts...) } diff --git a/internal/cli/init.go b/internal/cli/init.go index 69047fd75ac..919da943980 100644 --- a/internal/cli/init.go +++ b/internal/cli/init.go @@ -234,7 +234,7 @@ func (c *InitCommand) validateServer() bool { defer sg.Wait() s := sg.Add("Validating server credentials...") - client, err := c.initClient() + client, err := c.initClient(nil) if err != nil { c.stepError(s, initStepConnect, err) return false diff --git a/internal/cli/version.go b/internal/cli/version.go index 76022a129ad..f872daf11cd 100644 --- a/internal/cli/version.go +++ b/internal/cli/version.go @@ -1,9 +1,14 @@ package cli import ( + "context" + "errors" + "time" + "github.com/posener/complete" "github.com/hashicorp/waypoint/internal/pkg/flag" + "github.com/hashicorp/waypoint/internal/serverclient" "github.com/hashicorp/waypoint/internal/version" ) @@ -22,12 +27,26 @@ func (c *VersionCommand) Run(args []string) int { WithFlags(flagSet), WithNoConfig(), WithClient(false), + WithNoAutoServer(), ); err != nil { return 1 } out := c.VersionInfo.FullVersionNumber(true) - c.ui.Output(out) + c.ui.Output("CLI: %s", out) + + // Get our server version. We use a short context here. + ctx, cancel := context.WithTimeout(c.Ctx, 2*time.Second) + defer cancel() + client, err := c.initClient(ctx) + if err != nil && !errors.Is(err, serverclient.ErrNoServerConfig) { + c.ui.Output("Error connecting to server to read server version: %s", err.Error()) + } + + if err == nil { + server := client.ServerVersion() + c.ui.Output("Server: %s", server.Version) + } return 0 } @@ -52,9 +71,11 @@ func (c *VersionCommand) Help() string { return formatHelp(` Usage: waypoint version - Prints the version of this Waypoint CLI. + Prints the version information for Waypoint. + + This command will show the version of the current Waypoint CLI. If + the CLI is configured to communicate to a Waypoint server, the server + version will also be shown. - There are no arguments or flags to this command. Any additional arguments or - flags are ignored. `) } diff --git a/internal/client/project.go b/internal/client/project.go index f7072398717..8170ab6275d 100644 --- a/internal/client/project.go +++ b/internal/client/project.go @@ -27,6 +27,7 @@ type Project struct { labels map[string]string dataSourceOverrides map[string]string cleanupFunc func() + serverVersion *pb.VersionInfo local bool @@ -141,6 +142,11 @@ func (c *Project) Local() bool { return c.localServer } +// ServerVersion returns the server version that this client is connected to. +func (c *Project) ServerVersion() *pb.VersionInfo { + return c.serverVersion +} + // Close should be called to clean up any resources that the client created. func (c *Project) Close() error { // Stop the runner early so that it we block here waiting for any outstanding jobs to finish diff --git a/internal/client/server.go b/internal/client/server.go index 411d2613bbe..7f9fbed49f2 100644 --- a/internal/client/server.go +++ b/internal/client/server.go @@ -187,6 +187,9 @@ func (c *Project) negotiateApiVersion(ctx context.Context) error { "entrypoint_current", resp.Info.Entrypoint.Current, ) + // Store the server version info + c.serverVersion = resp.Info + vsn, err := protocolversion.Negotiate(protocolversion.Current().Api, resp.Info.Api) if err != nil { return err diff --git a/internal/serverclient/client.go b/internal/serverclient/client.go index 261ab0eff6a..4dca38018c4 100644 --- a/internal/serverclient/client.go +++ b/internal/serverclient/client.go @@ -3,6 +3,7 @@ package serverclient import ( "context" "crypto/tls" + "errors" "fmt" "os" "time" @@ -15,6 +16,10 @@ import ( "github.com/hashicorp/waypoint/internal/serverconfig" ) +// ErrNoServerConfig is the error when there is no server configuration +// found for connection. +var ErrNoServerConfig = errors.New("no server connection configuration found") + // ConnectOption is used to configure how Waypoint server connection // configuration is sourced. type ConnectOption func(*connectConfig) error @@ -40,7 +45,7 @@ func Connect(ctx context.Context, opts ...ConnectOption) (*grpc.ClientConn, erro return nil, nil } - return nil, fmt.Errorf("no server credentials found") + return nil, ErrNoServerConfig } ctx, cancel := context.WithTimeout(ctx, cfg.Timeout) diff --git a/internal/version/version.go b/internal/version/version.go index 849175538e8..16eb325d14c 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -72,7 +72,7 @@ func (c *VersionInfo) FullVersionNumber(rev bool) string { return "Waypoint (version unknown)" } - fmt.Fprintf(&versionString, "Waypoint %s", c.Version) + fmt.Fprintf(&versionString, "%s", c.Version) if c.VersionPrerelease != "" && c.GitDescribe == "" { fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease) } From 2ed8fe493d4dec554257a1aaa3a4f79882795a1d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 20 Apr 2021 10:30:37 -0700 Subject: [PATCH 2/3] changelog --- .changelog/1364.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/1364.txt diff --git a/.changelog/1364.txt b/.changelog/1364.txt new file mode 100644 index 00000000000..bcbf20e4696 --- /dev/null +++ b/.changelog/1364.txt @@ -0,0 +1,3 @@ +```release-note:improvement +cli: version command now shoes the server version +``` From 7b60edb7f5e42298daf5ade91bbb9e0e040b9e8f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 20 Apr 2021 11:07:07 -0700 Subject: [PATCH 3/3] internal/cli: --version reroutes to `waypoint version` --- internal/cli/main.go | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/internal/cli/main.go b/internal/cli/main.go index 3708cbb726a..eb3d832e445 100644 --- a/internal/cli/main.go +++ b/internal/cli/main.go @@ -90,15 +90,29 @@ func Main(args []string) int { base, commands := Commands(ctx, log, logOutput) defer base.Close() - // Build the CLI - cli := &cli.CLI{ - Name: args[0], - Args: args[1:], - Version: vsn.FullVersionNumber(true), - Commands: commands, - Autocomplete: true, - AutocompleteNoDefaultFlags: true, - HelpFunc: GroupedHelpFunc(cli.BasicHelpFunc(cliName)), + // Build the CLI. We use a CLI factory function because to modify the + // args once you call a func on CLI you need to create a new CLI instance. + cliFactory := func() *cli.CLI { + return &cli.CLI{ + Name: args[0], + Args: args[1:], + Version: vsn.FullVersionNumber(true), + Commands: commands, + Autocomplete: true, + AutocompleteNoDefaultFlags: true, + HelpFunc: GroupedHelpFunc(cli.BasicHelpFunc(cliName)), + } + } + + // Copy the CLI to check if it is a version call. If so, we modify + // the args to just be the version subcommand. This ensures that + // --version behaves by calling `waypoint version` and we get consistent + // behavior. + cli := cliFactory() + if cli.IsVersion() { + // We need to reinit because you can't modify fields after calling funcs + cli = cliFactory() + cli.Args = []string{"version"} } // Run the CLI