github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/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/internal/test/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  }