Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fa5dfbb

Browse files
Josh HawnArnaud Porterie
authored andcommitted
Fix premature close of build output on pull
The build job will sometimes trigger a pull job when the base image does not exist. Now that engine jobs properly close their output by default the pull job would also close the build job's stdout in a cascading close upon completion of the pull. This patch corrects this by wrapping the `pull` job's stdout with a nopCloseWriter which will not close the stdout of the `build` job. Docker-DCO-1.1-Signed-off-by: Josh Hawn <[email protected]> (github: jlhawn)
1 parent 6532a07 commit fa5dfbb

2 files changed

Lines changed: 86 additions & 1 deletion

File tree

builder/internals.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
imagepkg "github.com/docker/docker/image"
2626
"github.com/docker/docker/pkg/archive"
2727
"github.com/docker/docker/pkg/chrootarchive"
28+
"github.com/docker/docker/pkg/ioutils"
2829
"github.com/docker/docker/pkg/parsers"
2930
"github.com/docker/docker/pkg/symlink"
3031
"github.com/docker/docker/pkg/system"
@@ -433,7 +434,7 @@ func (b *Builder) pullImage(name string) (*imagepkg.Image, error) {
433434
job.SetenvBool("json", b.StreamFormatter.Json())
434435
job.SetenvBool("parallel", true)
435436
job.SetenvJson("authConfig", pullRegistryAuth)
436-
job.Stdout.Add(b.OutOld)
437+
job.Stdout.Add(ioutils.NopWriteCloser(b.OutOld))
437438
if err := job.Run(); err != nil {
438439
return nil, err
439440
}

engine/engine_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"bytes"
55
"strings"
66
"testing"
7+
8+
"github.com/docker/docker/pkg/ioutils"
79
)
810

911
func TestRegister(t *testing.T) {
@@ -150,3 +152,85 @@ func TestCatchallEmptyName(t *testing.T) {
150152
t.Fatalf("Engine.Job(\"\").Run() should return an error")
151153
}
152154
}
155+
156+
// Ensure that a job within a job both using the same underlying standard
157+
// output writer does not close the output of the outer job when the inner
158+
// job's stdout is wrapped with a NopCloser. When not wrapped, it should
159+
// close the outer job's output.
160+
func TestNestedJobSharedOutput(t *testing.T) {
161+
var (
162+
outerHandler Handler
163+
innerHandler Handler
164+
wrapOutput bool
165+
)
166+
167+
outerHandler = func(job *Job) Status {
168+
job.Stdout.Write([]byte("outer1"))
169+
170+
innerJob := job.Eng.Job("innerJob")
171+
172+
if wrapOutput {
173+
innerJob.Stdout.Add(ioutils.NopWriteCloser(job.Stdout))
174+
} else {
175+
innerJob.Stdout.Add(job.Stdout)
176+
}
177+
178+
if err := innerJob.Run(); err != nil {
179+
t.Fatal(err)
180+
}
181+
182+
// If wrapOutput was *false* this write will do nothing.
183+
// FIXME (jlhawn): It should cause an error to write to
184+
// closed output.
185+
job.Stdout.Write([]byte(" outer2"))
186+
187+
return StatusOK
188+
}
189+
190+
innerHandler = func(job *Job) Status {
191+
job.Stdout.Write([]byte(" inner"))
192+
193+
return StatusOK
194+
}
195+
196+
eng := New()
197+
eng.Register("outerJob", outerHandler)
198+
eng.Register("innerJob", innerHandler)
199+
200+
// wrapOutput starts *false* so the expected
201+
// output of running the outer job will be:
202+
//
203+
// "outer1 inner"
204+
//
205+
outBuf := new(bytes.Buffer)
206+
outerJob := eng.Job("outerJob")
207+
outerJob.Stdout.Add(outBuf)
208+
209+
if err := outerJob.Run(); err != nil {
210+
t.Fatal(err)
211+
}
212+
213+
expectedOutput := "outer1 inner"
214+
if outBuf.String() != expectedOutput {
215+
t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String())
216+
}
217+
218+
// Set wrapOutput to true so that the expected
219+
// output of running the outer job will be:
220+
//
221+
// "outer1 inner outer2"
222+
//
223+
wrapOutput = true
224+
outBuf.Reset()
225+
outerJob = eng.Job("outerJob")
226+
outerJob.Stdout.Add(outBuf)
227+
228+
if err := outerJob.Run(); err != nil {
229+
t.Fatal(err)
230+
}
231+
232+
expectedOutput = "outer1 inner outer2"
233+
if outBuf.String() != expectedOutput {
234+
t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String())
235+
}
236+
}

0 commit comments

Comments
 (0)