github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/integration-cli/docker_api_build_test.go (about)

     1  package main
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"github.com/go-check/check"
    10  )
    11  
    12  func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
    13  	// Test to make sure we stop people from trying to leave the
    14  	// build context when specifying the path to the dockerfile
    15  	buffer := new(bytes.Buffer)
    16  	tw := tar.NewWriter(buffer)
    17  	defer tw.Close()
    18  
    19  	dockerfile := []byte("FROM busybox")
    20  	if err := tw.WriteHeader(&tar.Header{
    21  		Name: "Dockerfile",
    22  		Size: int64(len(dockerfile)),
    23  	}); err != nil {
    24  		c.Fatalf("failed to write tar file header: %v", err)
    25  	}
    26  	if _, err := tw.Write(dockerfile); err != nil {
    27  		c.Fatalf("failed to write tar file content: %v", err)
    28  	}
    29  	if err := tw.Close(); err != nil {
    30  		c.Fatalf("failed to close tar archive: %v", err)
    31  	}
    32  
    33  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
    34  	c.Assert(err, check.IsNil)
    35  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
    36  
    37  	out, err := readBody(body)
    38  	if err != nil {
    39  		c.Fatal(err)
    40  	}
    41  
    42  	if !strings.Contains(string(out), "must be within the build context") {
    43  		c.Fatalf("Didn't complain about leaving build context: %s", out)
    44  	}
    45  }
    46  
    47  func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
    48  	server, err := fakeStorage(map[string]string{
    49  		"testD": `FROM busybox
    50  COPY * /tmp/
    51  RUN find / -name ba*
    52  RUN find /tmp/`,
    53  	})
    54  	if err != nil {
    55  		c.Fatal(err)
    56  	}
    57  	defer server.Close()
    58  
    59  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
    60  	c.Assert(err, check.IsNil)
    61  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
    62  
    63  	buf, err := readBody(body)
    64  	if err != nil {
    65  		c.Fatal(err)
    66  	}
    67  
    68  	// Make sure Dockerfile exists.
    69  	// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
    70  	out := string(buf)
    71  	if !strings.Contains(out, "/tmp/Dockerfile") ||
    72  		strings.Contains(out, "baz") {
    73  		c.Fatalf("Incorrect output: %s", out)
    74  	}
    75  }
    76  
    77  func (s *DockerSuite) TestBuildApiRemoteTarballContext(c *check.C) {
    78  	buffer := new(bytes.Buffer)
    79  	tw := tar.NewWriter(buffer)
    80  	defer tw.Close()
    81  
    82  	dockerfile := []byte("FROM busybox")
    83  	if err := tw.WriteHeader(&tar.Header{
    84  		Name: "Dockerfile",
    85  		Size: int64(len(dockerfile)),
    86  	}); err != nil {
    87  		c.Fatalf("failed to write tar file header: %v", err)
    88  	}
    89  	if _, err := tw.Write(dockerfile); err != nil {
    90  		c.Fatalf("failed to write tar file content: %v", err)
    91  	}
    92  	if err := tw.Close(); err != nil {
    93  		c.Fatalf("failed to close tar archive: %v", err)
    94  	}
    95  
    96  	server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
    97  		"testT.tar": buffer,
    98  	})
    99  	c.Assert(err, check.IsNil)
   100  
   101  	defer server.Close()
   102  
   103  	res, b, err := sockRequestRaw("POST", "/build?remote="+server.URL()+"/testT.tar", nil, "application/tar")
   104  	c.Assert(err, check.IsNil)
   105  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   106  	b.Close()
   107  }
   108  
   109  func (s *DockerSuite) TestBuildApiRemoteTarballContextWithCustomDockerfile(c *check.C) {
   110  	buffer := new(bytes.Buffer)
   111  	tw := tar.NewWriter(buffer)
   112  	defer tw.Close()
   113  
   114  	dockerfile := []byte(`FROM busybox
   115  RUN echo 'wrong'`)
   116  	if err := tw.WriteHeader(&tar.Header{
   117  		Name: "Dockerfile",
   118  		Size: int64(len(dockerfile)),
   119  	}); err != nil {
   120  		c.Fatalf("failed to write tar file header: %v", err)
   121  	}
   122  	if _, err := tw.Write(dockerfile); err != nil {
   123  		c.Fatalf("failed to write tar file content: %v", err)
   124  	}
   125  
   126  	custom := []byte(`FROM busybox
   127  RUN echo 'right'
   128  `)
   129  	if err := tw.WriteHeader(&tar.Header{
   130  		Name: "custom",
   131  		Size: int64(len(custom)),
   132  	}); err != nil {
   133  		c.Fatalf("failed to write tar file header: %v", err)
   134  	}
   135  	if _, err := tw.Write(custom); err != nil {
   136  		c.Fatalf("failed to write tar file content: %v", err)
   137  	}
   138  
   139  	if err := tw.Close(); err != nil {
   140  		c.Fatalf("failed to close tar archive: %v", err)
   141  	}
   142  
   143  	server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
   144  		"testT.tar": buffer,
   145  	})
   146  	c.Assert(err, check.IsNil)
   147  
   148  	defer server.Close()
   149  	url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
   150  	res, body, err := sockRequestRaw("POST", url, nil, "application/tar")
   151  	c.Assert(err, check.IsNil)
   152  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   153  
   154  	defer body.Close()
   155  	content, err := readBody(body)
   156  	c.Assert(err, check.IsNil)
   157  
   158  	if strings.Contains(string(content), "wrong") {
   159  		c.Fatalf("Build used the wrong dockerfile.")
   160  	}
   161  }
   162  
   163  func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
   164  	git, err := newFakeGit("repo", map[string]string{
   165  		"dockerfile": `FROM busybox
   166  RUN echo from dockerfile`,
   167  	}, false)
   168  	if err != nil {
   169  		c.Fatal(err)
   170  	}
   171  	defer git.Close()
   172  
   173  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   174  	c.Assert(err, check.IsNil)
   175  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   176  
   177  	buf, err := readBody(body)
   178  	if err != nil {
   179  		c.Fatal(err)
   180  	}
   181  
   182  	out := string(buf)
   183  	if !strings.Contains(out, "from dockerfile") {
   184  		c.Fatalf("Incorrect output: %s", out)
   185  	}
   186  }
   187  
   188  func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
   189  	git, err := newFakeGit("repo", map[string]string{
   190  		"baz": `FROM busybox
   191  RUN echo from baz`,
   192  		"Dockerfile": `FROM busybox
   193  RUN echo from Dockerfile`,
   194  	}, false)
   195  	if err != nil {
   196  		c.Fatal(err)
   197  	}
   198  	defer git.Close()
   199  
   200  	// Make sure it tries to 'dockerfile' query param value
   201  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
   202  	c.Assert(err, check.IsNil)
   203  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   204  
   205  	buf, err := readBody(body)
   206  	if err != nil {
   207  		c.Fatal(err)
   208  	}
   209  
   210  	out := string(buf)
   211  	if !strings.Contains(out, "from baz") {
   212  		c.Fatalf("Incorrect output: %s", out)
   213  	}
   214  }
   215  
   216  func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
   217  	testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
   218  	git, err := newFakeGit("repo", map[string]string{
   219  		"Dockerfile": `FROM busybox
   220  RUN echo from Dockerfile`,
   221  		"dockerfile": `FROM busybox
   222  RUN echo from dockerfile`,
   223  	}, false)
   224  	if err != nil {
   225  		c.Fatal(err)
   226  	}
   227  	defer git.Close()
   228  
   229  	// Make sure it tries to 'dockerfile' query param value
   230  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   231  	c.Assert(err, check.IsNil)
   232  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   233  
   234  	buf, err := readBody(body)
   235  	if err != nil {
   236  		c.Fatal(err)
   237  	}
   238  
   239  	out := string(buf)
   240  	if !strings.Contains(out, "from Dockerfile") {
   241  		c.Fatalf("Incorrect output: %s", out)
   242  	}
   243  }
   244  
   245  func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
   246  	// Test to make sure we stop people from trying to leave the
   247  	// build context when specifying a symlink as the path to the dockerfile
   248  	buffer := new(bytes.Buffer)
   249  	tw := tar.NewWriter(buffer)
   250  	defer tw.Close()
   251  
   252  	if err := tw.WriteHeader(&tar.Header{
   253  		Name:     "Dockerfile",
   254  		Typeflag: tar.TypeSymlink,
   255  		Linkname: "/etc/passwd",
   256  	}); err != nil {
   257  		c.Fatalf("failed to write tar file header: %v", err)
   258  	}
   259  	if err := tw.Close(); err != nil {
   260  		c.Fatalf("failed to close tar archive: %v", err)
   261  	}
   262  
   263  	res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
   264  	c.Assert(err, check.IsNil)
   265  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   266  
   267  	out, err := readBody(body)
   268  	if err != nil {
   269  		c.Fatal(err)
   270  	}
   271  
   272  	// The reason the error is "Cannot locate specified Dockerfile" is because
   273  	// in the builder, the symlink is resolved within the context, therefore
   274  	// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
   275  	// a nonexistent file.
   276  	if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") {
   277  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   278  	}
   279  }