github.com/slene/docker@v1.8.0-rc1/integration-cli/docker_api_containers_test.go (about)

     1  package main
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"encoding/json"
     7  	"io"
     8  	"net/http"
     9  	"net/http/httputil"
    10  	"os"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/docker/docker/api/types"
    16  	"github.com/docker/docker/pkg/stringid"
    17  	"github.com/docker/docker/runconfig"
    18  	"github.com/go-check/check"
    19  )
    20  
    21  func (s *DockerSuite) TestContainerApiGetAll(c *check.C) {
    22  	startCount, err := getContainerCount()
    23  	if err != nil {
    24  		c.Fatalf("Cannot query container count: %v", err)
    25  	}
    26  
    27  	name := "getall"
    28  	dockerCmd(c, "run", "--name", name, "busybox", "true")
    29  
    30  	status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
    31  	c.Assert(err, check.IsNil)
    32  	c.Assert(status, check.Equals, http.StatusOK)
    33  
    34  	var inspectJSON []struct {
    35  		Names []string
    36  	}
    37  	if err = json.Unmarshal(body, &inspectJSON); err != nil {
    38  		c.Fatalf("unable to unmarshal response body: %v", err)
    39  	}
    40  
    41  	if len(inspectJSON) != startCount+1 {
    42  		c.Fatalf("Expected %d container(s), %d found (started with: %d)", startCount+1, len(inspectJSON), startCount)
    43  	}
    44  
    45  	if actual := inspectJSON[0].Names[0]; actual != "/"+name {
    46  		c.Fatalf("Container Name mismatch. Expected: %q, received: %q\n", "/"+name, actual)
    47  	}
    48  }
    49  
    50  // regression test for empty json field being omitted #13691
    51  func (s *DockerSuite) TestContainerApiGetJSONNoFieldsOmitted(c *check.C) {
    52  	dockerCmd(c, "run", "busybox", "true")
    53  
    54  	status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
    55  	c.Assert(err, check.IsNil)
    56  	c.Assert(status, check.Equals, http.StatusOK)
    57  
    58  	// empty Labels field triggered this bug, make sense to check for everything
    59  	// cause even Ports for instance can trigger this bug
    60  	// better safe than sorry..
    61  	fields := []string{
    62  		"Id",
    63  		"Names",
    64  		"Image",
    65  		"Command",
    66  		"Created",
    67  		"Ports",
    68  		"Labels",
    69  		"Status",
    70  	}
    71  
    72  	// decoding into types.Container do not work since it eventually unmarshal
    73  	// and empty field to an empty go map, so we just check for a string
    74  	for _, f := range fields {
    75  		if !strings.Contains(string(body), f) {
    76  			c.Fatalf("Field %s is missing and it shouldn't", f)
    77  		}
    78  	}
    79  }
    80  
    81  type containerPs struct {
    82  	Names []string
    83  	Ports []map[string]interface{}
    84  }
    85  
    86  // regression test for non-empty fields from #13901
    87  func (s *DockerSuite) TestContainerPsOmitFields(c *check.C) {
    88  	name := "pstest"
    89  	port := 80
    90  	dockerCmd(c, "run", "-d", "--name", name, "--expose", strconv.Itoa(port), "busybox", "top")
    91  
    92  	status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
    93  	c.Assert(err, check.IsNil)
    94  	c.Assert(status, check.Equals, http.StatusOK)
    95  
    96  	var resp []containerPs
    97  	err = json.Unmarshal(body, &resp)
    98  	c.Assert(err, check.IsNil)
    99  
   100  	var foundContainer *containerPs
   101  	for _, container := range resp {
   102  		for _, testName := range container.Names {
   103  			if "/"+name == testName {
   104  				foundContainer = &container
   105  				break
   106  			}
   107  		}
   108  	}
   109  
   110  	c.Assert(len(foundContainer.Ports), check.Equals, 1)
   111  	c.Assert(foundContainer.Ports[0]["PrivatePort"], check.Equals, float64(port))
   112  	_, ok := foundContainer.Ports[0]["PublicPort"]
   113  	c.Assert(ok, check.Not(check.Equals), true)
   114  	_, ok = foundContainer.Ports[0]["IP"]
   115  	c.Assert(ok, check.Not(check.Equals), true)
   116  }
   117  
   118  func (s *DockerSuite) TestContainerApiGetExport(c *check.C) {
   119  	name := "exportcontainer"
   120  	dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test")
   121  
   122  	status, body, err := sockRequest("GET", "/containers/"+name+"/export", nil)
   123  	c.Assert(err, check.IsNil)
   124  	c.Assert(status, check.Equals, http.StatusOK)
   125  
   126  	found := false
   127  	for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
   128  		h, err := tarReader.Next()
   129  		if err != nil {
   130  			if err == io.EOF {
   131  				break
   132  			}
   133  			c.Fatal(err)
   134  		}
   135  		if h.Name == "test" {
   136  			found = true
   137  			break
   138  		}
   139  	}
   140  
   141  	if !found {
   142  		c.Fatalf("The created test file has not been found in the exported image")
   143  	}
   144  }
   145  
   146  func (s *DockerSuite) TestContainerApiGetChanges(c *check.C) {
   147  	name := "changescontainer"
   148  	dockerCmd(c, "run", "--name", name, "busybox", "rm", "/etc/passwd")
   149  
   150  	status, body, err := sockRequest("GET", "/containers/"+name+"/changes", nil)
   151  	c.Assert(err, check.IsNil)
   152  	c.Assert(status, check.Equals, http.StatusOK)
   153  
   154  	changes := []struct {
   155  		Kind int
   156  		Path string
   157  	}{}
   158  	if err = json.Unmarshal(body, &changes); err != nil {
   159  		c.Fatalf("unable to unmarshal response body: %v", err)
   160  	}
   161  
   162  	// Check the changelog for removal of /etc/passwd
   163  	success := false
   164  	for _, elem := range changes {
   165  		if elem.Path == "/etc/passwd" && elem.Kind == 2 {
   166  			success = true
   167  		}
   168  	}
   169  	if !success {
   170  		c.Fatalf("/etc/passwd has been removed but is not present in the diff")
   171  	}
   172  }
   173  
   174  func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) {
   175  	name := "testing"
   176  	config := map[string]interface{}{
   177  		"Image":   "busybox",
   178  		"Volumes": map[string]struct{}{"/tmp": {}},
   179  	}
   180  
   181  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   182  	c.Assert(err, check.IsNil)
   183  	c.Assert(status, check.Equals, http.StatusCreated)
   184  
   185  	bindPath := randomUnixTmpDirPath("test")
   186  	config = map[string]interface{}{
   187  		"Binds": []string{bindPath + ":/tmp"},
   188  	}
   189  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   190  	c.Assert(err, check.IsNil)
   191  	c.Assert(status, check.Equals, http.StatusNoContent)
   192  
   193  	pth, err := inspectMountSourceField(name, "/tmp")
   194  	if err != nil {
   195  		c.Fatal(err)
   196  	}
   197  
   198  	if pth != bindPath {
   199  		c.Fatalf("expected volume host path to be %s, got %s", bindPath, pth)
   200  	}
   201  }
   202  
   203  // Test for GH#10618
   204  func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) {
   205  	name := "testdups"
   206  	config := map[string]interface{}{
   207  		"Image":   "busybox",
   208  		"Volumes": map[string]struct{}{"/tmp": {}},
   209  	}
   210  
   211  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   212  	c.Assert(err, check.IsNil)
   213  	c.Assert(status, check.Equals, http.StatusCreated)
   214  
   215  	bindPath1 := randomUnixTmpDirPath("test1")
   216  	bindPath2 := randomUnixTmpDirPath("test2")
   217  
   218  	config = map[string]interface{}{
   219  		"Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"},
   220  	}
   221  	status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
   222  	c.Assert(err, check.IsNil)
   223  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   224  
   225  	if !strings.Contains(string(body), "Duplicate bind") {
   226  		c.Fatalf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err)
   227  	}
   228  }
   229  
   230  func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
   231  	volName := "voltst"
   232  	volPath := "/tmp"
   233  
   234  	dockerCmd(c, "run", "-d", "--name", volName, "-v", volPath, "busybox")
   235  
   236  	name := "TestContainerApiStartVolumesFrom"
   237  	config := map[string]interface{}{
   238  		"Image":   "busybox",
   239  		"Volumes": map[string]struct{}{volPath: {}},
   240  	}
   241  
   242  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   243  	c.Assert(err, check.IsNil)
   244  	c.Assert(status, check.Equals, http.StatusCreated)
   245  
   246  	config = map[string]interface{}{
   247  		"VolumesFrom": []string{volName},
   248  	}
   249  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   250  	c.Assert(err, check.IsNil)
   251  	c.Assert(status, check.Equals, http.StatusNoContent)
   252  
   253  	pth, err := inspectMountSourceField(name, volPath)
   254  	if err != nil {
   255  		c.Fatal(err)
   256  	}
   257  	pth2, err := inspectMountSourceField(volName, volPath)
   258  	if err != nil {
   259  		c.Fatal(err)
   260  	}
   261  
   262  	if pth != pth2 {
   263  		c.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
   264  	}
   265  }
   266  
   267  func (s *DockerSuite) TestGetContainerStats(c *check.C) {
   268  	var (
   269  		name = "statscontainer"
   270  	)
   271  	dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
   272  
   273  	type b struct {
   274  		status int
   275  		body   []byte
   276  		err    error
   277  	}
   278  	bc := make(chan b, 1)
   279  	go func() {
   280  		status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
   281  		bc <- b{status, body, err}
   282  	}()
   283  
   284  	// allow some time to stream the stats from the container
   285  	time.Sleep(4 * time.Second)
   286  	dockerCmd(c, "rm", "-f", name)
   287  
   288  	// collect the results from the stats stream or timeout and fail
   289  	// if the stream was not disconnected.
   290  	select {
   291  	case <-time.After(2 * time.Second):
   292  		c.Fatal("stream was not closed after container was removed")
   293  	case sr := <-bc:
   294  		c.Assert(sr.err, check.IsNil)
   295  		c.Assert(sr.status, check.Equals, http.StatusOK)
   296  
   297  		dec := json.NewDecoder(bytes.NewBuffer(sr.body))
   298  		var s *types.Stats
   299  		// decode only one object from the stream
   300  		if err := dec.Decode(&s); err != nil {
   301  			c.Fatal(err)
   302  		}
   303  	}
   304  }
   305  
   306  func (s *DockerSuite) TestGetContainerStatsRmRunning(c *check.C) {
   307  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
   308  	id := strings.TrimSpace(out)
   309  
   310  	buf := &channelBuffer{make(chan []byte, 1)}
   311  	defer buf.Close()
   312  	chErr := make(chan error)
   313  	go func() {
   314  		_, body, err := sockRequestRaw("GET", "/containers/"+id+"/stats?stream=1", nil, "application/json")
   315  		if err != nil {
   316  			chErr <- err
   317  		}
   318  		defer body.Close()
   319  		_, err = io.Copy(buf, body)
   320  		chErr <- err
   321  	}()
   322  	defer func() {
   323  		c.Assert(<-chErr, check.IsNil)
   324  	}()
   325  
   326  	b := make([]byte, 32)
   327  	// make sure we've got some stats
   328  	_, err := buf.ReadTimeout(b, 2*time.Second)
   329  	c.Assert(err, check.IsNil)
   330  
   331  	// Now remove without `-f` and make sure we are still pulling stats
   332  	_, _, err = dockerCmdWithError(c, "rm", id)
   333  	c.Assert(err, check.Not(check.IsNil), check.Commentf("rm should have failed but didn't"))
   334  	_, err = buf.ReadTimeout(b, 2*time.Second)
   335  	c.Assert(err, check.IsNil)
   336  	dockerCmd(c, "rm", "-f", id)
   337  
   338  	_, err = buf.ReadTimeout(b, 2*time.Second)
   339  	c.Assert(err, check.Not(check.IsNil))
   340  }
   341  
   342  // regression test for gh13421
   343  // previous test was just checking one stat entry so it didn't fail (stats with
   344  // stream false always return one stat)
   345  func (s *DockerSuite) TestGetContainerStatsStream(c *check.C) {
   346  	name := "statscontainer"
   347  	dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
   348  
   349  	type b struct {
   350  		status int
   351  		body   []byte
   352  		err    error
   353  	}
   354  	bc := make(chan b, 1)
   355  	go func() {
   356  		status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
   357  		bc <- b{status, body, err}
   358  	}()
   359  
   360  	// allow some time to stream the stats from the container
   361  	time.Sleep(4 * time.Second)
   362  	dockerCmd(c, "rm", "-f", name)
   363  
   364  	// collect the results from the stats stream or timeout and fail
   365  	// if the stream was not disconnected.
   366  	select {
   367  	case <-time.After(2 * time.Second):
   368  		c.Fatal("stream was not closed after container was removed")
   369  	case sr := <-bc:
   370  		c.Assert(sr.err, check.IsNil)
   371  		c.Assert(sr.status, check.Equals, http.StatusOK)
   372  
   373  		s := string(sr.body)
   374  		// count occurrences of "read" of types.Stats
   375  		if l := strings.Count(s, "read"); l < 2 {
   376  			c.Fatalf("Expected more than one stat streamed, got %d", l)
   377  		}
   378  	}
   379  }
   380  
   381  func (s *DockerSuite) TestGetContainerStatsNoStream(c *check.C) {
   382  	name := "statscontainer"
   383  	dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
   384  
   385  	type b struct {
   386  		status int
   387  		body   []byte
   388  		err    error
   389  	}
   390  	bc := make(chan b, 1)
   391  	go func() {
   392  		status, body, err := sockRequest("GET", "/containers/"+name+"/stats?stream=0", nil)
   393  		bc <- b{status, body, err}
   394  	}()
   395  
   396  	// allow some time to stream the stats from the container
   397  	time.Sleep(4 * time.Second)
   398  	dockerCmd(c, "rm", "-f", name)
   399  
   400  	// collect the results from the stats stream or timeout and fail
   401  	// if the stream was not disconnected.
   402  	select {
   403  	case <-time.After(2 * time.Second):
   404  		c.Fatal("stream was not closed after container was removed")
   405  	case sr := <-bc:
   406  		c.Assert(sr.err, check.IsNil)
   407  		c.Assert(sr.status, check.Equals, http.StatusOK)
   408  
   409  		s := string(sr.body)
   410  		// count occurrences of "read" of types.Stats
   411  		if l := strings.Count(s, "read"); l != 1 {
   412  			c.Fatalf("Expected only one stat streamed, got %d", l)
   413  		}
   414  	}
   415  }
   416  
   417  func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
   418  	// TODO: this test does nothing because we are c.Assert'ing in goroutine
   419  	var (
   420  		name = "statscontainer"
   421  	)
   422  	dockerCmd(c, "create", "--name", name, "busybox", "top")
   423  
   424  	go func() {
   425  		// We'll never get return for GET stats from sockRequest as of now,
   426  		// just send request and see if panic or error would happen on daemon side.
   427  		status, _, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
   428  		c.Assert(err, check.IsNil)
   429  		c.Assert(status, check.Equals, http.StatusOK)
   430  	}()
   431  
   432  	// allow some time to send request and let daemon deal with it
   433  	time.Sleep(1 * time.Second)
   434  }
   435  
   436  func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
   437  	// Test to make sure we stop people from trying to leave the
   438  	// build context when specifying the path to the dockerfile
   439  	buffer := new(bytes.Buffer)
   440  	tw := tar.NewWriter(buffer)
   441  	defer tw.Close()
   442  
   443  	dockerfile := []byte("FROM busybox")
   444  	if err := tw.WriteHeader(&tar.Header{
   445  		Name: "Dockerfile",
   446  		Size: int64(len(dockerfile)),
   447  	}); err != nil {
   448  		c.Fatalf("failed to write tar file header: %v", err)
   449  	}
   450  	if _, err := tw.Write(dockerfile); err != nil {
   451  		c.Fatalf("failed to write tar file content: %v", err)
   452  	}
   453  	if err := tw.Close(); err != nil {
   454  		c.Fatalf("failed to close tar archive: %v", err)
   455  	}
   456  
   457  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
   458  	c.Assert(err, check.IsNil)
   459  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   460  
   461  	out, err := readBody(body)
   462  	if err != nil {
   463  		c.Fatal(err)
   464  	}
   465  
   466  	if !strings.Contains(string(out), "must be within the build context") {
   467  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   468  	}
   469  }
   470  
   471  func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
   472  	server, err := fakeStorage(map[string]string{
   473  		"testD": `FROM busybox
   474  COPY * /tmp/
   475  RUN find / -name ba*
   476  RUN find /tmp/`,
   477  	})
   478  	if err != nil {
   479  		c.Fatal(err)
   480  	}
   481  	defer server.Close()
   482  
   483  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
   484  	c.Assert(err, check.IsNil)
   485  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   486  
   487  	buf, err := readBody(body)
   488  	if err != nil {
   489  		c.Fatal(err)
   490  	}
   491  
   492  	// Make sure Dockerfile exists.
   493  	// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
   494  	out := string(buf)
   495  	if !strings.Contains(out, "/tmp/Dockerfile") ||
   496  		strings.Contains(out, "baz") {
   497  		c.Fatalf("Incorrect output: %s", out)
   498  	}
   499  }
   500  
   501  func (s *DockerSuite) TestBuildApiRemoteTarballContext(c *check.C) {
   502  	buffer := new(bytes.Buffer)
   503  	tw := tar.NewWriter(buffer)
   504  	defer tw.Close()
   505  
   506  	dockerfile := []byte("FROM busybox")
   507  	if err := tw.WriteHeader(&tar.Header{
   508  		Name: "Dockerfile",
   509  		Size: int64(len(dockerfile)),
   510  	}); err != nil {
   511  		c.Fatalf("failed to write tar file header: %v", err)
   512  	}
   513  	if _, err := tw.Write(dockerfile); err != nil {
   514  		c.Fatalf("failed to write tar file content: %v", err)
   515  	}
   516  	if err := tw.Close(); err != nil {
   517  		c.Fatalf("failed to close tar archive: %v", err)
   518  	}
   519  
   520  	server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
   521  		"testT.tar": buffer,
   522  	})
   523  	c.Assert(err, check.IsNil)
   524  
   525  	defer server.Close()
   526  
   527  	res, b, err := sockRequestRaw("POST", "/build?remote="+server.URL()+"/testT.tar", nil, "application/tar")
   528  	c.Assert(err, check.IsNil)
   529  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   530  	b.Close()
   531  }
   532  
   533  func (s *DockerSuite) TestBuildApiRemoteTarballContextWithCustomDockerfile(c *check.C) {
   534  	buffer := new(bytes.Buffer)
   535  	tw := tar.NewWriter(buffer)
   536  	defer tw.Close()
   537  
   538  	dockerfile := []byte(`FROM busybox
   539  RUN echo 'wrong'`)
   540  	if err := tw.WriteHeader(&tar.Header{
   541  		Name: "Dockerfile",
   542  		Size: int64(len(dockerfile)),
   543  	}); err != nil {
   544  		c.Fatalf("failed to write tar file header: %v", err)
   545  	}
   546  	if _, err := tw.Write(dockerfile); err != nil {
   547  		c.Fatalf("failed to write tar file content: %v", err)
   548  	}
   549  
   550  	custom := []byte(`FROM busybox
   551  RUN echo 'right'
   552  `)
   553  	if err := tw.WriteHeader(&tar.Header{
   554  		Name: "custom",
   555  		Size: int64(len(custom)),
   556  	}); err != nil {
   557  		c.Fatalf("failed to write tar file header: %v", err)
   558  	}
   559  	if _, err := tw.Write(custom); err != nil {
   560  		c.Fatalf("failed to write tar file content: %v", err)
   561  	}
   562  
   563  	if err := tw.Close(); err != nil {
   564  		c.Fatalf("failed to close tar archive: %v", err)
   565  	}
   566  
   567  	server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
   568  		"testT.tar": buffer,
   569  	})
   570  	c.Assert(err, check.IsNil)
   571  
   572  	defer server.Close()
   573  	url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
   574  	res, body, err := sockRequestRaw("POST", url, nil, "application/tar")
   575  	c.Assert(err, check.IsNil)
   576  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   577  
   578  	defer body.Close()
   579  	content, err := readBody(body)
   580  	c.Assert(err, check.IsNil)
   581  
   582  	if strings.Contains(string(content), "wrong") {
   583  		c.Fatalf("Build used the wrong dockerfile.")
   584  	}
   585  }
   586  
   587  func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
   588  	git, err := newFakeGit("repo", map[string]string{
   589  		"dockerfile": `FROM busybox
   590  RUN echo from dockerfile`,
   591  	}, false)
   592  	if err != nil {
   593  		c.Fatal(err)
   594  	}
   595  	defer git.Close()
   596  
   597  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   598  	c.Assert(err, check.IsNil)
   599  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   600  
   601  	buf, err := readBody(body)
   602  	if err != nil {
   603  		c.Fatal(err)
   604  	}
   605  
   606  	out := string(buf)
   607  	if !strings.Contains(out, "from dockerfile") {
   608  		c.Fatalf("Incorrect output: %s", out)
   609  	}
   610  }
   611  
   612  func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
   613  	git, err := newFakeGit("repo", map[string]string{
   614  		"baz": `FROM busybox
   615  RUN echo from baz`,
   616  		"Dockerfile": `FROM busybox
   617  RUN echo from Dockerfile`,
   618  	}, false)
   619  	if err != nil {
   620  		c.Fatal(err)
   621  	}
   622  	defer git.Close()
   623  
   624  	// Make sure it tries to 'dockerfile' query param value
   625  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
   626  	c.Assert(err, check.IsNil)
   627  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   628  
   629  	buf, err := readBody(body)
   630  	if err != nil {
   631  		c.Fatal(err)
   632  	}
   633  
   634  	out := string(buf)
   635  	if !strings.Contains(out, "from baz") {
   636  		c.Fatalf("Incorrect output: %s", out)
   637  	}
   638  }
   639  
   640  func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
   641  	testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
   642  	git, err := newFakeGit("repo", map[string]string{
   643  		"Dockerfile": `FROM busybox
   644  RUN echo from Dockerfile`,
   645  		"dockerfile": `FROM busybox
   646  RUN echo from dockerfile`,
   647  	}, false)
   648  	if err != nil {
   649  		c.Fatal(err)
   650  	}
   651  	defer git.Close()
   652  
   653  	// Make sure it tries to 'dockerfile' query param value
   654  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   655  	c.Assert(err, check.IsNil)
   656  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   657  
   658  	buf, err := readBody(body)
   659  	if err != nil {
   660  		c.Fatal(err)
   661  	}
   662  
   663  	out := string(buf)
   664  	if !strings.Contains(out, "from Dockerfile") {
   665  		c.Fatalf("Incorrect output: %s", out)
   666  	}
   667  }
   668  
   669  func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
   670  	// Test to make sure we stop people from trying to leave the
   671  	// build context when specifying a symlink as the path to the dockerfile
   672  	buffer := new(bytes.Buffer)
   673  	tw := tar.NewWriter(buffer)
   674  	defer tw.Close()
   675  
   676  	if err := tw.WriteHeader(&tar.Header{
   677  		Name:     "Dockerfile",
   678  		Typeflag: tar.TypeSymlink,
   679  		Linkname: "/etc/passwd",
   680  	}); err != nil {
   681  		c.Fatalf("failed to write tar file header: %v", err)
   682  	}
   683  	if err := tw.Close(); err != nil {
   684  		c.Fatalf("failed to close tar archive: %v", err)
   685  	}
   686  
   687  	res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
   688  	c.Assert(err, check.IsNil)
   689  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   690  
   691  	out, err := readBody(body)
   692  	if err != nil {
   693  		c.Fatal(err)
   694  	}
   695  
   696  	// The reason the error is "Cannot locate specified Dockerfile" is because
   697  	// in the builder, the symlink is resolved within the context, therefore
   698  	// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
   699  	// a nonexistent file.
   700  	if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") {
   701  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   702  	}
   703  }
   704  
   705  // #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume
   706  func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) {
   707  	dockerCmd(c, "create", "-v", "/foo", "--name=one", "busybox")
   708  
   709  	fooDir, err := inspectMountSourceField("one", "/foo")
   710  	if err != nil {
   711  		c.Fatal(err)
   712  	}
   713  
   714  	dockerCmd(c, "create", "-v", "/foo", "--name=two", "busybox")
   715  
   716  	bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}}
   717  	status, _, err := sockRequest("POST", "/containers/two/start", bindSpec)
   718  	c.Assert(err, check.IsNil)
   719  	c.Assert(status, check.Equals, http.StatusNoContent)
   720  
   721  	fooDir2, err := inspectMountSourceField("two", "/foo")
   722  	if err != nil {
   723  		c.Fatal(err)
   724  	}
   725  
   726  	if fooDir2 != fooDir {
   727  		c.Fatalf("expected volume path to be %s, got: %s", fooDir, fooDir2)
   728  	}
   729  }
   730  
   731  func (s *DockerSuite) TestContainerApiPause(c *check.C) {
   732  	defer unpauseAllContainers()
   733  	out, _ := dockerCmd(c, "run", "-d", "busybox", "sleep", "30")
   734  	ContainerID := strings.TrimSpace(out)
   735  
   736  	status, _, err := sockRequest("POST", "/containers/"+ContainerID+"/pause", nil)
   737  	c.Assert(err, check.IsNil)
   738  	c.Assert(status, check.Equals, http.StatusNoContent)
   739  
   740  	pausedContainers, err := getSliceOfPausedContainers()
   741  
   742  	if err != nil {
   743  		c.Fatalf("error thrown while checking if containers were paused: %v", err)
   744  	}
   745  
   746  	if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] {
   747  		c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
   748  	}
   749  
   750  	status, _, err = sockRequest("POST", "/containers/"+ContainerID+"/unpause", nil)
   751  	c.Assert(err, check.IsNil)
   752  	c.Assert(status, check.Equals, http.StatusNoContent)
   753  
   754  	pausedContainers, err = getSliceOfPausedContainers()
   755  
   756  	if err != nil {
   757  		c.Fatalf("error thrown while checking if containers were paused: %v", err)
   758  	}
   759  
   760  	if pausedContainers != nil {
   761  		c.Fatalf("There should be no paused container.")
   762  	}
   763  }
   764  
   765  func (s *DockerSuite) TestContainerApiTop(c *check.C) {
   766  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "top")
   767  	id := strings.TrimSpace(string(out))
   768  	if err := waitRun(id); err != nil {
   769  		c.Fatal(err)
   770  	}
   771  
   772  	type topResp struct {
   773  		Titles    []string
   774  		Processes [][]string
   775  	}
   776  	var top topResp
   777  	status, b, err := sockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil)
   778  	c.Assert(err, check.IsNil)
   779  	c.Assert(status, check.Equals, http.StatusOK)
   780  
   781  	if err := json.Unmarshal(b, &top); err != nil {
   782  		c.Fatal(err)
   783  	}
   784  
   785  	if len(top.Titles) != 11 {
   786  		c.Fatalf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles)
   787  	}
   788  
   789  	if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" {
   790  		c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles)
   791  	}
   792  	if len(top.Processes) != 2 {
   793  		c.Fatalf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes)
   794  	}
   795  	if top.Processes[0][10] != "/bin/sh -c top" {
   796  		c.Fatalf("expected `/bin/sh -c top`, found: %s", top.Processes[0][10])
   797  	}
   798  	if top.Processes[1][10] != "top" {
   799  		c.Fatalf("expected `top`, found: %s", top.Processes[1][10])
   800  	}
   801  }
   802  
   803  func (s *DockerSuite) TestContainerApiCommit(c *check.C) {
   804  	cName := "testapicommit"
   805  	dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test")
   806  
   807  	name := "TestContainerApiCommit"
   808  	status, b, err := sockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil)
   809  	c.Assert(err, check.IsNil)
   810  	c.Assert(status, check.Equals, http.StatusCreated)
   811  
   812  	type resp struct {
   813  		ID string
   814  	}
   815  	var img resp
   816  	if err := json.Unmarshal(b, &img); err != nil {
   817  		c.Fatal(err)
   818  	}
   819  
   820  	cmd, err := inspectField(img.ID, "Config.Cmd")
   821  	if err != nil {
   822  		c.Fatal(err)
   823  	}
   824  	if cmd != "{[/bin/sh -c touch /test]}" {
   825  		c.Fatalf("got wrong Cmd from commit: %q", cmd)
   826  	}
   827  	// sanity check, make sure the image is what we think it is
   828  	dockerCmd(c, "run", img.ID, "ls", "/test")
   829  }
   830  
   831  func (s *DockerSuite) TestContainerApiCommitWithLabelInConfig(c *check.C) {
   832  	cName := "testapicommitwithconfig"
   833  	dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test")
   834  
   835  	config := map[string]interface{}{
   836  		"Labels": map[string]string{"key1": "value1", "key2": "value2"},
   837  	}
   838  
   839  	name := "TestContainerApiCommitWithConfig"
   840  	status, b, err := sockRequest("POST", "/commit?repo="+name+"&container="+cName, config)
   841  	c.Assert(err, check.IsNil)
   842  	c.Assert(status, check.Equals, http.StatusCreated)
   843  
   844  	type resp struct {
   845  		ID string
   846  	}
   847  	var img resp
   848  	if err := json.Unmarshal(b, &img); err != nil {
   849  		c.Fatal(err)
   850  	}
   851  
   852  	label1, err := inspectFieldMap(img.ID, "Config.Labels", "key1")
   853  	if err != nil {
   854  		c.Fatal(err)
   855  	}
   856  	c.Assert(label1, check.Equals, "value1")
   857  
   858  	label2, err := inspectFieldMap(img.ID, "Config.Labels", "key2")
   859  	if err != nil {
   860  		c.Fatal(err)
   861  	}
   862  	c.Assert(label2, check.Equals, "value2")
   863  
   864  	cmd, err := inspectField(img.ID, "Config.Cmd")
   865  	if err != nil {
   866  		c.Fatal(err)
   867  	}
   868  	if cmd != "{[/bin/sh -c touch /test]}" {
   869  		c.Fatalf("got wrong Cmd from commit: %q", cmd)
   870  	}
   871  
   872  	// sanity check, make sure the image is what we think it is
   873  	dockerCmd(c, "run", img.ID, "ls", "/test")
   874  }
   875  
   876  func (s *DockerSuite) TestContainerApiBadPort(c *check.C) {
   877  	config := map[string]interface{}{
   878  		"Image": "busybox",
   879  		"Cmd":   []string{"/bin/sh", "-c", "echo test"},
   880  		"PortBindings": map[string]interface{}{
   881  			"8080/tcp": []map[string]interface{}{
   882  				{
   883  					"HostIP":   "",
   884  					"HostPort": "aa80",
   885  				},
   886  			},
   887  		},
   888  	}
   889  
   890  	jsonData := bytes.NewBuffer(nil)
   891  	json.NewEncoder(jsonData).Encode(config)
   892  
   893  	status, b, err := sockRequest("POST", "/containers/create", config)
   894  	c.Assert(err, check.IsNil)
   895  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   896  
   897  	if strings.TrimSpace(string(b)) != `Invalid port specification: "aa80"` {
   898  		c.Fatalf("Incorrect error msg: %s", string(b))
   899  	}
   900  }
   901  
   902  func (s *DockerSuite) TestContainerApiCreate(c *check.C) {
   903  	config := map[string]interface{}{
   904  		"Image": "busybox",
   905  		"Cmd":   []string{"/bin/sh", "-c", "touch /test && ls /test"},
   906  	}
   907  
   908  	status, b, err := sockRequest("POST", "/containers/create", config)
   909  	c.Assert(err, check.IsNil)
   910  	c.Assert(status, check.Equals, http.StatusCreated)
   911  
   912  	type createResp struct {
   913  		ID string
   914  	}
   915  	var container createResp
   916  	if err := json.Unmarshal(b, &container); err != nil {
   917  		c.Fatal(err)
   918  	}
   919  
   920  	out, _ := dockerCmd(c, "start", "-a", container.ID)
   921  	if strings.TrimSpace(out) != "/test" {
   922  		c.Fatalf("expected output `/test`, got %q", out)
   923  	}
   924  }
   925  
   926  func (s *DockerSuite) TestContainerApiCreateEmptyConfig(c *check.C) {
   927  	config := map[string]interface{}{}
   928  
   929  	status, b, err := sockRequest("POST", "/containers/create", config)
   930  	c.Assert(err, check.IsNil)
   931  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   932  
   933  	expected := "Config cannot be empty in order to create a container\n"
   934  	if body := string(b); body != expected {
   935  		c.Fatalf("Expected to get %q, got %q", expected, body)
   936  	}
   937  }
   938  
   939  func (s *DockerSuite) TestContainerApiCreateWithHostName(c *check.C) {
   940  	hostName := "test-host"
   941  	config := map[string]interface{}{
   942  		"Image":    "busybox",
   943  		"Hostname": hostName,
   944  	}
   945  
   946  	status, body, err := sockRequest("POST", "/containers/create", config)
   947  	c.Assert(err, check.IsNil)
   948  	c.Assert(status, check.Equals, http.StatusCreated)
   949  
   950  	var container types.ContainerCreateResponse
   951  	if err := json.Unmarshal(body, &container); err != nil {
   952  		c.Fatal(err)
   953  	}
   954  
   955  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
   956  	c.Assert(err, check.IsNil)
   957  	c.Assert(status, check.Equals, http.StatusOK)
   958  
   959  	var containerJSON types.ContainerJSON
   960  	if err := json.Unmarshal(body, &containerJSON); err != nil {
   961  		c.Fatal(err)
   962  	}
   963  
   964  	if containerJSON.Config.Hostname != hostName {
   965  		c.Fatalf("Mismatched Hostname, Expected %s, Actual: %s ", hostName, containerJSON.Config.Hostname)
   966  	}
   967  }
   968  
   969  func (s *DockerSuite) TestContainerApiCreateWithDomainName(c *check.C) {
   970  	domainName := "test-domain"
   971  	config := map[string]interface{}{
   972  		"Image":      "busybox",
   973  		"Domainname": domainName,
   974  	}
   975  
   976  	status, body, err := sockRequest("POST", "/containers/create", config)
   977  	c.Assert(err, check.IsNil)
   978  	c.Assert(status, check.Equals, http.StatusCreated)
   979  
   980  	var container types.ContainerCreateResponse
   981  	if err := json.Unmarshal(body, &container); err != nil {
   982  		c.Fatal(err)
   983  	}
   984  
   985  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
   986  	c.Assert(err, check.IsNil)
   987  	c.Assert(status, check.Equals, http.StatusOK)
   988  
   989  	var containerJSON types.ContainerJSON
   990  	if err := json.Unmarshal(body, &containerJSON); err != nil {
   991  		c.Fatal(err)
   992  	}
   993  
   994  	if containerJSON.Config.Domainname != domainName {
   995  		c.Fatalf("Mismatched Domainname, Expected %s, Actual: %s ", domainName, containerJSON.Config.Domainname)
   996  	}
   997  }
   998  
   999  func (s *DockerSuite) TestContainerApiCreateNetworkMode(c *check.C) {
  1000  	UtilCreateNetworkMode(c, "host")
  1001  	UtilCreateNetworkMode(c, "bridge")
  1002  	UtilCreateNetworkMode(c, "container:web1")
  1003  }
  1004  
  1005  func UtilCreateNetworkMode(c *check.C, networkMode string) {
  1006  	config := map[string]interface{}{
  1007  		"Image":      "busybox",
  1008  		"HostConfig": map[string]interface{}{"NetworkMode": networkMode},
  1009  	}
  1010  
  1011  	status, body, err := sockRequest("POST", "/containers/create", config)
  1012  	c.Assert(err, check.IsNil)
  1013  	c.Assert(status, check.Equals, http.StatusCreated)
  1014  
  1015  	var container types.ContainerCreateResponse
  1016  	if err := json.Unmarshal(body, &container); err != nil {
  1017  		c.Fatal(err)
  1018  	}
  1019  
  1020  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1021  	c.Assert(err, check.IsNil)
  1022  	c.Assert(status, check.Equals, http.StatusOK)
  1023  
  1024  	var containerJSON types.ContainerJSON
  1025  	if err := json.Unmarshal(body, &containerJSON); err != nil {
  1026  		c.Fatal(err)
  1027  	}
  1028  
  1029  	if containerJSON.HostConfig.NetworkMode != runconfig.NetworkMode(networkMode) {
  1030  		c.Fatalf("Mismatched NetworkMode, Expected %s, Actual: %s ", networkMode, containerJSON.HostConfig.NetworkMode)
  1031  	}
  1032  }
  1033  
  1034  func (s *DockerSuite) TestContainerApiCreateWithCpuSharesCpuset(c *check.C) {
  1035  	config := map[string]interface{}{
  1036  		"Image":      "busybox",
  1037  		"CpuShares":  512,
  1038  		"CpusetCpus": "0,1",
  1039  	}
  1040  
  1041  	status, body, err := sockRequest("POST", "/containers/create", config)
  1042  	c.Assert(err, check.IsNil)
  1043  	c.Assert(status, check.Equals, http.StatusCreated)
  1044  
  1045  	var container types.ContainerCreateResponse
  1046  	if err := json.Unmarshal(body, &container); err != nil {
  1047  		c.Fatal(err)
  1048  	}
  1049  
  1050  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1051  	c.Assert(err, check.IsNil)
  1052  	c.Assert(status, check.Equals, http.StatusOK)
  1053  
  1054  	var containerJSON types.ContainerJSON
  1055  
  1056  	c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1057  
  1058  	out, err := inspectField(containerJSON.Id, "HostConfig.CpuShares")
  1059  	c.Assert(err, check.IsNil)
  1060  	c.Assert(out, check.Equals, "512")
  1061  
  1062  	outCpuset, errCpuset := inspectField(containerJSON.Id, "HostConfig.CpusetCpus")
  1063  	c.Assert(errCpuset, check.IsNil, check.Commentf("Output: %s", outCpuset))
  1064  	c.Assert(outCpuset, check.Equals, "0,1")
  1065  }
  1066  
  1067  func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) {
  1068  	config := map[string]interface{}{
  1069  		"Image": "busybox",
  1070  	}
  1071  
  1072  	create := func(ct string) (*http.Response, io.ReadCloser, error) {
  1073  		jsonData := bytes.NewBuffer(nil)
  1074  		if err := json.NewEncoder(jsonData).Encode(config); err != nil {
  1075  			c.Fatal(err)
  1076  		}
  1077  		return sockRequestRaw("POST", "/containers/create", jsonData, ct)
  1078  	}
  1079  
  1080  	// Try with no content-type
  1081  	res, body, err := create("")
  1082  	c.Assert(err, check.IsNil)
  1083  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
  1084  	body.Close()
  1085  
  1086  	// Try with wrong content-type
  1087  	res, body, err = create("application/xml")
  1088  	c.Assert(err, check.IsNil)
  1089  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
  1090  	body.Close()
  1091  
  1092  	// now application/json
  1093  	res, body, err = create("application/json")
  1094  	c.Assert(err, check.IsNil)
  1095  	c.Assert(res.StatusCode, check.Equals, http.StatusCreated)
  1096  	body.Close()
  1097  }
  1098  
  1099  //Issue 14230. daemon should return 500 for invalid port syntax
  1100  func (s *DockerSuite) TestContainerApiInvalidPortSyntax(c *check.C) {
  1101  	config := `{
  1102  				  "Image": "busybox",
  1103  				  "HostConfig": {
  1104  					"PortBindings": {
  1105  					  "19039;1230": [
  1106  						{}
  1107  					  ]
  1108  					}
  1109  				  }
  1110  				}`
  1111  
  1112  	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
  1113  	c.Assert(err, check.IsNil)
  1114  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
  1115  
  1116  	b, err := readBody(body)
  1117  	if err != nil {
  1118  		c.Fatal(err)
  1119  	}
  1120  	c.Assert(strings.Contains(string(b[:]), "Invalid port"), check.Equals, true)
  1121  }
  1122  
  1123  // Issue 7941 - test to make sure a "null" in JSON is just ignored.
  1124  // W/o this fix a null in JSON would be parsed into a string var as "null"
  1125  func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) {
  1126  	config := `{
  1127  		"Hostname":"",
  1128  		"Domainname":"",
  1129  		"Memory":0,
  1130  		"MemorySwap":0,
  1131  		"CpuShares":0,
  1132  		"Cpuset":null,
  1133  		"AttachStdin":true,
  1134  		"AttachStdout":true,
  1135  		"AttachStderr":true,
  1136  		"ExposedPorts":{},
  1137  		"Tty":true,
  1138  		"OpenStdin":true,
  1139  		"StdinOnce":true,
  1140  		"Env":[],
  1141  		"Cmd":"ls",
  1142  		"Image":"busybox",
  1143  		"Volumes":{},
  1144  		"WorkingDir":"",
  1145  		"Entrypoint":null,
  1146  		"NetworkDisabled":false,
  1147  		"OnBuild":null}`
  1148  
  1149  	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
  1150  	c.Assert(err, check.IsNil)
  1151  	c.Assert(res.StatusCode, check.Equals, http.StatusCreated)
  1152  
  1153  	b, err := readBody(body)
  1154  	if err != nil {
  1155  		c.Fatal(err)
  1156  	}
  1157  	type createResp struct {
  1158  		ID string
  1159  	}
  1160  	var container createResp
  1161  	if err := json.Unmarshal(b, &container); err != nil {
  1162  		c.Fatal(err)
  1163  	}
  1164  
  1165  	out, err := inspectField(container.ID, "HostConfig.CpusetCpus")
  1166  	if err != nil {
  1167  		c.Fatal(err, out)
  1168  	}
  1169  	if out != "" {
  1170  		c.Fatalf("expected empty string, got %q", out)
  1171  	}
  1172  
  1173  	outMemory, errMemory := inspectField(container.ID, "HostConfig.Memory")
  1174  	c.Assert(outMemory, check.Equals, "0")
  1175  	if errMemory != nil {
  1176  		c.Fatal(errMemory, outMemory)
  1177  	}
  1178  	outMemorySwap, errMemorySwap := inspectField(container.ID, "HostConfig.MemorySwap")
  1179  	c.Assert(outMemorySwap, check.Equals, "0")
  1180  	if errMemorySwap != nil {
  1181  		c.Fatal(errMemorySwap, outMemorySwap)
  1182  	}
  1183  }
  1184  
  1185  func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) {
  1186  	config := `{
  1187  		"Image":     "busybox",
  1188  		"Cmd":       "ls",
  1189  		"OpenStdin": true,
  1190  		"CpuShares": 100,
  1191  		"Memory":    524287
  1192  	}`
  1193  
  1194  	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
  1195  	c.Assert(err, check.IsNil)
  1196  	b, err2 := readBody(body)
  1197  	if err2 != nil {
  1198  		c.Fatal(err2)
  1199  	}
  1200  
  1201  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
  1202  	c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
  1203  }
  1204  
  1205  func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) {
  1206  	out, _ := dockerCmd(c, "create", "busybox")
  1207  
  1208  	containerID := strings.TrimSpace(out)
  1209  
  1210  	config := `{
  1211                  "CpuShares": 100,
  1212                  "Memory":    524287
  1213          }`
  1214  
  1215  	res, body, err := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
  1216  	c.Assert(err, check.IsNil)
  1217  	b, err2 := readBody(body)
  1218  	if err2 != nil {
  1219  		c.Fatal(err2)
  1220  	}
  1221  
  1222  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
  1223  	c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
  1224  }
  1225  
  1226  func (s *DockerSuite) TestContainerApiRename(c *check.C) {
  1227  	out, _ := dockerCmd(c, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh")
  1228  
  1229  	containerID := strings.TrimSpace(out)
  1230  	newName := "TestContainerApiRenameNew"
  1231  	statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil)
  1232  	c.Assert(err, check.IsNil)
  1233  	// 204 No Content is expected, not 200
  1234  	c.Assert(statusCode, check.Equals, http.StatusNoContent)
  1235  
  1236  	name, err := inspectField(containerID, "Name")
  1237  	if name != "/"+newName {
  1238  		c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name)
  1239  	}
  1240  }
  1241  
  1242  func (s *DockerSuite) TestContainerApiKill(c *check.C) {
  1243  	name := "test-api-kill"
  1244  	dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
  1245  
  1246  	status, _, err := sockRequest("POST", "/containers/"+name+"/kill", nil)
  1247  	c.Assert(err, check.IsNil)
  1248  	c.Assert(status, check.Equals, http.StatusNoContent)
  1249  
  1250  	state, err := inspectField(name, "State.Running")
  1251  	if err != nil {
  1252  		c.Fatal(err)
  1253  	}
  1254  	if state != "false" {
  1255  		c.Fatalf("got wrong State from container %s: %q", name, state)
  1256  	}
  1257  }
  1258  
  1259  func (s *DockerSuite) TestContainerApiRestart(c *check.C) {
  1260  	name := "test-api-restart"
  1261  	dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
  1262  
  1263  	status, _, err := sockRequest("POST", "/containers/"+name+"/restart?t=1", nil)
  1264  	c.Assert(err, check.IsNil)
  1265  	c.Assert(status, check.Equals, http.StatusNoContent)
  1266  
  1267  	if err := waitInspect(name, "{{ .State.Restarting  }} {{ .State.Running  }}", "false true", 5); err != nil {
  1268  		c.Fatal(err)
  1269  	}
  1270  }
  1271  
  1272  func (s *DockerSuite) TestContainerApiRestartNotimeoutParam(c *check.C) {
  1273  	name := "test-api-restart-no-timeout-param"
  1274  	out, _ := dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
  1275  	id := strings.TrimSpace(out)
  1276  	c.Assert(waitRun(id), check.IsNil)
  1277  
  1278  	status, _, err := sockRequest("POST", "/containers/"+name+"/restart", nil)
  1279  	c.Assert(err, check.IsNil)
  1280  	c.Assert(status, check.Equals, http.StatusNoContent)
  1281  
  1282  	if err := waitInspect(name, "{{ .State.Restarting  }} {{ .State.Running  }}", "false true", 5); err != nil {
  1283  		c.Fatal(err)
  1284  	}
  1285  }
  1286  
  1287  func (s *DockerSuite) TestContainerApiStart(c *check.C) {
  1288  	name := "testing-start"
  1289  	config := map[string]interface{}{
  1290  		"Image":     "busybox",
  1291  		"Cmd":       []string{"/bin/sh", "-c", "/bin/top"},
  1292  		"OpenStdin": true,
  1293  	}
  1294  
  1295  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
  1296  	c.Assert(err, check.IsNil)
  1297  	c.Assert(status, check.Equals, http.StatusCreated)
  1298  
  1299  	conf := make(map[string]interface{})
  1300  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
  1301  	c.Assert(err, check.IsNil)
  1302  	c.Assert(status, check.Equals, http.StatusNoContent)
  1303  
  1304  	// second call to start should give 304
  1305  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
  1306  	c.Assert(err, check.IsNil)
  1307  	c.Assert(status, check.Equals, http.StatusNotModified)
  1308  }
  1309  
  1310  func (s *DockerSuite) TestContainerApiStop(c *check.C) {
  1311  	name := "test-api-stop"
  1312  	dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
  1313  
  1314  	status, _, err := sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
  1315  	c.Assert(err, check.IsNil)
  1316  	c.Assert(status, check.Equals, http.StatusNoContent)
  1317  
  1318  	if err := waitInspect(name, "{{ .State.Running  }}", "false", 5); err != nil {
  1319  		c.Fatal(err)
  1320  	}
  1321  
  1322  	// second call to start should give 304
  1323  	status, _, err = sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
  1324  	c.Assert(err, check.IsNil)
  1325  	c.Assert(status, check.Equals, http.StatusNotModified)
  1326  }
  1327  
  1328  func (s *DockerSuite) TestContainerApiWait(c *check.C) {
  1329  	name := "test-api-wait"
  1330  	dockerCmd(c, "run", "--name", name, "busybox", "sleep", "5")
  1331  
  1332  	status, body, err := sockRequest("POST", "/containers/"+name+"/wait", nil)
  1333  	c.Assert(err, check.IsNil)
  1334  	c.Assert(status, check.Equals, http.StatusOK)
  1335  
  1336  	if err := waitInspect(name, "{{ .State.Running  }}", "false", 5); err != nil {
  1337  		c.Fatal(err)
  1338  	}
  1339  
  1340  	var waitres types.ContainerWaitResponse
  1341  	if err := json.Unmarshal(body, &waitres); err != nil {
  1342  		c.Fatalf("unable to unmarshal response body: %v", err)
  1343  	}
  1344  
  1345  	if waitres.StatusCode != 0 {
  1346  		c.Fatalf("Expected wait response StatusCode to be 0, got %d", waitres.StatusCode)
  1347  	}
  1348  }
  1349  
  1350  func (s *DockerSuite) TestContainerApiCopy(c *check.C) {
  1351  	name := "test-container-api-copy"
  1352  	dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
  1353  
  1354  	postData := types.CopyConfig{
  1355  		Resource: "/test.txt",
  1356  	}
  1357  
  1358  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1359  	c.Assert(err, check.IsNil)
  1360  	c.Assert(status, check.Equals, http.StatusOK)
  1361  
  1362  	found := false
  1363  	for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
  1364  		h, err := tarReader.Next()
  1365  		if err != nil {
  1366  			if err == io.EOF {
  1367  				break
  1368  			}
  1369  			c.Fatal(err)
  1370  		}
  1371  		if h.Name == "test.txt" {
  1372  			found = true
  1373  			break
  1374  		}
  1375  	}
  1376  	c.Assert(found, check.Equals, true)
  1377  }
  1378  
  1379  func (s *DockerSuite) TestContainerApiCopyResourcePathEmpty(c *check.C) {
  1380  	name := "test-container-api-copy-resource-empty"
  1381  	dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
  1382  
  1383  	postData := types.CopyConfig{
  1384  		Resource: "",
  1385  	}
  1386  
  1387  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1388  	c.Assert(err, check.IsNil)
  1389  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1390  	c.Assert(string(body), check.Matches, "Path cannot be empty\n")
  1391  }
  1392  
  1393  func (s *DockerSuite) TestContainerApiCopyResourcePathNotFound(c *check.C) {
  1394  	name := "test-container-api-copy-resource-not-found"
  1395  	dockerCmd(c, "run", "--name", name, "busybox")
  1396  
  1397  	postData := types.CopyConfig{
  1398  		Resource: "/notexist",
  1399  	}
  1400  
  1401  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1402  	c.Assert(err, check.IsNil)
  1403  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1404  	c.Assert(string(body), check.Matches, "Could not find the file /notexist in container "+name+"\n")
  1405  }
  1406  
  1407  func (s *DockerSuite) TestContainerApiCopyContainerNotFound(c *check.C) {
  1408  	postData := types.CopyConfig{
  1409  		Resource: "/something",
  1410  	}
  1411  
  1412  	status, _, err := sockRequest("POST", "/containers/notexists/copy", postData)
  1413  	c.Assert(err, check.IsNil)
  1414  	c.Assert(status, check.Equals, http.StatusNotFound)
  1415  }
  1416  
  1417  func (s *DockerSuite) TestContainerApiDelete(c *check.C) {
  1418  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1419  
  1420  	id := strings.TrimSpace(out)
  1421  	c.Assert(waitRun(id), check.IsNil)
  1422  
  1423  	dockerCmd(c, "stop", id)
  1424  
  1425  	status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  1426  	c.Assert(err, check.IsNil)
  1427  	c.Assert(status, check.Equals, http.StatusNoContent)
  1428  }
  1429  
  1430  func (s *DockerSuite) TestContainerApiDeleteNotExist(c *check.C) {
  1431  	status, body, err := sockRequest("DELETE", "/containers/doesnotexist", nil)
  1432  	c.Assert(err, check.IsNil)
  1433  	c.Assert(status, check.Equals, http.StatusNotFound)
  1434  	c.Assert(string(body), check.Matches, "no such id: doesnotexist\n")
  1435  }
  1436  
  1437  func (s *DockerSuite) TestContainerApiDeleteForce(c *check.C) {
  1438  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1439  
  1440  	id := strings.TrimSpace(out)
  1441  	c.Assert(waitRun(id), check.IsNil)
  1442  
  1443  	status, _, err := sockRequest("DELETE", "/containers/"+id+"?force=1", nil)
  1444  	c.Assert(err, check.IsNil)
  1445  	c.Assert(status, check.Equals, http.StatusNoContent)
  1446  }
  1447  
  1448  func (s *DockerSuite) TestContainerApiDeleteRemoveLinks(c *check.C) {
  1449  	out, _ := dockerCmd(c, "run", "-d", "--name", "tlink1", "busybox", "top")
  1450  
  1451  	id := strings.TrimSpace(out)
  1452  	c.Assert(waitRun(id), check.IsNil)
  1453  
  1454  	out, _ = dockerCmd(c, "run", "--link", "tlink1:tlink1", "--name", "tlink2", "-d", "busybox", "top")
  1455  
  1456  	id2 := strings.TrimSpace(out)
  1457  	c.Assert(waitRun(id2), check.IsNil)
  1458  
  1459  	links, err := inspectFieldJSON(id2, "HostConfig.Links")
  1460  	c.Assert(err, check.IsNil)
  1461  
  1462  	if links != "[\"/tlink1:/tlink2/tlink1\"]" {
  1463  		c.Fatal("expected to have links between containers")
  1464  	}
  1465  
  1466  	status, _, err := sockRequest("DELETE", "/containers/tlink2/tlink1?link=1", nil)
  1467  	c.Assert(err, check.IsNil)
  1468  	c.Assert(status, check.Equals, http.StatusNoContent)
  1469  
  1470  	linksPostRm, err := inspectFieldJSON(id2, "HostConfig.Links")
  1471  	c.Assert(err, check.IsNil)
  1472  
  1473  	if linksPostRm != "null" {
  1474  		c.Fatal("call to api deleteContainer links should have removed the specified links")
  1475  	}
  1476  }
  1477  
  1478  func (s *DockerSuite) TestContainerApiDeleteConflict(c *check.C) {
  1479  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1480  
  1481  	id := strings.TrimSpace(out)
  1482  	c.Assert(waitRun(id), check.IsNil)
  1483  
  1484  	status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  1485  	c.Assert(err, check.IsNil)
  1486  	c.Assert(status, check.Equals, http.StatusConflict)
  1487  }
  1488  
  1489  func (s *DockerSuite) TestContainerApiDeleteRemoveVolume(c *check.C) {
  1490  	testRequires(c, SameHostDaemon)
  1491  
  1492  	out, _ := dockerCmd(c, "run", "-d", "-v", "/testvolume", "busybox", "top")
  1493  
  1494  	id := strings.TrimSpace(out)
  1495  	c.Assert(waitRun(id), check.IsNil)
  1496  
  1497  	source, err := inspectMountSourceField(id, "/testvolume")
  1498  	_, err = os.Stat(source)
  1499  	c.Assert(err, check.IsNil)
  1500  
  1501  	status, _, err := sockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil)
  1502  	c.Assert(err, check.IsNil)
  1503  	c.Assert(status, check.Equals, http.StatusNoContent)
  1504  
  1505  	if _, err := os.Stat(source); !os.IsNotExist(err) {
  1506  		c.Fatalf("expected to get ErrNotExist error, got %v", err)
  1507  	}
  1508  }
  1509  
  1510  // Regression test for https://github.com/docker/docker/issues/6231
  1511  func (s *DockerSuite) TestContainersApiChunkedEncoding(c *check.C) {
  1512  	out, _ := dockerCmd(c, "create", "-v", "/foo", "busybox", "true")
  1513  	id := strings.TrimSpace(out)
  1514  
  1515  	conn, err := sockConn(time.Duration(10 * time.Second))
  1516  	if err != nil {
  1517  		c.Fatal(err)
  1518  	}
  1519  	client := httputil.NewClientConn(conn, nil)
  1520  	defer client.Close()
  1521  
  1522  	bindCfg := strings.NewReader(`{"Binds": ["/tmp:/foo"]}`)
  1523  	req, err := http.NewRequest("POST", "/containers/"+id+"/start", bindCfg)
  1524  	if err != nil {
  1525  		c.Fatal(err)
  1526  	}
  1527  	req.Header.Set("Content-Type", "application/json")
  1528  	// This is a cheat to make the http request do chunked encoding
  1529  	// Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
  1530  	// https://golang.org/src/pkg/net/http/request.go?s=11980:12172
  1531  	req.ContentLength = -1
  1532  
  1533  	resp, err := client.Do(req)
  1534  	if err != nil {
  1535  		c.Fatalf("error starting container with chunked encoding: %v", err)
  1536  	}
  1537  	resp.Body.Close()
  1538  	if resp.StatusCode != 204 {
  1539  		c.Fatalf("expected status code 204, got %d", resp.StatusCode)
  1540  	}
  1541  
  1542  	out, err = inspectFieldJSON(id, "HostConfig.Binds")
  1543  	if err != nil {
  1544  		c.Fatal(err)
  1545  	}
  1546  
  1547  	var binds []string
  1548  	if err := json.NewDecoder(strings.NewReader(out)).Decode(&binds); err != nil {
  1549  		c.Fatal(err)
  1550  	}
  1551  	if len(binds) != 1 {
  1552  		c.Fatalf("got unexpected binds: %v", binds)
  1553  	}
  1554  
  1555  	expected := "/tmp:/foo"
  1556  	if binds[0] != expected {
  1557  		c.Fatalf("got incorrect bind spec, wanted %s, got: %s", expected, binds[0])
  1558  	}
  1559  }
  1560  
  1561  func (s *DockerSuite) TestPostContainerStop(c *check.C) {
  1562  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1563  
  1564  	containerID := strings.TrimSpace(out)
  1565  	c.Assert(waitRun(containerID), check.IsNil)
  1566  
  1567  	statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/stop", nil)
  1568  	c.Assert(err, check.IsNil)
  1569  	// 204 No Content is expected, not 200
  1570  	c.Assert(statusCode, check.Equals, http.StatusNoContent)
  1571  
  1572  	if err := waitInspect(containerID, "{{ .State.Running  }}", "false", 5); err != nil {
  1573  		c.Fatal(err)
  1574  	}
  1575  }
  1576  
  1577  // #14170
  1578  func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceEntrypoint(c *check.C) {
  1579  	config := struct {
  1580  		Image      string
  1581  		Entrypoint string
  1582  		Cmd        []string
  1583  	}{"busybox", "echo", []string{"hello", "world"}}
  1584  	_, _, err := sockRequest("POST", "/containers/create?name=echotest", config)
  1585  	c.Assert(err, check.IsNil)
  1586  	out, _ := dockerCmd(c, "start", "-a", "echotest")
  1587  	c.Assert(strings.TrimSpace(out), check.Equals, "hello world")
  1588  
  1589  	config2 := struct {
  1590  		Image      string
  1591  		Entrypoint []string
  1592  		Cmd        []string
  1593  	}{"busybox", []string{"echo"}, []string{"hello", "world"}}
  1594  	_, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2)
  1595  	c.Assert(err, check.IsNil)
  1596  	out, _ = dockerCmd(c, "start", "-a", "echotest2")
  1597  	c.Assert(strings.TrimSpace(out), check.Equals, "hello world")
  1598  }
  1599  
  1600  // #14170
  1601  func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *check.C) {
  1602  	config := struct {
  1603  		Image      string
  1604  		Entrypoint string
  1605  		Cmd        string
  1606  	}{"busybox", "echo", "hello world"}
  1607  	_, _, err := sockRequest("POST", "/containers/create?name=echotest", config)
  1608  	c.Assert(err, check.IsNil)
  1609  	out, _ := dockerCmd(c, "start", "-a", "echotest")
  1610  	c.Assert(strings.TrimSpace(out), check.Equals, "hello world")
  1611  
  1612  	config2 := struct {
  1613  		Image string
  1614  		Cmd   []string
  1615  	}{"busybox", []string{"echo", "hello", "world"}}
  1616  	_, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2)
  1617  	c.Assert(err, check.IsNil)
  1618  	out, _ = dockerCmd(c, "start", "-a", "echotest2")
  1619  	c.Assert(strings.TrimSpace(out), check.Equals, "hello world")
  1620  }
  1621  
  1622  // regression #14318
  1623  func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *check.C) {
  1624  	config := struct {
  1625  		Image   string
  1626  		CapAdd  string
  1627  		CapDrop string
  1628  	}{"busybox", "NET_ADMIN", "SYS_ADMIN"}
  1629  	status, _, err := sockRequest("POST", "/containers/create?name=capaddtest0", config)
  1630  	c.Assert(err, check.IsNil)
  1631  	c.Assert(status, check.Equals, http.StatusCreated)
  1632  
  1633  	config2 := struct {
  1634  		Image   string
  1635  		CapAdd  []string
  1636  		CapDrop []string
  1637  	}{"busybox", []string{"NET_ADMIN", "SYS_ADMIN"}, []string{"SETGID"}}
  1638  	status, _, err = sockRequest("POST", "/containers/create?name=capaddtest1", config2)
  1639  	c.Assert(err, check.IsNil)
  1640  	c.Assert(status, check.Equals, http.StatusCreated)
  1641  }
  1642  
  1643  // #14640
  1644  func (s *DockerSuite) TestPostContainersStartWithoutLinksInHostConfig(c *check.C) {
  1645  	name := "test-host-config-links"
  1646  	dockerCmd(c, "create", "--name", name, "busybox", "top")
  1647  
  1648  	hc, err := inspectFieldJSON(name, "HostConfig")
  1649  	c.Assert(err, check.IsNil)
  1650  	config := `{"HostConfig":` + hc + `}`
  1651  
  1652  	res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1653  	c.Assert(err, check.IsNil)
  1654  	c.Assert(res.StatusCode, check.Equals, http.StatusNoContent)
  1655  	b.Close()
  1656  }
  1657  
  1658  // #14640
  1659  func (s *DockerSuite) TestPostContainersStartWithLinksInHostConfig(c *check.C) {
  1660  	name := "test-host-config-links"
  1661  	dockerCmd(c, "run", "--name", "foo", "-d", "busybox", "top")
  1662  	dockerCmd(c, "create", "--name", name, "--link", "foo:bar", "busybox", "top")
  1663  
  1664  	hc, err := inspectFieldJSON(name, "HostConfig")
  1665  	c.Assert(err, check.IsNil)
  1666  	config := `{"HostConfig":` + hc + `}`
  1667  
  1668  	res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1669  	c.Assert(err, check.IsNil)
  1670  	c.Assert(res.StatusCode, check.Equals, http.StatusNoContent)
  1671  	b.Close()
  1672  }
  1673  
  1674  // #14640
  1675  func (s *DockerSuite) TestPostContainersStartWithLinksInHostConfigIdLinked(c *check.C) {
  1676  	name := "test-host-config-links"
  1677  	out, _ := dockerCmd(c, "run", "--name", "link0", "-d", "busybox", "top")
  1678  	id := strings.TrimSpace(out)
  1679  	dockerCmd(c, "create", "--name", name, "--link", id, "busybox", "top")
  1680  
  1681  	hc, err := inspectFieldJSON(name, "HostConfig")
  1682  	c.Assert(err, check.IsNil)
  1683  	config := `{"HostConfig":` + hc + `}`
  1684  
  1685  	res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1686  	c.Assert(err, check.IsNil)
  1687  	c.Assert(res.StatusCode, check.Equals, http.StatusNoContent)
  1688  	b.Close()
  1689  }