Skip to content

Commit 7d723e2

Browse files
authored
Merge pull request #4337 from thaJeztah/dont_mutate_configfile
cli/command/container: don't mutate ConfigFile.DetachKeys
2 parents 8aee745 + 2331e4d commit 7d723e2

5 files changed

Lines changed: 94 additions & 89 deletions

File tree

cli/command/container/attach.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ func NewAttachCommand(dockerCli command.Cli) *cobra.Command {
7272

7373
func runAttach(dockerCli command.Cli, opts *attachOptions) error {
7474
ctx := context.Background()
75-
client := dockerCli.Client()
75+
apiClient := dockerCli.Client()
7676

7777
// request channel to wait for client
78-
resultC, errC := client.ContainerWait(ctx, opts.container, "")
78+
resultC, errC := apiClient.ContainerWait(ctx, opts.container, "")
7979

80-
c, err := inspectContainerAndCheckState(ctx, client, opts.container)
80+
c, err := inspectContainerAndCheckState(ctx, apiClient, opts.container)
8181
if err != nil {
8282
return err
8383
}
@@ -86,16 +86,17 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error {
8686
return err
8787
}
8888

89+
detachKeys := dockerCli.ConfigFile().DetachKeys
8990
if opts.detachKeys != "" {
90-
dockerCli.ConfigFile().DetachKeys = opts.detachKeys
91+
detachKeys = opts.detachKeys
9192
}
9293

9394
options := types.ContainerAttachOptions{
9495
Stream: true,
9596
Stdin: !opts.noStdin && c.Config.OpenStdin,
9697
Stdout: true,
9798
Stderr: true,
98-
DetachKeys: dockerCli.ConfigFile().DetachKeys,
99+
DetachKeys: detachKeys,
99100
}
100101

101102
var in io.ReadCloser
@@ -109,7 +110,7 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error {
109110
defer signal.StopCatch(sigc)
110111
}
111112

112-
resp, errAttach := client.ContainerAttach(ctx, opts.container, options)
113+
resp, errAttach := apiClient.ContainerAttach(ctx, opts.container, options)
113114
if errAttach != nil {
114115
return errAttach
115116
}
@@ -123,7 +124,7 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error {
123124
// the container and not exit.
124125
//
125126
// Recheck the container's state to avoid attach block.
126-
_, err = inspectContainerAndCheckState(ctx, client, opts.container)
127+
_, err = inspectContainerAndCheckState(ctx, apiClient, opts.container)
127128
if err != nil {
128129
return err
129130
}

cli/command/container/create.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptio
104104
reportError(dockerCli.Err(), "create", err.Error(), true)
105105
return cli.StatusError{StatusCode: 125}
106106
}
107-
response, err := createContainer(context.Background(), dockerCli, containerCfg, options)
107+
id, err := createContainer(context.Background(), dockerCli, containerCfg, options)
108108
if err != nil {
109109
return err
110110
}
111-
fmt.Fprintln(dockerCli.Out(), response.ID)
111+
_, _ = fmt.Fprintln(dockerCli.Out(), id)
112112
return nil
113113
}
114114

@@ -185,7 +185,7 @@ func newCIDFile(path string) (*cidFile, error) {
185185
}
186186

187187
//nolint:gocyclo
188-
func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *containerConfig, opts *createOptions) (*container.CreateResponse, error) {
188+
func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *containerConfig, opts *createOptions) (containerID string, err error) {
189189
config := containerCfg.Config
190190
hostConfig := containerCfg.HostConfig
191191
networkingConfig := containerCfg.NetworkingConfig
@@ -200,13 +200,13 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
200200

201201
containerIDFile, err := newCIDFile(hostConfig.ContainerIDFile)
202202
if err != nil {
203-
return nil, err
203+
return "", err
204204
}
205205
defer containerIDFile.Close()
206206

207207
ref, err := reference.ParseAnyReference(config.Image)
208208
if err != nil {
209-
return nil, err
209+
return "", err
210210
}
211211
if named, ok := ref.(reference.Named); ok {
212212
namedRef = reference.TagNameOnly(named)
@@ -215,7 +215,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
215215
var err error
216216
trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef)
217217
if err != nil {
218-
return nil, err
218+
return "", err
219219
}
220220
config.Image = reference.FamiliarString(trustedRef)
221221
}
@@ -239,14 +239,14 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
239239
if opts.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.41") {
240240
p, err := platforms.Parse(opts.platform)
241241
if err != nil {
242-
return nil, errors.Wrap(err, "error parsing specified platform")
242+
return "", errors.Wrap(err, "error parsing specified platform")
243243
}
244244
platform = &p
245245
}
246246

