Skip to content

Commit 2369935

Browse files
authored
Merge pull request docker#5645 from Benehiko/fix-run-ctx
2 parents 41fba28 + 30a73ff commit 2369935

File tree

4 files changed

+93
-9
lines changed

4 files changed

+93
-9
lines changed

cli/command/container/client_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type fakeClient struct {
2525
platform *specs.Platform,
2626
containerName string) (container.CreateResponse, error)
2727
containerStartFunc func(containerID string, options container.StartOptions) error
28-
imageCreateFunc func(parentReference string, options image.CreateOptions) (io.ReadCloser, error)
28+
imageCreateFunc func(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error)
2929
infoFunc func() (system.Info, error)
3030
containerStatPathFunc func(containerID, path string) (container.PathStat, error)
3131
containerCopyFromFunc func(containerID, srcPath string) (io.ReadCloser, container.PathStat, error)
@@ -100,9 +100,9 @@ func (f *fakeClient) ContainerRemove(ctx context.Context, containerID string, op
100100
return nil
101101
}
102102

103-
func (f *fakeClient) ImageCreate(_ context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
103+
func (f *fakeClient) ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
104104
if f.imageCreateFunc != nil {
105-
return f.imageCreateFunc(parentReference, options)
105+
return f.imageCreateFunc(ctx, parentReference, options)
106106
}
107107
return nil, nil
108108
}

cli/command/container/create_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
132132
return container.CreateResponse{ID: containerID}, nil
133133
}
134134
},
135-
imageCreateFunc: func(parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
135+
imageCreateFunc: func(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
136136
defer func() { pullCounter++ }()
137137
return io.NopCloser(strings.NewReader("")), nil
138138
},

cli/command/container/run.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,6 @@ func runRun(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet, ro
118118

119119
//nolint:gocyclo
120120
func runContainer(ctx context.Context, dockerCli command.Cli, runOpts *runOptions, copts *containerOptions, containerCfg *containerConfig) error {
121-
ctx = context.WithoutCancel(ctx)
122-
123121
config := containerCfg.Config
124122
stdout, stderr := dockerCli.Out(), dockerCli.Err()
125123
apiClient := dockerCli.Client()
@@ -141,9 +139,6 @@ func runContainer(ctx context.Context, dockerCli command.Cli, runOpts *runOption
141139
config.StdinOnce = false
142140
}
143141

144-
ctx, cancelFun := context.WithCancel(ctx)
145-
defer cancelFun()
146-
147142
containerID, err := createContainer(ctx, dockerCli, containerCfg, &runOpts.createOptions)
148143
if err != nil {
149144
return toStatusError(err)
@@ -159,6 +154,9 @@ func runContainer(ctx context.Context, dockerCli command.Cli, runOpts *runOption
159154
defer signal.StopCatch(sigc)
160155
}
161156

157+
ctx, cancelFun := context.WithCancel(context.WithoutCancel(ctx))
158+
defer cancelFun()
159+
162160
var (
163161
waitDisplayID chan struct{}
164162
errCh chan error

cli/command/container/run_test.go

+86
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package container
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
7+
"fmt"
68
"io"
79
"net"
810
"syscall"
@@ -16,7 +18,9 @@ import (
1618
"github.com/docker/cli/internal/test/notary"
1719
"github.com/docker/docker/api/types"
1820
"github.com/docker/docker/api/types/container"
21+
"github.com/docker/docker/api/types/image"
1922
"github.com/docker/docker/api/types/network"
23+
"github.com/docker/docker/pkg/jsonmessage"
2024
specs "github.com/opencontainers/image-spec/specs-go/v1"
2125
"github.com/spf13/pflag"
2226
"gotest.tools/v3/assert"
@@ -217,6 +221,88 @@ func TestRunAttachTermination(t *testing.T) {
217221
}
218222
}
219223

224+
func TestRunPullTermination(t *testing.T) {
225+
ctx, cancel := context.WithCancel(context.Background())
226+
t.Cleanup(cancel)
227+
228+
attachCh := make(chan struct{})
229+
fakeCLI := test.NewFakeCli(&fakeClient{
230+
createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig,
231+
platform *specs.Platform, containerName string,
232+
) (container.CreateResponse, error) {
233+
select {
234+
case <-ctx.Done():
235+
return container.CreateResponse{}, ctx.Err()
236+
default:
237+
}
238+
return container.CreateResponse{}, fakeNotFound{}
239+
},
240+
containerAttachFunc: func(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error) {
241+
return types.HijackedResponse{}, errors.New("shouldn't try to attach to a container")
242+
},
243+
imageCreateFunc: func(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
244+
server, client := net.Pipe()
245+
t.Cleanup(func() {
246+
_ = server.Close()
247+
})
248+
go func() {
249+
enc := json.NewEncoder(server)
250+
for i := 0; i < 100; i++ {
251+
select {
252+
case <-ctx.Done():
253+
assert.NilError(t, server.Close(), "failed to close imageCreateFunc server")
254+
return
255+
default:
256+
}
257+
assert.NilError(t, enc.Encode(jsonmessage.JSONMessage{
258+
Status: "Downloading",
259+
ID: fmt.Sprintf("id-%d", i),
260+
TimeNano: time.Now().UnixNano(),
261+
Time: time.Now().Unix(),
262+
Progress: &jsonmessage.JSONProgress{
263+
Current: int64(i),
264+
Total: 100,
265+
Start: 0,
266+
},
267+
}))
268+
time.Sleep(100 * time.Millisecond)
269+
}
270+
}()
271+
attachCh <- struct{}{}
272+
return client, nil
273+
},
274+
Version: "1.30",
275+
})
276+
277+
cmd := NewRunCommand(fakeCLI)
278+
cmd.SetOut(io.Discard)
279+
cmd.SetErr(io.Discard)
280+
cmd.SetArgs([]string{"foobar:latest"})
281+
282+
cmdErrC := make(chan error, 1)
283+
go func() {
284+
cmdErrC <- cmd.ExecuteContext(ctx)
285+
}()
286+
287+
select {
288+
case <-time.After(5 * time.Second):
289+
t.Fatal("imageCreateFunc was not called before the timeout")
290+
case <-attachCh:
291+
}
292+
293+
cancel()
294+
295+
select {
296+
case cmdErr := <-cmdErrC:
297+
assert.Equal(t, cmdErr, cli.StatusError{
298+
StatusCode: 125,
299+
Status: "docker: context canceled\n\nRun 'docker run --help' for more information",
300+
})
301+
case <-time.After(10 * time.Second):
302+
t.Fatal("cmd did not return before the timeout")
303+
}
304+
}
305+
220306
func TestRunCommandWithContentTrustErrors(t *testing.T) {
221307
testCases := []struct {
222308
name string

0 commit comments

Comments
 (0)