Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cli-plugins/examples/helloworld/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
)

func main() {
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
ctx := context.Background()
plugin.Run(ctx, func(ctx context.Context, dockerCli command.Cli) *cobra.Command {
goodbye := &cobra.Command{
Use: "goodbye",
Short: "Say Goodbye instead of Hello",
Expand Down
8 changes: 4 additions & 4 deletions cli-plugins/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager
}

// Run is the top-level entry point to the CLI plugin framework. It should be called from your plugin's `main()` function.
func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
func Run(ctx context.Context, makeCmd func(context.Context, command.Cli) *cobra.Command, meta manager.Metadata) {
dockerCli, err := command.NewDockerCli()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}

plugin := makeCmd(dockerCli)
plugin := makeCmd(ctx, dockerCli)

if err := RunPlugin(dockerCli, plugin, meta); err != nil {
if sterr, ok := err.(cli.StatusError); ok {
Expand All @@ -92,7 +92,7 @@ func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
}

func withPluginClientConn(name string) command.CLIOption {
return command.WithInitializeClient(func(dockerCli *command.DockerCli) (client.APIClient, error) {
return command.WithInitializeClient(func(ctx context.Context, dockerCli *command.DockerCli) (client.APIClient, error) {
cmd := "docker"
if x := os.Getenv(manager.ReexecEnvvar); x != "" {
cmd = x
Expand All @@ -119,7 +119,7 @@ func withPluginClientConn(name string) command.CLIOption {
return nil, err
}

return client.NewClientWithOpts(client.WithDialContext(helper.Dialer))
return client.NewClientWithOpts(ctx, client.WithDialContext(helper.Dialer))
})
}

Expand Down
21 changes: 11 additions & 10 deletions cli/command/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,12 @@ func (cli *DockerCli) DefaultVersion() string {
// CurrentVersion returns the API version currently negotiated, or the default
// version otherwise.
func (cli *DockerCli) CurrentVersion() string {
ctx := context.TODO()
_ = cli.initialize()
if cli.client == nil {
return api.DefaultVersion
}
return cli.client.ClientVersion()
return cli.client.ClientVersion(ctx)
}

// Client returns the APIClient
Expand Down Expand Up @@ -203,10 +204,10 @@ func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.Registry
}

// WithInitializeClient is passed to DockerCli.Initialize by callers who wish to set a particular API Client for use by the CLI.
func WithInitializeClient(makeClient func(dockerCli *DockerCli) (client.APIClient, error)) CLIOption {
func WithInitializeClient(makeClient func(ctx context.Context, dockerCli *DockerCli) (client.APIClient, error)) CLIOption {
return func(dockerCli *DockerCli) error {
var err error
dockerCli.client, err = makeClient(dockerCli)
dockerCli.client, err = makeClient(dockerCli.baseCtx, dockerCli)
return err
}
}
Expand Down Expand Up @@ -245,7 +246,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption)
}

// NewAPIClientFromFlags creates a new APIClient from command line flags
func NewAPIClientFromFlags(opts *cliflags.ClientOptions, configFile *configfile.ConfigFile) (client.APIClient, error) {
func NewAPIClientFromFlags(ctx context.Context, opts *cliflags.ClientOptions, configFile *configfile.ConfigFile) (client.APIClient, error) {
if opts.Context != "" && len(opts.Hosts) > 0 {
return nil, errors.New("conflicting options: either specify --host or --context, not both")
}
Expand All @@ -261,10 +262,10 @@ func NewAPIClientFromFlags(opts *cliflags.ClientOptions, configFile *configfile.
if err != nil {
return nil, errors.Wrap(err, "unable to resolve docker endpoint")
}
return newAPIClientFromEndpoint(endpoint, configFile)
return newAPIClientFromEndpoint(ctx, endpoint, configFile)
}

func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigFile) (client.APIClient, error) {
func newAPIClientFromEndpoint(ctx context.Context, ep docker.Endpoint, configFile *configfile.ConfigFile) (client.APIClient, error) {
opts, err := ep.ClientOpts()
if err != nil {
return nil, err
Expand All @@ -273,7 +274,7 @@ func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigF
opts = append(opts, client.WithHTTPHeaders(configFile.HTTPHeaders))
}
opts = append(opts, client.WithUserAgent(UserAgent()))
return client.NewClientWithOpts(opts...)
return client.NewClientWithOpts(ctx, opts...)
}

func resolveDockerEndpoint(s store.Reader, contextName string) (docker.Endpoint, error) {
Expand Down Expand Up @@ -337,7 +338,7 @@ func (cli *DockerCli) initializeFromClient() {
cli.serverInfo = ServerInfo{HasExperimental: true}

if ping.APIVersion != "" {
cli.client.NegotiateAPIVersionPing(ping)
cli.client.NegotiateAPIVersionPing(cli.baseCtx, ping)
}
return
}
Expand All @@ -348,7 +349,7 @@ func (cli *DockerCli) initializeFromClient() {
BuildkitVersion: ping.BuilderVersion,
SwarmStatus: ping.SwarmStatus,
}
cli.client.NegotiateAPIVersionPing(ping)
cli.client.NegotiateAPIVersionPing(cli.baseCtx, ping)
}

// NotaryClient provides a Notary Repository to interact with signed metadata for an image
Expand Down Expand Up @@ -444,7 +445,7 @@ func (cli *DockerCli) initialize() error {
return
}
if cli.client == nil {
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile); cli.initErr != nil {
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.baseCtx, cli.dockerEndpoint, cli.configFile); cli.initErr != nil {
return
}
}
Expand Down
50 changes: 32 additions & 18 deletions cli/command/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ func TestNewAPIClientFromFlags(t *testing.T) {
if runtime.GOOS == "windows" {
host = "npipe://./"
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

opts := &flags.ClientOptions{Hosts: []string{host}}
apiClient, err := NewAPIClientFromFlags(opts, &configfile.ConfigFile{})
apiClient, err := NewAPIClientFromFlags(ctx, opts, &configfile.ConfigFile{})
assert.NilError(t, err)
assert.Equal(t, apiClient.DaemonHost(), host)
assert.Equal(t, apiClient.ClientVersion(), api.DefaultVersion)
assert.Equal(t, apiClient.DaemonHost(ctx), host)
assert.Equal(t, apiClient.ClientVersion(ctx), api.DefaultVersion)
}

func TestNewAPIClientFromFlagsForDefaultSchema(t *testing.T) {
Expand All @@ -44,11 +47,14 @@ func TestNewAPIClientFromFlagsForDefaultSchema(t *testing.T) {
if runtime.GOOS == "windows" {
slug = "tcp://127.0.0.1"
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

opts := &flags.ClientOptions{Hosts: []string{host}}
apiClient, err := NewAPIClientFromFlags(opts, &configfile.ConfigFile{})
apiClient, err := NewAPIClientFromFlags(ctx, opts, &configfile.ConfigFile{})
assert.NilError(t, err)
assert.Equal(t, apiClient.DaemonHost(), slug+host)
assert.Equal(t, apiClient.ClientVersion(), api.DefaultVersion)
assert.Equal(t, apiClient.DaemonHost(ctx), slug+host)
assert.Equal(t, apiClient.ClientVersion(ctx), api.DefaultVersion)
}

func TestNewAPIClientFromFlagsWithCustomHeaders(t *testing.T) {
Expand All @@ -69,10 +75,13 @@ func TestNewAPIClientFromFlagsWithCustomHeaders(t *testing.T) {
},
}

apiClient, err := NewAPIClientFromFlags(opts, configFile)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

apiClient, err := NewAPIClientFromFlags(ctx, opts, configFile)
assert.NilError(t, err)
assert.Equal(t, apiClient.DaemonHost(), host)
assert.Equal(t, apiClient.ClientVersion(), api.DefaultVersion)
assert.Equal(t, apiClient.DaemonHost(ctx), host)
assert.Equal(t, apiClient.ClientVersion(ctx), api.DefaultVersion)

// verify User-Agent is not appended to the configfile. see https://github.com/docker/cli/pull/2756
assert.DeepEqual(t, configFile.HTTPHeaders, map[string]string{"My-Header": "Custom-Value"})
Expand All @@ -90,12 +99,14 @@ func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
customVersion := "v3.3.3"
t.Setenv("DOCKER_API_VERSION", customVersion)
t.Setenv("DOCKER_HOST", ":2375")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

opts := &flags.ClientOptions{}
configFile := &configfile.ConfigFile{}
apiclient, err := NewAPIClientFromFlags(opts, configFile)
apiclient, err := NewAPIClientFromFlags(ctx, opts, configFile)
assert.NilError(t, err)
assert.Equal(t, apiclient.ClientVersion(), customVersion)
assert.Equal(t, apiclient.ClientVersion(ctx), customVersion)
}

type fakeClient struct {
Expand All @@ -109,11 +120,11 @@ func (c *fakeClient) Ping(_ context.Context) (types.Ping, error) {
return c.pingFunc()
}

func (c *fakeClient) ClientVersion() string {
func (c *fakeClient) ClientVersion(_ context.Context) string {
return c.version
}

func (c *fakeClient) NegotiateAPIVersionPing(types.Ping) {
func (c *fakeClient) NegotiateAPIVersionPing(_ context.Context, _ types.Ping) {
c.negotiated = true
}

Expand Down Expand Up @@ -176,10 +187,13 @@ func TestInitializeFromClientHangs(t *testing.T) {
l, err := net.Listen("unix", socket)
assert.NilError(t, err)

receiveReqCh := make(chan bool)
timeoutCtx, cancel := context.WithTimeout(context.Background(), time.Second)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

receiveReqCh := make(chan bool)
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Second)
defer timeoutCancel()

// Simulate a server that hangs on connections.
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
select {
Expand All @@ -194,7 +208,7 @@ func TestInitializeFromClientHangs(t *testing.T) {

opts := &flags.ClientOptions{Hosts: []string{fmt.Sprintf("unix://%s", socket)}}
configFile := &configfile.ConfigFile{}
apiClient, err := NewAPIClientFromFlags(opts, configFile)
apiClient, err := NewAPIClientFromFlags(ctx, opts, configFile)
assert.NilError(t, err)

initializedCh := make(chan bool)
Expand Down Expand Up @@ -302,8 +316,8 @@ func TestNewDockerCliAndOperators(t *testing.T) {
func TestInitializeShouldAlwaysCreateTheContextStore(t *testing.T) {
cli, err := NewDockerCli()
assert.NilError(t, err)
assert.NilError(t, cli.Initialize(flags.NewClientOptions(), WithInitializeClient(func(cli *DockerCli) (client.APIClient, error) {
return client.NewClientWithOpts()
assert.NilError(t, cli.Initialize(flags.NewClientOptions(), WithInitializeClient(func(ctx context.Context, cli *DockerCli) (client.APIClient, error) {
return client.NewClientWithOpts(ctx)
})))
assert.Check(t, cli.ContextStore() != nil)
}
2 changes: 1 addition & 1 deletion cli/command/container/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (f *fakeClient) ContainerLogs(_ context.Context, containerID string, option
return nil, nil
}

func (f *fakeClient) ClientVersion() string {
func (f *fakeClient) ClientVersion(_ context.Context) string {
return f.Version
}

Expand Down
6 changes: 3 additions & 3 deletions cli/command/container/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet,
reportError(dockerCli.Err(), "create", err.Error(), true)
return cli.StatusError{StatusCode: 125}
}
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(ctx), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
newEnv := []string{}
for k, v := range proxyConfig {
if v == nil {
Expand All @@ -100,7 +100,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet,
reportError(dockerCli.Err(), "create", err.Error(), true)
return cli.StatusError{StatusCode: 125}
}
if err = validateAPIVersion(containerCfg, dockerCli.Client().ClientVersion()); err != nil {
if err = validateAPIVersion(containerCfg, dockerCli.Client().ClientVersion(ctx)); err != nil {
reportError(dockerCli.Err(), "create", err.Error(), true)
return cli.StatusError{StatusCode: 125}
}
Expand Down Expand Up @@ -236,7 +236,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
// create. It will produce an error if you try to set a platform on older API
// versions, so check the API version here to maintain backwards
// compatibility for CLI users.
if options.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.41") {
if options.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(ctx), "1.41") {
p, err := platforms.Parse(options.platform)
if err != nil {
return "", errors.Wrap(err, "error parsing specified platform")
Expand Down
2 changes: 1 addition & 1 deletion cli/command/container/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func runRun(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet, ro
reportError(dockerCli.Err(), "run", err.Error(), true)
return cli.StatusError{StatusCode: 125}
}
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(ctx), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
newEnv := []string{}
for k, v := range proxyConfig {
if v == nil {
Expand Down
4 changes: 2 additions & 2 deletions cli/command/container/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func waitExitOrRemoved(ctx context.Context, apiClient client.APIClient, containe
// Older versions used the Events API, and even older versions did not
// support server-side removal. This legacyWaitExitOrRemoved method
// preserves that old behavior and any issues it may have.
if versions.LessThan(apiClient.ClientVersion(), "1.30") {
if versions.LessThan(apiClient.ClientVersion(ctx), "1.30") {
return legacyWaitExitOrRemoved(ctx, apiClient, containerID, waitRemove)
}

Expand Down Expand Up @@ -81,7 +81,7 @@ func legacyWaitExitOrRemoved(ctx context.Context, apiClient client.APIClient, co
}
if !waitRemove {
stopProcessing = true
} else if versions.LessThan(apiClient.ClientVersion(), "1.25") {
} else if versions.LessThan(apiClient.ClientVersion(ctx), "1.25") {
// If we are talking to an older daemon, `AutoRemove` is not supported.
// We need to fall back to the old behavior, which is client-side removal
go func() {
Expand Down
12 changes: 7 additions & 5 deletions cli/command/context/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package context

import (
"bytes"
"context"
"fmt"

"github.com/docker/cli/cli"
Expand Down Expand Up @@ -47,7 +48,8 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command {
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.Name = args[0]
return RunCreate(dockerCLI, opts)
ctx := cmd.Context()
return RunCreate(ctx, dockerCLI, opts)
},
Long: longCreateDescription(),
ValidArgsFunction: completion.NoComplete,
Expand All @@ -60,7 +62,7 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command {
}

// RunCreate creates a Docker context
func RunCreate(dockerCLI command.Cli, o *CreateOptions) error {
func RunCreate(ctx context.Context, dockerCLI command.Cli, o *CreateOptions) error {
s := dockerCLI.ContextStore()
err := checkContextNameForCreation(s, o.Name)
if err != nil {
Expand All @@ -72,7 +74,7 @@ func RunCreate(dockerCLI command.Cli, o *CreateOptions) error {
case o.From != "":
err = createFromExistingContext(s, o.From, o)
default:
err = createNewContext(s, o)
err = createNewContext(ctx, s, o)
}
if err == nil {
fmt.Fprintln(dockerCLI.Out(), o.Name)
Expand All @@ -81,11 +83,11 @@ func RunCreate(dockerCLI command.Cli, o *CreateOptions) error {
return err
}

func createNewContext(contextStore store.ReaderWriter, o *CreateOptions) error {
func createNewContext(ctx context.Context, contextStore store.ReaderWriter, o *CreateOptions) error {
if o.Docker == nil {
return errors.New("docker endpoint configuration is required")
}
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(contextStore, o.Docker)
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(ctx, contextStore, o.Docker)
if err != nil {
return errors.Wrap(err, "unable to create docker endpoint config")
}
Expand Down
Loading