247247
if opts.pull == PullImageAlways {
248248
if err := pullAndTagImage(); err != nil {
249-
return nil, err
249+
return "", err
250250
}
251251
}
252252

@@ -262,24 +262,24 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
262262
}
263263

264264
if err := pullAndTagImage(); err != nil {
265-
return nil, err
265+
return "", err
266266
}
267267

268268
var retryErr error
269269
response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, opts.name)
270270
if retryErr != nil {
271-
return nil, retryErr
271+
return "", retryErr
272272
}
273273
} else {
274-
return nil, err
274+
return "", err
275275
}
276276
}
277277

278278
for _, w := range response.Warnings {
279-
fmt.Fprintf(dockerCli.Err(), "WARNING: %s\n", w)
279+
_, _ = fmt.Fprintf(dockerCli.Err(), "WARNING: %s\n", w)
280280
}
281281
err = containerIDFile.Write(response.ID)
282-
return &response, err
282+
return response.ID, err
283283
}
284284

285285
func warnOnOomKillDisable(hostConfig container.HostConfig, stderr io.Writer) {

cli/command/container/create_test.go

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@ func TestCIDFileCloseWithWrite(t *testing.T) {
7979
}
8080

8181
func TestCreateContainerImagePullPolicy(t *testing.T) {
82-
imageName := "does-not-exist-locally"
83-
containerID := "abcdef"
82+
const (
83+
imageName = "does-not-exist-locally"
84+
containerID = "abcdef"
85+
)
8486
config := &containerConfig{
8587
Config: &container.Config{
8688
Image: imageName,
@@ -91,69 +93,71 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
9193
cases := []struct {
9294
PullPolicy string
9395
ExpectedPulls int
94-
ExpectedBody container.CreateResponse
96+
ExpectedID string
9597
ExpectedErrMsg string
9698
ResponseCounter int
9799
}{
98100
{
99101
PullPolicy: PullImageMissing,
100102
ExpectedPulls: 1,
101-
ExpectedBody: container.CreateResponse{ID: containerID},
103+
ExpectedID: containerID,
102104
}, {
103105
PullPolicy: PullImageAlways,
104106
ExpectedPulls: 1,
105-
ExpectedBody: container.CreateResponse{ID: containerID},
107+
ExpectedID: containerID,
106108
ResponseCounter: 1, // This lets us return a container on the first pull
107109
}, {
108110
PullPolicy: PullImageNever,
109111
ExpectedPulls: 0,
110112
ExpectedErrMsg: "error fake not found",
111113
},
112114
}
113-
for _, c := range cases {
114-
c := c
115-
pullCounter := 0
115+
for _, tc := range cases {
116+
tc := tc
117+
t.Run(tc.PullPolicy, func(t *testing.T) {
118+
pullCounter := 0
116119

117-
client := &fakeClient{
118-
createContainerFunc: func(
119-
config *container.Config,
120-
hostConfig *container.HostConfig,
121-
networkingConfig *network.NetworkingConfig,
122-
platform *specs.Platform,
123-
containerName string,
124-
) (container.CreateResponse, error) {
125-
defer func() { c.ResponseCounter++ }()
126-
switch c.ResponseCounter {
127-
case 0:
128-
return container.CreateResponse{}, fakeNotFound{}
129-
default:
130-
return container.CreateResponse{ID: containerID}, nil
131-
}
132-
},
133-
imageCreateFunc: func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
134-
defer func() { pullCounter++ }()
135-
return io.NopCloser(strings.NewReader("")), nil
136-
},
137-
infoFunc: func() (types.Info, error) {
138-
return types.Info{IndexServerAddress: "https://indexserver.example.com"}, nil
139-
},
140-
}
141-
cli := test.NewFakeCli(client)
142-
body, err := createContainer(context.Background(), cli, config, &createOptions{
143-
name: "name",
144-
platform: runtime.GOOS,
145-
untrusted: true,
146-
pull: c.PullPolicy,
147-
})
120+
client := &fakeClient{
121+
createContainerFunc: func(
122+
config *container.Config,
123+
hostConfig *container.HostConfig,
124+
networkingConfig *network.NetworkingConfig,
125+
platform *specs.Platform,
126+
containerName string,
127+
) (container.CreateResponse, error) {
128+
defer func() { tc.ResponseCounter++ }()
129+
switch tc.ResponseCounter {
130+
case 0:
131+
return container.CreateResponse{}, fakeNotFound{}
132+
default:
133+
return container.CreateResponse{ID: containerID}, nil
134+
}
135+
},
136+
imageCreateFunc: func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
137+
defer func() { pullCounter++ }()
138+
return io.NopCloser(strings.NewReader("")), nil
139+
},
140+
infoFunc: func() (types.Info, error) {
141+
return types.Info{IndexServerAddress: "https://indexserver.example.com"}, nil
142+
},
143+
}
144+
fakeCLI := test.NewFakeCli(client)
145+
id, err := createContainer(context.Background(), fakeCLI, config, &createOptions{
146+
name: "name",
147+
platform: runtime.GOOS,
148+
untrusted: true,
149+
pull: tc.PullPolicy,
150+
})
148151

149-
if c.ExpectedErrMsg != "" {
150-
assert.ErrorContains(t, err, c.ExpectedErrMsg)
151-
} else {
152-
assert.NilError(t, err)
153-
assert.Check(t, is.DeepEqual(c.ExpectedBody, *body))
154-
}
152+
if tc.ExpectedErrMsg != "" {
153+
assert.Check(t, is.ErrorContains(err, tc.ExpectedErrMsg))
154+
} else {
155+
assert.Check(t, err)
156+
assert.Check(t, is.Equal(tc.ExpectedID, id))
157+
}
155158

156-
assert.Check(t, is.Equal(c.ExpectedPulls, pullCounter))
159+
assert.Check(t, is.Equal(tc.ExpectedPulls, pullCounter))
160+
})
157161
}
158162
}
159163

cli/command/container/run.go

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,14 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
144144
ctx, cancelFun := context.WithCancel(context.Background())
145145
defer cancelFun()
146146

147-
createResponse, err := createContainer(ctx, dockerCli, containerCfg, &opts.createOptions)
147+
containerID, err := createContainer(ctx, dockerCli, containerCfg, &opts.createOptions)
148148
if err != nil {
149149
reportError(stderr, "run", err.Error(), true)
150150
return runStartContainerErr(err)
151151
}
152152
if opts.sigProxy {
153153
sigc := notifyAllSignals()
154-
go ForwardAllSignals(ctx, dockerCli, createResponse.ID, sigc)
154+
go ForwardAllSignals(ctx, dockerCli, containerID, sigc)
155155
defer signal.StopCatch(sigc)
156156
}
157157

@@ -164,26 +164,33 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
164164
waitDisplayID = make(chan struct{})
165165
go func() {
166166
defer close(waitDisplayID)
167-
fmt.Fprintln(stdout, createResponse.ID)
167+
_, _ = fmt.Fprintln(stdout, containerID)
168168
}()
169169
}
170170
attach := config.AttachStdin || config.AttachStdout || config.AttachStderr
171171
if attach {
172+
detachKeys := dockerCli.ConfigFile().DetachKeys
172173
if opts.detachKeys != "" {
173-
dockerCli.ConfigFile().DetachKeys = opts.detachKeys
174+
detachKeys = opts.detachKeys
174175
}
175176

176-
closeFn, err := attachContainer(ctx, dockerCli, &errCh, config, createResponse.ID)
177+
closeFn, err := attachContainer(ctx, dockerCli, containerID, &errCh, config, types.ContainerAttachOptions{
178+
Stream: true,
179+
Stdin: config.AttachStdin,
180+
Stdout: config.AttachStdout,
181+
Stderr: config.AttachStderr,
182+
DetachKeys: detachKeys,
183+
})
177184
if err != nil {
178185
return err
179186
}
180187
defer closeFn()
181188
}
182189

183-
statusChan := waitExitOrRemoved(ctx, dockerCli, createResponse.ID, copts.autoRemove)
190+
statusChan := waitExitOrRemoved(ctx, dockerCli, containerID, copts.autoRemove)
184191

185192
// start the container
186-
if err := client.ContainerStart(ctx, createResponse.ID, types.ContainerStartOptions{}); err != nil {
193+
if err := client.ContainerStart(ctx, containerID, types.ContainerStartOptions{}); err != nil {
187194
// If we have hijackedIOStreamer, we should notify
188195
// hijackedIOStreamer we are going to exit and wait
189196
// to avoid the terminal are not restored.
@@ -201,8 +208,8 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
201208
}
202209

203210
if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && dockerCli.Out().IsTerminal() {
204-
if err := MonitorTtySize(ctx, dockerCli, createResponse.ID, false); err != nil {
205-
fmt.Fprintln(stderr, "Error monitoring TTY size:", err)
211+
if err := MonitorTtySize(ctx, dockerCli, containerID, false); err != nil {
212+
_, _ = fmt.Fprintln(stderr, "Error monitoring TTY size:", err)
206213
}
207214
}
208215

@@ -232,15 +239,7 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
232239
return nil
233240
}
234241

235-
func attachContainer(ctx context.Context, dockerCli command.Cli, errCh *chan error, config *container.Config, containerID string) (func(), error) {
236-
options := types.ContainerAttachOptions{
237-
Stream: true,
238-
Stdin: config.AttachStdin,
239-
Stdout: config.AttachStdout,
240-
Stderr: config.AttachStderr,
241-
DetachKeys: dockerCli.ConfigFile().DetachKeys,
242-
}
243-
242+
func attachContainer(ctx context.Context, dockerCli command.Cli, containerID string, errCh *chan error, config *container.Config, options types.ContainerAttachOptions) (func(), error) {
244243
resp, errAttach := dockerCli.Client().ContainerAttach(ctx, containerID, options)
245244
if errAttach != nil {
246245
return nil, errAttach
@@ -250,13 +249,13 @@ func attachContainer(ctx context.Context, dockerCli command.Cli, errCh *chan err
250249
out, cerr io.Writer
251250
in io.ReadCloser
252251
)
253-
if config.AttachStdin {
252+
if options.Stdin {
254253
in = dockerCli.In()
255254
}
256-
if config.AttachStdout {
255+
if options.Stdout {
257256
out = dockerCli.Out()
258257
}
259-
if config.AttachStderr {
258+
if options.Stderr {
260259
if config.Tty {
261260
cerr = dockerCli.Out()
262261
} else {

cli/command/container/start.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,17 @@ func RunStart(dockerCli command.Cli, opts *StartOptions) error {
9494
defer signal.StopCatch(sigc)
9595
}
9696

97+
detachKeys := dockerCli.ConfigFile().DetachKeys
9798
if opts.DetachKeys != "" {
98-
dockerCli.ConfigFile().DetachKeys = opts.DetachKeys
99+
detachKeys = opts.DetachKeys
99100
}
100101

101102
options := types.ContainerAttachOptions{
102103
Stream: true,
103104
Stdin: opts.OpenStdin && c.Config.OpenStdin,
104105
Stdout: true,
105106
Stderr: true,
106-
DetachKeys: dockerCli.ConfigFile().DetachKeys,
107+
DetachKeys: detachKeys,
107108
}
108109

109110
var in io.ReadCloser

0 commit comments

Comments
 (0)