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