github.com/resin-io/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  }