github.com/getong/docker@v1.13.1/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 "time" 16 17 "github.com/docker/docker/pkg/integration" 18 "github.com/docker/docker/pkg/integration/checker" 19 "github.com/docker/go-units" 20 "github.com/go-check/check" 21 ) 22 23 func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) { 24 testRequires(c, cpuCfsQuota) 25 name := "testbuildresourceconstraints" 26 27 ctx, err := fakeContext(` 28 FROM hello-world:frozen 29 RUN ["/hello"] 30 `, map[string]string{}) 31 c.Assert(err, checker.IsNil) 32 33 _, _, err = dockerCmdInDir(c, ctx.Dir, "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", "-t", name, ".") 34 if err != nil { 35 c.Fatal(err) 36 } 37 38 out, _ := dockerCmd(c, "ps", "-lq") 39 cID := strings.TrimSpace(out) 40 41 type hostConfig struct { 42 Memory int64 43 MemorySwap int64 44 CpusetCpus string 45 CpusetMems string 46 CPUShares int64 47 CPUQuota int64 48 Ulimits []*units.Ulimit 49 } 50 51 cfg := inspectFieldJSON(c, cID, "HostConfig") 52 53 var c1 hostConfig 54 err = json.Unmarshal([]byte(cfg), &c1) 55 c.Assert(err, checker.IsNil, check.Commentf(cfg)) 56 57 c.Assert(c1.Memory, checker.Equals, int64(64*1024*1024), check.Commentf("resource constraints not set properly for Memory")) 58 c.Assert(c1.MemorySwap, checker.Equals, int64(-1), check.Commentf("resource constraints not set properly for MemorySwap")) 59 c.Assert(c1.CpusetCpus, checker.Equals, "0", check.Commentf("resource constraints not set properly for CpusetCpus")) 60 c.Assert(c1.CpusetMems, checker.Equals, "0", check.Commentf("resource constraints not set properly for CpusetMems")) 61 c.Assert(c1.CPUShares, checker.Equals, int64(100), check.Commentf("resource constraints not set properly for CPUShares")) 62 c.Assert(c1.CPUQuota, checker.Equals, int64(8000), check.Commentf("resource constraints not set properly for CPUQuota")) 63 c.Assert(c1.Ulimits[0].Name, checker.Equals, "nofile", check.Commentf("resource constraints not set properly for Ulimits")) 64 c.Assert(c1.Ulimits[0].Hard, checker.Equals, int64(42), check.Commentf("resource constraints not set properly for Ulimits")) 65 66 // Make sure constraints aren't saved to image 67 dockerCmd(c, "run", "--name=test", name) 68 69 cfg = inspectFieldJSON(c, "test", "HostConfig") 70 71 var c2 hostConfig 72 err = json.Unmarshal([]byte(cfg), &c2) 73 c.Assert(err, checker.IsNil, check.Commentf(cfg)) 74 75 c.Assert(c2.Memory, check.Not(checker.Equals), int64(64*1024*1024), check.Commentf("resource leaked from build for Memory")) 76 c.Assert(c2.MemorySwap, check.Not(checker.Equals), int64(-1), check.Commentf("resource leaked from build for MemorySwap")) 77 c.Assert(c2.CpusetCpus, check.Not(checker.Equals), "0", check.Commentf("resource leaked from build for CpusetCpus")) 78 c.Assert(c2.CpusetMems, check.Not(checker.Equals), "0", check.Commentf("resource leaked from build for CpusetMems")) 79 c.Assert(c2.CPUShares, check.Not(checker.Equals), int64(100), check.Commentf("resource leaked from build for CPUShares")) 80 c.Assert(c2.CPUQuota, check.Not(checker.Equals), int64(8000), check.Commentf("resource leaked from build for CPUQuota")) 81 c.Assert(c2.Ulimits, checker.IsNil, check.Commentf("resource leaked from build for Ulimits")) 82 } 83 84 func (s *DockerSuite) TestBuildAddChangeOwnership(c *check.C) { 85 testRequires(c, DaemonIsLinux) 86 name := "testbuildaddown" 87 88 ctx := func() *FakeContext { 89 dockerfile := ` 90 FROM busybox 91 ADD foo /bar/ 92 RUN [ $(stat -c %U:%G "/bar") = 'root:root' ] 93 RUN [ $(stat -c %U:%G "/bar/foo") = 'root:root' ] 94 ` 95 tmpDir, err := ioutil.TempDir("", "fake-context") 96 c.Assert(err, check.IsNil) 97 testFile, err := os.Create(filepath.Join(tmpDir, "foo")) 98 if err != nil { 99 c.Fatalf("failed to create foo file: %v", err) 100 } 101 defer testFile.Close() 102 103 chownCmd := exec.Command("chown", "daemon:daemon", "foo") 104 chownCmd.Dir = tmpDir 105 out, _, err := runCommandWithOutput(chownCmd) 106 if err != nil { 107 c.Fatal(err, out) 108 } 109 110 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 111 c.Fatalf("failed to open destination dockerfile: %v", err) 112 } 113 return fakeContextFromDir(tmpDir) 114 }() 115 116 defer ctx.Close() 117 118 if _, err := buildImageFromContext(name, ctx, true); err != nil { 119 c.Fatalf("build failed to complete for TestBuildAddChangeOwnership: %v", err) 120 } 121 } 122 123 // Test that an infinite sleep during a build is killed if the client disconnects. 124 // This test is fairly hairy because there are lots of ways to race. 125 // Strategy: 126 // * Monitor the output of docker events starting from before 127 // * Run a 1-year-long sleep from a docker build. 128 // * When docker events sees container start, close the "docker build" command 129 // * Wait for docker events to emit a dying event. 130 func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) { 131 testRequires(c, DaemonIsLinux) 132 name := "testbuildcancellation" 133 134 observer, err := newEventObserver(c) 135 c.Assert(err, checker.IsNil) 136 err = observer.Start() 137 c.Assert(err, checker.IsNil) 138 defer observer.Stop() 139 140 // (Note: one year, will never finish) 141 ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil) 142 if err != nil { 143 c.Fatal(err) 144 } 145 defer ctx.Close() 146 147 buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".") 148 buildCmd.Dir = ctx.Dir 149 150 stdoutBuild, err := buildCmd.StdoutPipe() 151 if err := buildCmd.Start(); err != nil { 152 c.Fatalf("failed to run build: %s", err) 153 } 154 155 matchCID := regexp.MustCompile("Running in (.+)") 156 scanner := bufio.NewScanner(stdoutBuild) 157 158 outputBuffer := new(bytes.Buffer) 159 var buildID string 160 for scanner.Scan() { 161 line := scanner.Text() 162 outputBuffer.WriteString(line) 163 outputBuffer.WriteString("\n") 164 if matches := matchCID.FindStringSubmatch(line); len(matches) > 0 { 165 buildID = matches[1] 166 break 167 } 168 } 169 170 if buildID == "" { 171 c.Fatalf("Unable to find build container id in build output:\n%s", outputBuffer.String()) 172 } 173 174 testActions := map[string]chan bool{ 175 "start": make(chan bool, 1), 176 "die": make(chan bool, 1), 177 } 178 179 matcher := matchEventLine(buildID, "container", testActions) 180 processor := processEventMatch(testActions) 181 go observer.Match(matcher, processor) 182 183 select { 184 case <-time.After(10 * time.Second): 185 observer.CheckEventError(c, buildID, "start", matcher) 186 case <-testActions["start"]: 187 // ignore, done 188 } 189 190 // Send a kill to the `docker build` command. 191 // Causes the underlying build to be cancelled due to socket close. 192 if err := buildCmd.Process.Kill(); err != nil { 193 c.Fatalf("error killing build command: %s", err) 194 } 195 196 // Get the exit status of `docker build`, check it exited because killed. 197 if err := buildCmd.Wait(); err != nil && !integration.IsKilled(err) { 198 c.Fatalf("wait failed during build run: %T %s", err, err) 199 } 200 201 select { 202 case <-time.After(10 * time.Second): 203 observer.CheckEventError(c, buildID, "die", matcher) 204 case <-testActions["die"]: 205 // ignore, done 206 } 207 }