Skip to content

Commit

Permalink
Defer API version negociation
Browse files Browse the repository at this point in the history
This commit defers API version negociation within the dockerCli structure to the point where we need to access
server info or the API client itself. This also introduce a "no-remote"
annotation, to skip the evaluation of server-side support for those
commands (which requires access to server-info). The context subcommands
are marked with this "no-remote" annotation so that they respond quickly
even if the current context points to an unreachable endpoint.

Signed-off-by: Simon Ferquel <[email protected]>
  • Loading branch information
simonferquel committed Mar 18, 2019
1 parent 33c8c05 commit e87de89
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 18 deletions.
31 changes: 17 additions & 14 deletions cli/command/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"
"runtime"
"strconv"
"sync"

"github.com/docker/cli/cli/config"
cliconfig "github.com/docker/cli/cli/config"
Expand Down Expand Up @@ -70,19 +71,20 @@ type Cli interface {
// DockerCli is an instance the docker command line client.
// Instances of the client can be returned from NewDockerCli.
type DockerCli struct {
configFile *configfile.ConfigFile
in *streams.In
out *streams.Out
err io.Writer
client client.APIClient
serverInfo ServerInfo
clientInfo ClientInfo
contentTrust bool
newContainerizeClient func(string) (clitypes.ContainerizedClient, error)
contextStore store.Store
currentContext string
dockerEndpoint docker.Endpoint
contextStoreConfig store.Config
configFile *configfile.ConfigFile
in *streams.In
out *streams.Out
err io.Writer
client client.APIClient
serverInfo ServerInfo
clientInfo ClientInfo
contentTrust bool
newContainerizeClient func(string) (clitypes.ContainerizedClient, error)
contextStore store.Store
currentContext string
dockerEndpoint docker.Endpoint
contextStoreConfig store.Config
initializeFromClientOnce sync.Once
}

// DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified.
Expand All @@ -92,6 +94,7 @@ func (cli *DockerCli) DefaultVersion() string {

// Client returns the APIClient
func (cli *DockerCli) Client() client.APIClient {
cli.initializeFromClientOnce.Do(cli.initializeFromClient)
return cli.client
}

Expand Down Expand Up @@ -132,6 +135,7 @@ func (cli *DockerCli) ConfigFile() *configfile.ConfigFile {
// ServerInfo returns the server version details for the host this client is
// connected to
func (cli *DockerCli) ServerInfo() ServerInfo {
cli.initializeFromClientOnce.Do(cli.initializeFromClient)
return cli.serverInfo
}

Expand Down Expand Up @@ -247,7 +251,6 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...Initialize
DefaultVersion: cli.client.ClientVersion(),
HasExperimental: hasExperimental,
}
cli.initializeFromClient()
return nil
}

Expand Down
9 changes: 5 additions & 4 deletions cli/command/context/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import (
// NewContextCommand returns the context cli subcommand
func NewContextCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "context",
Short: "Manage contexts",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Use: "context",
Short: "Manage contexts",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"no-remote": ""},
}
cmd.AddCommand(
newCreateCommand(dockerCli),
Expand Down
14 changes: 14 additions & 0 deletions cmd/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ func findCommand(cmd *cobra.Command, commands []string) bool {
}

func isSupported(cmd *cobra.Command, details versionDetails) error {
if isNoRemote(cmd) {
return nil
}
if err := areSubcommandsSupported(cmd, details); err != nil {
return err
}
Expand Down Expand Up @@ -432,3 +435,14 @@ func hasTags(cmd *cobra.Command) bool {

return false
}

func isNoRemote(cmd *cobra.Command) bool {
for cmd != nil {
if _, ok := cmd.Annotations["no-remote"]; ok {
return true
}
cmd = cmd.Parent()
}

return false
}

0 comments on commit e87de89

Please sign in to comment.