github.com/shishir-a412ed/docker@v1.3.2-0.20180103180333-fda904911d87/integration-cli/docker_cli_build_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bufio" 7 "bytes" 8 "encoding/json" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "regexp" 14 "strings" 15 "syscall" 16 "time" 17 18 "github.com/docker/docker/integration-cli/checker" 19 "github.com/docker/docker/integration-cli/cli" 20 "github.com/docker/docker/integration-cli/cli/build" 21 "github.com/docker/docker/integration-cli/cli/build/fakecontext" 22 units "github.com/docker/go-units" 23 "github.com/go-check/check" 24 "github.com/gotestyourself/gotestyourself/icmd" 25 ) 26 27 func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) { 28 testRequires(c, cpuCfsQuota) 29 name := "testbuildresourceconstraints" 30 buildLabel := "DockerSuite.TestBuildResourceConstraintsAreUsed" 31 32 ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(` 33 FROM hello-world:frozen 34 RUN ["/hello"] 35 `)) 36 cli.Docker( 37 cli.Args("build", "--no-cache", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=0", "--cpuset-mems=0", "--cpu-shares=100", "--cpu-quota=8000", "--ulimit", "nofile=42", "--label="+buildLabel, "-t", name, "."), 38 cli.InDir(ctx.Dir), 39 ).Assert(c, icmd.Success) 40 41 out := cli.DockerCmd(c, "ps", "-lq", "--filter", "label="+buildLabel).Combined() 42 cID := strings.TrimSpace(out) 43 44 type hostConfig struct { 45 Memory int64 46 MemorySwap int64 47 CpusetCpus string 48 CpusetMems string 49 CPUShares int64 50 CPUQuota int64 51 Ulimits []*units.Ulimit 52 } 53 54 cfg := inspectFieldJSON(c, cID, "HostConfig") 55 56 var c1 hostConfig 57 err := json.Unmarshal([]byte(cfg), &c1) 58 c.Assert(err, checker.IsNil, check.Commentf(cfg)) 59 60 c.Assert(c1.Memory, checker.Equals, int64(64*1024*1024), check.Commentf("resource constraints not set properly for Memory")) 61 c.Assert(c1.MemorySwap, checker.Equals, int64(-1), check.Commentf("resource constraints not set properly for MemorySwap")) 62 c.Assert(c1.CpusetCpus, checker.Equals, "0", check.Commentf("resource constraints not set properly for CpusetCpus")) 63 c.Assert(c1.CpusetMems, checker.Equals, "0", check.Commentf("resource constraints not set properly for CpusetMems")) 64 c.Assert(c1.CPUShares, checker.Equals, int64(100), check.Commentf("resource constraints not set properly for CPUShares")) 65 c.Assert(c1.CPUQuota, checker.Equals, int64(8000), check.Commentf("resource constraints not set properly for CPUQuota")) 66 c.Assert(c1.Ulimits[0].Name, checker.Equals, "nofile", check.Commentf("resource constraints not set properly for Ulimits")) 67 c.Assert(c1.Ulimits[0].Hard, checker.Equals, int64(42), check.Commentf("resource constraints not set properly for Ulimits")) 68 69 // Make sure constraints aren't saved to image 70 cli.DockerCmd(c, "run", "--name=test", name) 71 72 cfg = inspectFieldJSON(c, "test", "HostConfig") 73 74 var c2 hostConfig 75 err = json.Unmarshal([]byte(cfg), &c2) 76 c.Assert(err, checker.IsNil, check.Commentf(cfg)) 77 78 c.Assert(c2.Memory, check.Not(checker.Equals), int64(64*1024*1024), check.Commentf("resource leaked from build for Memory")) 79 c.Assert(c2.MemorySwap, check.Not(checker.Equals), int64(-1), check.Commentf("resource leaked from build for MemorySwap")) 80 c.Assert(c2.CpusetCpus, check.Not(checker.Equals), "0", check.Commentf("resource leaked from build for CpusetCpus")) 81 c.Assert(c2.CpusetMems, check.Not(checker.Equals), "0", check.Commentf("resource leaked from build for CpusetMems")) 82 c.Assert(c2.CPUShares, check.Not(checker.Equals), int64(100), check.Commentf("resource leaked from build for CPUShares")) 83 c.Assert(c2.CPUQuota, check.Not(checker.Equals), int64(8000), check.Commentf("resource leaked from build for CPUQuota")) 84 c.Assert(c2.Ulimits, checker.IsNil, check.Commentf("resource leaked from build for Ulimits")) 85 } 86 87 func (s *DockerSuite) TestBuildAddChangeOwnership(c *check.C) { 88 testRequires(c, DaemonIsLinux) 89 name := "testbuildaddown" 90 91 ctx := func() *fakecontext.Fake { 92 dockerfile := ` 93 FROM busybox 94 ADD foo /bar/ 95 RUN [ $(stat -c %U:%G "/bar") = 'root:root' ] 96 RUN [ $(stat -c %U:%G "/bar/foo") = 'root:root' ] 97 ` 98 tmpDir, err := ioutil.TempDir("", "fake-context") 99 c.Assert(err, check.IsNil) 100 testFile, err := os.Create(filepath.Join(tmpDir, "foo")) 101 if err != nil { 102 c.Fatalf("failed to create foo file: %v", err) 103 } 104 defer testFile.Close() 105 106 icmd.RunCmd(icmd.Cmd{ 107 Command: []string{"chown", "daemon:daemon", "foo"}, 108 Dir: tmpDir, 109 }).Assert(c, icmd.Success) 110 111 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 112 c.Fatalf("failed to open destination dockerfile: %v", err) 113 } 114 return fakecontext.New(c, tmpDir) 115 }() 116 117 defer ctx.Close() 118 119 buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx)) 120 } 121 122 // Test that an infinite sleep during a build is killed if the client disconnects. 123 // This test is fairly hairy because there are lots of ways to race. 124 // Strategy: 125 // * Monitor the output of docker events starting from before 126 // * Run a 1-year-long sleep from a docker build. 127 // * When docker events sees container start, close the "docker build" command 128 // * Wait for docker events to emit a dying event. 129 func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) { 130 testRequires(c, DaemonIsLinux) 131 name := "testbuildcancellation" 132 133 observer, err := newEventObserver(c) 134 c.Assert(err, checker.IsNil) 135 err = observer.Start() 136 c.Assert(err, checker.IsNil) 137 defer observer.Stop() 138 139 // (Note: one year, will never finish) 140 ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM busybox\nRUN sleep 31536000")) 141 defer ctx.Close() 142 143 buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".") 144 buildCmd.Dir = ctx.Dir 145 146 stdoutBuild, err := buildCmd.StdoutPipe() 147 c.Assert(err, checker.IsNil) 148 149 if err := buildCmd.Start(); err != nil { 150 c.Fatalf("failed to run build: %s", err) 151 } 152 // always clean up 153 defer func() { 154 buildCmd.Process.Kill() 155 buildCmd.Wait() 156 }() 157 158 matchCID := regexp.MustCompile("Running in (.+)") 159 scanner := bufio.NewScanner(stdoutBuild) 160 161 outputBuffer := new(bytes.Buffer) 162 var buildID string 163 for scanner.Scan() { 164 line := scanner.Text() 165 outputBuffer.WriteString(line) 166 outputBuffer.WriteString("\n") 167 if matches := matchCID.FindStringSubmatch(line); len(matches) > 0 { 168 buildID = matches[1] 169 break 170 } 171 } 172 173 if buildID == "" { 174 c.Fatalf("Unable to find build container id in build output:\n%s", outputBuffer.String()) 175 } 176 177 testActions := map[string]chan bool{ 178 "start": make(chan bool, 1), 179 "die": make(chan bool, 1), 180 } 181 182 matcher := matchEventLine(buildID, "container", testActions) 183 processor := processEventMatch(testActions) 184 go observer.Match(matcher, processor) 185 186 select { 187 case <-time.After(10 * time.Second): 188 observer.CheckEventError(c, buildID, "start", matcher) 189 case <-testActions["start"]: 190 // ignore, done 191 } 192 193 // Send a kill to the `docker build` command. 194 // Causes the underlying build to be cancelled due to socket close. 195 if err := buildCmd.Process.Kill(); err != nil { 196 c.Fatalf("error killing build command: %s", err) 197 } 198 199 // Get the exit status of `docker build`, check it exited because killed. 200 if err := buildCmd.Wait(); err != nil && !isKilled(err) { 201 c.Fatalf("wait failed during build run: %T %s", err, err) 202 } 203 204 select { 205 case <-time.After(10 * time.Second): 206 observer.CheckEventError(c, buildID, "die", matcher) 207 case <-testActions["die"]: 208 // ignore, done 209 } 210 } 211 212 func isKilled(err error) bool { 213 if exitErr, ok := err.(*exec.ExitError); ok { 214 status, ok := exitErr.Sys().(syscall.WaitStatus) 215 if !ok { 216 return false 217 } 218 // status.ExitStatus() is required on Windows because it does not 219 // implement Signal() nor Signaled(). Just check it had a bad exit 220 // status could mean it was killed (and in tests we do kill) 221 return (status.Signaled() && status.Signal() == os.Kill) || status.ExitStatus() != 0 222 } 223 return false 224 }