github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/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  	"os/exec"
    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  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true")
    29  	out, _, err := runCommandWithOutput(runCmd)
    30  	if err != nil {
    31  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
    32  	}
    33  
    34  	status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
    35  	c.Assert(status, check.Equals, http.StatusOK)
    36  	c.Assert(err, check.IsNil)
    37  
    38  	var inspectJSON []struct {
    39  		Names []string
    40  	}
    41  	if err = json.Unmarshal(body, &inspectJSON); err != nil {
    42  		c.Fatalf("unable to unmarshal response body: %v", err)
    43  	}
    44  
    45  	if len(inspectJSON) != startCount+1 {
    46  		c.Fatalf("Expected %d container(s), %d found (started with: %d)", startCount+1, len(inspectJSON), startCount)
    47  	}
    48  
    49  	if actual := inspectJSON[0].Names[0]; actual != "/"+name {
    50  		c.Fatalf("Container Name mismatch. Expected: %q, received: %q\n", "/"+name, actual)
    51  	}
    52  }
    53  
    54  func (s *DockerSuite) TestContainerApiGetExport(c *check.C) {
    55  	name := "exportcontainer"
    56  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test")
    57  	out, _, err := runCommandWithOutput(runCmd)
    58  	if err != nil {
    59  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
    60  	}
    61  
    62  	status, body, err := sockRequest("GET", "/containers/"+name+"/export", nil)
    63  	c.Assert(status, check.Equals, http.StatusOK)
    64  	c.Assert(err, check.IsNil)
    65  
    66  	found := false
    67  	for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
    68  		h, err := tarReader.Next()
    69  		if err != nil {
    70  			if err == io.EOF {
    71  				break
    72  			}
    73  			c.Fatal(err)
    74  		}
    75  		if h.Name == "test" {
    76  			found = true
    77  			break
    78  		}
    79  	}
    80  
    81  	if !found {
    82  		c.Fatalf("The created test file has not been found in the exported image")
    83  	}
    84  }
    85  
    86  func (s *DockerSuite) TestContainerApiGetChanges(c *check.C) {
    87  	name := "changescontainer"
    88  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "rm", "/etc/passwd")
    89  	out, _, err := runCommandWithOutput(runCmd)
    90  	if err != nil {
    91  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
    92  	}
    93  
    94  	status, body, err := sockRequest("GET", "/containers/"+name+"/changes", nil)
    95  	c.Assert(status, check.Equals, http.StatusOK)
    96  	c.Assert(err, check.IsNil)
    97  
    98  	changes := []struct {
    99  		Kind int
   100  		Path string
   101  	}{}
   102  	if err = json.Unmarshal(body, &changes); err != nil {
   103  		c.Fatalf("unable to unmarshal response body: %v", err)
   104  	}
   105  
   106  	// Check the changelog for removal of /etc/passwd
   107  	success := false
   108  	for _, elem := range changes {
   109  		if elem.Path == "/etc/passwd" && elem.Kind == 2 {
   110  			success = true
   111  		}
   112  	}
   113  	if !success {
   114  		c.Fatalf("/etc/passwd has been removed but is not present in the diff")
   115  	}
   116  }
   117  
   118  func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) {
   119  	name := "testing"
   120  	config := map[string]interface{}{
   121  		"Image":   "busybox",
   122  		"Volumes": map[string]struct{}{"/tmp": {}},
   123  	}
   124  
   125  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   126  	c.Assert(status, check.Equals, http.StatusCreated)
   127  	c.Assert(err, check.IsNil)
   128  
   129  	bindPath := randomUnixTmpDirPath("test")
   130  	config = map[string]interface{}{
   131  		"Binds": []string{bindPath + ":/tmp"},
   132  	}
   133  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   134  	c.Assert(status, check.Equals, http.StatusNoContent)
   135  	c.Assert(err, check.IsNil)
   136  
   137  	pth, err := inspectFieldMap(name, "Volumes", "/tmp")
   138  	if err != nil {
   139  		c.Fatal(err)
   140  	}
   141  
   142  	if pth != bindPath {
   143  		c.Fatalf("expected volume host path to be %s, got %s", bindPath, pth)
   144  	}
   145  }
   146  
   147  // Test for GH#10618
   148  func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) {
   149  	name := "testdups"
   150  	config := map[string]interface{}{
   151  		"Image":   "busybox",
   152  		"Volumes": map[string]struct{}{"/tmp": {}},
   153  	}
   154  
   155  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   156  	c.Assert(status, check.Equals, http.StatusCreated)
   157  	c.Assert(err, check.IsNil)
   158  
   159  	bindPath1 := randomUnixTmpDirPath("test1")
   160  	bindPath2 := randomUnixTmpDirPath("test2")
   161  
   162  	config = map[string]interface{}{
   163  		"Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"},
   164  	}
   165  	status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
   166  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   167  	c.Assert(err, check.IsNil)
   168  
   169  	if !strings.Contains(string(body), "Duplicate volume") {
   170  		c.Fatalf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err)
   171  	}
   172  }
   173  
   174  func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
   175  	volName := "voltst"
   176  	volPath := "/tmp"
   177  
   178  	if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil {
   179  		c.Fatal(out, err)
   180  	}
   181  
   182  	name := "TestContainerApiStartDupVolumeBinds"
   183  	config := map[string]interface{}{
   184  		"Image":   "busybox",
   185  		"Volumes": map[string]struct{}{volPath: {}},
   186  	}
   187  
   188  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   189  	c.Assert(status, check.Equals, http.StatusCreated)
   190  	c.Assert(err, check.IsNil)
   191  
   192  	config = map[string]interface{}{
   193  		"VolumesFrom": []string{volName},
   194  	}
   195  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   196  	c.Assert(status, check.Equals, http.StatusNoContent)
   197  	c.Assert(err, check.IsNil)
   198  
   199  	pth, err := inspectFieldMap(name, "Volumes", volPath)
   200  	if err != nil {
   201  		c.Fatal(err)
   202  	}
   203  	pth2, err := inspectFieldMap(volName, "Volumes", volPath)
   204  	if err != nil {
   205  		c.Fatal(err)
   206  	}
   207  
   208  	if pth != pth2 {
   209  		c.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
   210  	}
   211  }
   212  
   213  // Ensure that volumes-from has priority over binds/anything else
   214  // This is pretty much the same as TestRunApplyVolumesFromBeforeVolumes, except with passing the VolumesFrom and the bind on start
   215  func (s *DockerSuite) TestVolumesFromHasPriority(c *check.C) {
   216  	volName := "voltst2"
   217  	volPath := "/tmp"
   218  
   219  	if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil {
   220  		c.Fatal(out, err)
   221  	}
   222  
   223  	name := "testing"
   224  	config := map[string]interface{}{
   225  		"Image":   "busybox",
   226  		"Volumes": map[string]struct{}{volPath: {}},
   227  	}
   228  
   229  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   230  	c.Assert(status, check.Equals, http.StatusCreated)
   231  	c.Assert(err, check.IsNil)
   232  
   233  	bindPath := randomUnixTmpDirPath("test")
   234  	config = map[string]interface{}{
   235  		"VolumesFrom": []string{volName},
   236  		"Binds":       []string{bindPath + ":/tmp"},
   237  	}
   238  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   239  	c.Assert(status, check.Equals, http.StatusNoContent)
   240  	c.Assert(err, check.IsNil)
   241  
   242  	pth, err := inspectFieldMap(name, "Volumes", volPath)
   243  	if err != nil {
   244  		c.Fatal(err)
   245  	}
   246  	pth2, err := inspectFieldMap(volName, "Volumes", volPath)
   247  	if err != nil {
   248  		c.Fatal(err)
   249  	}
   250  
   251  	if pth != pth2 {
   252  		c.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
   253  	}
   254  }
   255  
   256  func (s *DockerSuite) TestGetContainerStats(c *check.C) {
   257  	var (
   258  		name   = "statscontainer"
   259  		runCmd = exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "top")
   260  	)
   261  	out, _, err := runCommandWithOutput(runCmd)
   262  	if err != nil {
   263  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
   264  	}
   265  	type b struct {
   266  		status int
   267  		body   []byte
   268  		err    error
   269  	}
   270  	bc := make(chan b, 1)
   271  	go func() {
   272  		status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
   273  		bc <- b{status, body, err}
   274  	}()
   275  
   276  	// allow some time to stream the stats from the container
   277  	time.Sleep(4 * time.Second)
   278  	if _, err := runCommand(exec.Command(dockerBinary, "rm", "-f", name)); err != nil {
   279  		c.Fatal(err)
   280  	}
   281  
   282  	// collect the results from the stats stream or timeout and fail
   283  	// if the stream was not disconnected.
   284  	select {
   285  	case <-time.After(2 * time.Second):
   286  		c.Fatal("stream was not closed after container was removed")
   287  	case sr := <-bc:
   288  		c.Assert(sr.err, check.IsNil)
   289  		c.Assert(sr.status, check.Equals, http.StatusOK)
   290  
   291  		dec := json.NewDecoder(bytes.NewBuffer(sr.body))
   292  		var s *types.Stats
   293  		// decode only one object from the stream
   294  		if err := dec.Decode(&s); err != nil {
   295  			c.Fatal(err)
   296  		}
   297  	}
   298  }
   299  
   300  func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
   301  	// TODO: this test does nothing because we are c.Assert'ing in goroutine
   302  	var (
   303  		name   = "statscontainer"
   304  		runCmd = exec.Command(dockerBinary, "create", "--name", name, "busybox", "top")
   305  	)
   306  	out, _, err := runCommandWithOutput(runCmd)
   307  	if err != nil {
   308  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
   309  	}
   310  
   311  	go func() {
   312  		// We'll never get return for GET stats from sockRequest as of now,
   313  		// just send request and see if panic or error would happen on daemon side.
   314  		status, _, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
   315  		c.Assert(status, check.Equals, http.StatusOK)
   316  		c.Assert(err, check.IsNil)
   317  	}()
   318  
   319  	// allow some time to send request and let daemon deal with it
   320  	time.Sleep(1 * time.Second)
   321  }
   322  
   323  func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
   324  	// Test to make sure we stop people from trying to leave the
   325  	// build context when specifying the path to the dockerfile
   326  	buffer := new(bytes.Buffer)
   327  	tw := tar.NewWriter(buffer)
   328  	defer tw.Close()
   329  
   330  	dockerfile := []byte("FROM busybox")
   331  	if err := tw.WriteHeader(&tar.Header{
   332  		Name: "Dockerfile",
   333  		Size: int64(len(dockerfile)),
   334  	}); err != nil {
   335  		c.Fatalf("failed to write tar file header: %v", err)
   336  	}
   337  	if _, err := tw.Write(dockerfile); err != nil {
   338  		c.Fatalf("failed to write tar file content: %v", err)
   339  	}
   340  	if err := tw.Close(); err != nil {
   341  		c.Fatalf("failed to close tar archive: %v", err)
   342  	}
   343  
   344  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
   345  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   346  	c.Assert(err, check.IsNil)
   347  
   348  	out, err := readBody(body)
   349  	if err != nil {
   350  		c.Fatal(err)
   351  	}
   352  
   353  	if !strings.Contains(string(out), "must be within the build context") {
   354  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   355  	}
   356  }
   357  
   358  func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
   359  	server, err := fakeStorage(map[string]string{
   360  		"testD": `FROM busybox
   361  COPY * /tmp/
   362  RUN find / -name ba*
   363  RUN find /tmp/`,
   364  	})
   365  	if err != nil {
   366  		c.Fatal(err)
   367  	}
   368  	defer server.Close()
   369  
   370  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
   371  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   372  	c.Assert(err, check.IsNil)
   373  
   374  	buf, err := readBody(body)
   375  	if err != nil {
   376  		c.Fatal(err)
   377  	}
   378  
   379  	// Make sure Dockerfile exists.
   380  	// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
   381  	out := string(buf)
   382  	if !strings.Contains(out, "/tmp/Dockerfile") ||
   383  		strings.Contains(out, "baz") {
   384  		c.Fatalf("Incorrect output: %s", out)
   385  	}
   386  }
   387  
   388  func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
   389  	git, err := fakeGIT("repo", map[string]string{
   390  		"dockerfile": `FROM busybox
   391  RUN echo from dockerfile`,
   392  	}, false)
   393  	if err != nil {
   394  		c.Fatal(err)
   395  	}
   396  	defer git.Close()
   397  
   398  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   399  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   400  	c.Assert(err, check.IsNil)
   401  
   402  	buf, err := readBody(body)
   403  	if err != nil {
   404  		c.Fatal(err)
   405  	}
   406  
   407  	out := string(buf)
   408  	if !strings.Contains(out, "from dockerfile") {
   409  		c.Fatalf("Incorrect output: %s", out)
   410  	}
   411  }
   412  
   413  func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
   414  	git, err := fakeGIT("repo", map[string]string{
   415  		"baz": `FROM busybox
   416  RUN echo from baz`,
   417  		"Dockerfile": `FROM busybox
   418  RUN echo from Dockerfile`,
   419  	}, false)
   420  	if err != nil {
   421  		c.Fatal(err)
   422  	}
   423  	defer git.Close()
   424  
   425  	// Make sure it tries to 'dockerfile' query param value
   426  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
   427  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   428  	c.Assert(err, check.IsNil)
   429  
   430  	buf, err := readBody(body)
   431  	if err != nil {
   432  		c.Fatal(err)
   433  	}
   434  
   435  	out := string(buf)
   436  	if !strings.Contains(out, "from baz") {
   437  		c.Fatalf("Incorrect output: %s", out)
   438  	}
   439  }
   440  
   441  func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
   442  	testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
   443  	git, err := fakeGIT("repo", map[string]string{
   444  		"Dockerfile": `FROM busybox
   445  RUN echo from Dockerfile`,
   446  		"dockerfile": `FROM busybox
   447  RUN echo from dockerfile`,
   448  	}, false)
   449  	if err != nil {
   450  		c.Fatal(err)
   451  	}
   452  	defer git.Close()
   453  
   454  	// Make sure it tries to 'dockerfile' query param value
   455  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   456  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   457  	c.Assert(err, check.IsNil)
   458  
   459  	buf, err := readBody(body)
   460  	if err != nil {
   461  		c.Fatal(err)
   462  	}
   463  
   464  	out := string(buf)
   465  	if !strings.Contains(out, "from Dockerfile") {
   466  		c.Fatalf("Incorrect output: %s", out)
   467  	}
   468  }
   469  
   470  func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
   471  	// Test to make sure we stop people from trying to leave the
   472  	// build context when specifying a symlink as the path to the dockerfile
   473  	buffer := new(bytes.Buffer)
   474  	tw := tar.NewWriter(buffer)
   475  	defer tw.Close()
   476  
   477  	if err := tw.WriteHeader(&tar.Header{
   478  		Name:     "Dockerfile",
   479  		Typeflag: tar.TypeSymlink,
   480  		Linkname: "/etc/passwd",
   481  	}); err != nil {
   482  		c.Fatalf("failed to write tar file header: %v", err)
   483  	}
   484  	if err := tw.Close(); err != nil {
   485  		c.Fatalf("failed to close tar archive: %v", err)
   486  	}
   487  
   488  	res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
   489  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   490  	c.Assert(err, check.IsNil)
   491  
   492  	out, err := readBody(body)
   493  	if err != nil {
   494  		c.Fatal(err)
   495  	}
   496  
   497  	// The reason the error is "Cannot locate specified Dockerfile" is because
   498  	// in the builder, the symlink is resolved within the context, therefore
   499  	// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
   500  	// a nonexistent file.
   501  	if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") {
   502  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   503  	}
   504  }
   505  
   506  // #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
   507  func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) {
   508  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=one", "busybox"))
   509  	if err != nil {
   510  		c.Fatal(err, out)
   511  	}
   512  
   513  	fooDir, err := inspectFieldMap("one", "Volumes", "/foo")
   514  	if err != nil {
   515  		c.Fatal(err)
   516  	}
   517  
   518  	out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=two", "busybox"))
   519  	if err != nil {
   520  		c.Fatal(err, out)
   521  	}
   522  
   523  	bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}}
   524  	status, _, err := sockRequest("POST", "/containers/two/start", bindSpec)
   525  	c.Assert(status, check.Equals, http.StatusNoContent)
   526  	c.Assert(err, check.IsNil)
   527  
   528  	fooDir2, err := inspectFieldMap("two", "Volumes", "/foo")
   529  	if err != nil {
   530  		c.Fatal(err)
   531  	}
   532  
   533  	if fooDir2 != fooDir {
   534  		c.Fatalf("expected volume path to be %s, got: %s", fooDir, fooDir2)
   535  	}
   536  }
   537  
   538  func (s *DockerSuite) TestContainerApiPause(c *check.C) {
   539  	defer unpauseAllContainers()
   540  	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep", "30")
   541  	out, _, err := runCommandWithOutput(runCmd)
   542  
   543  	if err != nil {
   544  		c.Fatalf("failed to create a container: %s, %v", out, err)
   545  	}
   546  	ContainerID := strings.TrimSpace(out)
   547  
   548  	status, _, err := sockRequest("POST", "/containers/"+ContainerID+"/pause", nil)
   549  	c.Assert(status, check.Equals, http.StatusNoContent)
   550  	c.Assert(err, check.IsNil)
   551  
   552  	pausedContainers, err := getSliceOfPausedContainers()
   553  
   554  	if err != nil {
   555  		c.Fatalf("error thrown while checking if containers were paused: %v", err)
   556  	}
   557  
   558  	if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] {
   559  		c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
   560  	}
   561  
   562  	status, _, err = sockRequest("POST", "/containers/"+ContainerID+"/unpause", nil)
   563  	c.Assert(status, check.Equals, http.StatusNoContent)
   564  	c.Assert(err, check.IsNil)
   565  
   566  	pausedContainers, err = getSliceOfPausedContainers()
   567  
   568  	if err != nil {
   569  		c.Fatalf("error thrown while checking if containers were paused: %v", err)
   570  	}
   571  
   572  	if pausedContainers != nil {
   573  		c.Fatalf("There should be no paused container.")
   574  	}
   575  }
   576  
   577  func (s *DockerSuite) TestContainerApiTop(c *check.C) {
   578  	out, err := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", "top").CombinedOutput()
   579  	if err != nil {
   580  		c.Fatal(err, out)
   581  	}
   582  	id := strings.TrimSpace(string(out))
   583  	if err := waitRun(id); err != nil {
   584  		c.Fatal(err)
   585  	}
   586  
   587  	type topResp struct {
   588  		Titles    []string
   589  		Processes [][]string
   590  	}
   591  	var top topResp
   592  	status, b, err := sockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil)
   593  	c.Assert(status, check.Equals, http.StatusOK)
   594  	c.Assert(err, check.IsNil)
   595  
   596  	if err := json.Unmarshal(b, &top); err != nil {
   597  		c.Fatal(err)
   598  	}
   599  
   600  	if len(top.Titles) != 11 {
   601  		c.Fatalf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles)
   602  	}
   603  
   604  	if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" {
   605  		c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles)
   606  	}
   607  	if len(top.Processes) != 2 {
   608  		c.Fatalf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes)
   609  	}
   610  	if top.Processes[0][10] != "/bin/sh -c top" {
   611  		c.Fatalf("expected `/bin/sh -c top`, found: %s", top.Processes[0][10])
   612  	}
   613  	if top.Processes[1][10] != "top" {
   614  		c.Fatalf("expected `top`, found: %s", top.Processes[1][10])
   615  	}
   616  }
   617  
   618  func (s *DockerSuite) TestContainerApiCommit(c *check.C) {
   619  	cName := "testapicommit"
   620  	out, err := exec.Command(dockerBinary, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test").CombinedOutput()
   621  	if err != nil {
   622  		c.Fatal(err, out)
   623  	}
   624  
   625  	name := "TestContainerApiCommit"
   626  	status, b, err := sockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil)
   627  	c.Assert(status, check.Equals, http.StatusCreated)
   628  	c.Assert(err, check.IsNil)
   629  
   630  	type resp struct {
   631  		Id string
   632  	}
   633  	var img resp
   634  	if err := json.Unmarshal(b, &img); err != nil {
   635  		c.Fatal(err)
   636  	}
   637  
   638  	cmd, err := inspectField(img.Id, "Config.Cmd")
   639  	if err != nil {
   640  		c.Fatal(err)
   641  	}
   642  	if cmd != "{[/bin/sh -c touch /test]}" {
   643  		c.Fatalf("got wrong Cmd from commit: %q", cmd)
   644  	}
   645  	// sanity check, make sure the image is what we think it is
   646  	out, err = exec.Command(dockerBinary, "run", img.Id, "ls", "/test").CombinedOutput()
   647  	if err != nil {
   648  		c.Fatalf("error checking committed image: %v - %q", err, string(out))
   649  	}
   650  }
   651  
   652  func (s *DockerSuite) TestContainerApiCreate(c *check.C) {
   653  	config := map[string]interface{}{
   654  		"Image": "busybox",
   655  		"Cmd":   []string{"/bin/sh", "-c", "touch /test && ls /test"},
   656  	}
   657  
   658  	status, b, err := sockRequest("POST", "/containers/create", config)
   659  	c.Assert(status, check.Equals, http.StatusCreated)
   660  	c.Assert(err, check.IsNil)
   661  
   662  	type createResp struct {
   663  		Id string
   664  	}
   665  	var container createResp
   666  	if err := json.Unmarshal(b, &container); err != nil {
   667  		c.Fatal(err)
   668  	}
   669  
   670  	out, err := exec.Command(dockerBinary, "start", "-a", container.Id).CombinedOutput()
   671  	if err != nil {
   672  		c.Fatal(out, err)
   673  	}
   674  	if strings.TrimSpace(string(out)) != "/test" {
   675  		c.Fatalf("expected output `/test`, got %q", out)
   676  	}
   677  }
   678  
   679  func (s *DockerSuite) TestContainerApiCreateWithHostName(c *check.C) {
   680  	hostName := "test-host"
   681  	config := map[string]interface{}{
   682  		"Image":    "busybox",
   683  		"Hostname": hostName,
   684  	}
   685  
   686  	status, body, err := sockRequest("POST", "/containers/create", config)
   687  	c.Assert(err, check.IsNil)
   688  	c.Assert(status, check.Equals, http.StatusCreated)
   689  
   690  	var container types.ContainerCreateResponse
   691  	if err := json.Unmarshal(body, &container); err != nil {
   692  		c.Fatal(err)
   693  	}
   694  
   695  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
   696  	c.Assert(err, check.IsNil)
   697  	c.Assert(status, check.Equals, http.StatusOK)
   698  
   699  	var containerJSON types.ContainerJSON
   700  	if err := json.Unmarshal(body, &containerJSON); err != nil {
   701  		c.Fatal(err)
   702  	}
   703  
   704  	if containerJSON.Config.Hostname != hostName {
   705  		c.Fatalf("Mismatched Hostname, Expected %s, Actual: %s ", hostName, containerJSON.Config.Hostname)
   706  	}
   707  }
   708  
   709  func (s *DockerSuite) TestContainerApiCreateWithDomainName(c *check.C) {
   710  	domainName := "test-domain"
   711  	config := map[string]interface{}{
   712  		"Image":      "busybox",
   713  		"Domainname": domainName,
   714  	}
   715  
   716  	status, body, err := sockRequest("POST", "/containers/create", config)
   717  	c.Assert(err, check.IsNil)
   718  	c.Assert(status, check.Equals, http.StatusCreated)
   719  
   720  	var container types.ContainerCreateResponse
   721  	if err := json.Unmarshal(body, &container); err != nil {
   722  		c.Fatal(err)
   723  	}
   724  
   725  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
   726  	c.Assert(err, check.IsNil)
   727  	c.Assert(status, check.Equals, http.StatusOK)
   728  
   729  	var containerJSON types.ContainerJSON
   730  	if err := json.Unmarshal(body, &containerJSON); err != nil {
   731  		c.Fatal(err)
   732  	}
   733  
   734  	if containerJSON.Config.Domainname != domainName {
   735  		c.Fatalf("Mismatched Domainname, Expected %s, Actual: %s ", domainName, containerJSON.Config.Domainname)
   736  	}
   737  }
   738  
   739  func (s *DockerSuite) TestContainerApiCreateNetworkMode(c *check.C) {
   740  	UtilCreateNetworkMode(c, "host")
   741  	UtilCreateNetworkMode(c, "bridge")
   742  	UtilCreateNetworkMode(c, "container:web1")
   743  }
   744  
   745  func UtilCreateNetworkMode(c *check.C, networkMode string) {
   746  	config := map[string]interface{}{
   747  		"Image":      "busybox",
   748  		"HostConfig": map[string]interface{}{"NetworkMode": networkMode},
   749  	}
   750  
   751  	status, body, err := sockRequest("POST", "/containers/create", config)
   752  	c.Assert(err, check.IsNil)
   753  	c.Assert(status, check.Equals, http.StatusCreated)
   754  
   755  	var container types.ContainerCreateResponse
   756  	if err := json.Unmarshal(body, &container); err != nil {
   757  		c.Fatal(err)
   758  	}
   759  
   760  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
   761  	c.Assert(err, check.IsNil)
   762  	c.Assert(status, check.Equals, http.StatusOK)
   763  
   764  	var containerJSON types.ContainerJSON
   765  	if err := json.Unmarshal(body, &containerJSON); err != nil {
   766  		c.Fatal(err)
   767  	}
   768  
   769  	if containerJSON.HostConfig.NetworkMode != runconfig.NetworkMode(networkMode) {
   770  		c.Fatalf("Mismatched NetworkMode, Expected %s, Actual: %s ", networkMode, containerJSON.HostConfig.NetworkMode)
   771  	}
   772  }
   773  
   774  func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) {
   775  	config := map[string]interface{}{
   776  		"Image": "busybox",
   777  	}
   778  
   779  	create := func(ct string) (*http.Response, io.ReadCloser, error) {
   780  		jsonData := bytes.NewBuffer(nil)
   781  		if err := json.NewEncoder(jsonData).Encode(config); err != nil {
   782  			c.Fatal(err)
   783  		}
   784  		return sockRequestRaw("POST", "/containers/create", jsonData, ct)
   785  	}
   786  
   787  	// Try with no content-type
   788  	res, body, err := create("")
   789  	c.Assert(err, check.IsNil)
   790  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   791  	body.Close()
   792  
   793  	// Try with wrong content-type
   794  	res, body, err = create("application/xml")
   795  	c.Assert(err, check.IsNil)
   796  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   797  	body.Close()
   798  
   799  	// now application/json
   800  	res, body, err = create("application/json")
   801  	c.Assert(err, check.IsNil)
   802  	c.Assert(res.StatusCode, check.Equals, http.StatusCreated)
   803  	body.Close()
   804  }
   805  
   806  // Issue 7941 - test to make sure a "null" in JSON is just ignored.
   807  // W/o this fix a null in JSON would be parsed into a string var as "null"
   808  func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) {
   809  	config := `{
   810  		"Hostname":"",
   811  		"Domainname":"",
   812  		"Memory":0,
   813  		"MemorySwap":0,
   814  		"CpuShares":0,
   815  		"Cpuset":null,
   816  		"AttachStdin":true,
   817  		"AttachStdout":true,
   818  		"AttachStderr":true,
   819  		"PortSpecs":null,
   820  		"ExposedPorts":{},
   821  		"Tty":true,
   822  		"OpenStdin":true,
   823  		"StdinOnce":true,
   824  		"Env":[],
   825  		"Cmd":"ls",
   826  		"Image":"busybox",
   827  		"Volumes":{},
   828  		"WorkingDir":"",
   829  		"Entrypoint":null,
   830  		"NetworkDisabled":false,
   831  		"OnBuild":null}`
   832  
   833  	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
   834  	c.Assert(res.StatusCode, check.Equals, http.StatusCreated)
   835  	c.Assert(err, check.IsNil)
   836  
   837  	b, err := readBody(body)
   838  	if err != nil {
   839  		c.Fatal(err)
   840  	}
   841  	type createResp struct {
   842  		Id string
   843  	}
   844  	var container createResp
   845  	if err := json.Unmarshal(b, &container); err != nil {
   846  		c.Fatal(err)
   847  	}
   848  
   849  	out, err := inspectField(container.Id, "HostConfig.CpusetCpus")
   850  	if err != nil {
   851  		c.Fatal(err, out)
   852  	}
   853  	if out != "" {
   854  		c.Fatalf("expected empty string, got %q", out)
   855  	}
   856  
   857  	outMemory, errMemory := inspectField(container.Id, "HostConfig.Memory")
   858  	c.Assert(outMemory, check.Equals, "0")
   859  	if errMemory != nil {
   860  		c.Fatal(errMemory, outMemory)
   861  	}
   862  	outMemorySwap, errMemorySwap := inspectField(container.Id, "HostConfig.MemorySwap")
   863  	c.Assert(outMemorySwap, check.Equals, "0")
   864  	if errMemorySwap != nil {
   865  		c.Fatal(errMemorySwap, outMemorySwap)
   866  	}
   867  }
   868  
   869  func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) {
   870  	config := `{
   871  		"Image":     "busybox",
   872  		"Cmd":       "ls",
   873  		"OpenStdin": true,
   874  		"CpuShares": 100,
   875  		"Memory":    524287
   876  	}`
   877  
   878  	res, body, _ := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
   879  	b, err2 := readBody(body)
   880  	if err2 != nil {
   881  		c.Fatal(err2)
   882  	}
   883  
   884  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   885  	c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
   886  }
   887  
   888  func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) {
   889  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "busybox"))
   890  	if err != nil {
   891  		c.Fatal(err, out)
   892  	}
   893  
   894  	containerID := strings.TrimSpace(out)
   895  
   896  	config := `{
   897                  "CpuShares": 100,
   898                  "Memory":    524287
   899          }`
   900  
   901  	res, body, _ := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
   902  	b, err2 := readBody(body)
   903  	if err2 != nil {
   904  		c.Fatal(err2)
   905  	}
   906  
   907  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   908  	c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
   909  }
   910  
   911  func (s *DockerSuite) TestContainerApiRename(c *check.C) {
   912  	runCmd := exec.Command(dockerBinary, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh")
   913  	out, _, err := runCommandWithOutput(runCmd)
   914  	c.Assert(err, check.IsNil)
   915  
   916  	containerID := strings.TrimSpace(out)
   917  	newName := "TestContainerApiRenameNew"
   918  	statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil)
   919  
   920  	// 204 No Content is expected, not 200
   921  	c.Assert(statusCode, check.Equals, http.StatusNoContent)
   922  	c.Assert(err, check.IsNil)
   923  
   924  	name, err := inspectField(containerID, "Name")
   925  	if name != "/"+newName {
   926  		c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name)
   927  	}
   928  }
   929  
   930  func (s *DockerSuite) TestContainerApiKill(c *check.C) {
   931  	name := "test-api-kill"
   932  	runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top")
   933  	out, _, err := runCommandWithOutput(runCmd)
   934  	if err != nil {
   935  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
   936  	}
   937  
   938  	status, _, err := sockRequest("POST", "/containers/"+name+"/kill", nil)
   939  	c.Assert(status, check.Equals, http.StatusNoContent)
   940  	c.Assert(err, check.IsNil)
   941  
   942  	state, err := inspectField(name, "State.Running")
   943  	if err != nil {
   944  		c.Fatal(err)
   945  	}
   946  	if state != "false" {
   947  		c.Fatalf("got wrong State from container %s: %q", name, state)
   948  	}
   949  }
   950  
   951  func (s *DockerSuite) TestContainerApiRestart(c *check.C) {
   952  	name := "test-api-restart"
   953  	runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top")
   954  	out, _, err := runCommandWithOutput(runCmd)
   955  	if err != nil {
   956  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
   957  	}
   958  
   959  	status, _, err := sockRequest("POST", "/containers/"+name+"/restart?t=1", nil)
   960  	c.Assert(status, check.Equals, http.StatusNoContent)
   961  	c.Assert(err, check.IsNil)
   962  
   963  	if err := waitInspect(name, "{{ .State.Restarting  }} {{ .State.Running  }}", "false true", 5); err != nil {
   964  		c.Fatal(err)
   965  	}
   966  }
   967  
   968  func (s *DockerSuite) TestContainerApiRestartNotimeoutParam(c *check.C) {
   969  	name := "test-api-restart-no-timeout-param"
   970  	runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top")
   971  	out, _, err := runCommandWithOutput(runCmd)
   972  	if err != nil {
   973  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
   974  	}
   975  	id := strings.TrimSpace(out)
   976  	c.Assert(waitRun(id), check.IsNil)
   977  
   978  	status, _, err := sockRequest("POST", "/containers/"+name+"/restart", nil)
   979  	c.Assert(status, check.Equals, http.StatusNoContent)
   980  	c.Assert(err, check.IsNil)
   981  
   982  	if err := waitInspect(name, "{{ .State.Restarting  }} {{ .State.Running  }}", "false true", 5); err != nil {
   983  		c.Fatal(err)
   984  	}
   985  }
   986  
   987  func (s *DockerSuite) TestContainerApiStart(c *check.C) {
   988  	name := "testing-start"
   989  	config := map[string]interface{}{
   990  		"Image":     "busybox",
   991  		"Cmd":       []string{"/bin/sh", "-c", "/bin/top"},
   992  		"OpenStdin": true,
   993  	}
   994  
   995  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   996  	c.Assert(status, check.Equals, http.StatusCreated)
   997  	c.Assert(err, check.IsNil)
   998  
   999  	conf := make(map[string]interface{})
  1000  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
  1001  	c.Assert(status, check.Equals, http.StatusNoContent)
  1002  	c.Assert(err, check.IsNil)
  1003  
  1004  	// second call to start should give 304
  1005  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
  1006  	c.Assert(status, check.Equals, http.StatusNotModified)
  1007  	c.Assert(err, check.IsNil)
  1008  }
  1009  
  1010  func (s *DockerSuite) TestContainerApiStop(c *check.C) {
  1011  	name := "test-api-stop"
  1012  	runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top")
  1013  	out, _, err := runCommandWithOutput(runCmd)
  1014  	if err != nil {
  1015  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
  1016  	}
  1017  
  1018  	status, _, err := sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
  1019  	c.Assert(status, check.Equals, http.StatusNoContent)
  1020  	c.Assert(err, check.IsNil)
  1021  
  1022  	if err := waitInspect(name, "{{ .State.Running  }}", "false", 5); err != nil {
  1023  		c.Fatal(err)
  1024  	}
  1025  
  1026  	// second call to start should give 304
  1027  	status, _, err = sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
  1028  	c.Assert(status, check.Equals, http.StatusNotModified)
  1029  	c.Assert(err, check.IsNil)
  1030  }
  1031  
  1032  func (s *DockerSuite) TestContainerApiWait(c *check.C) {
  1033  	name := "test-api-wait"
  1034  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sleep", "5")
  1035  	out, _, err := runCommandWithOutput(runCmd)
  1036  	if err != nil {
  1037  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
  1038  	}
  1039  
  1040  	status, body, err := sockRequest("POST", "/containers/"+name+"/wait", nil)
  1041  	c.Assert(status, check.Equals, http.StatusOK)
  1042  	c.Assert(err, check.IsNil)
  1043  
  1044  	if err := waitInspect(name, "{{ .State.Running  }}", "false", 5); err != nil {
  1045  		c.Fatal(err)
  1046  	}
  1047  
  1048  	var waitres types.ContainerWaitResponse
  1049  	if err := json.Unmarshal(body, &waitres); err != nil {
  1050  		c.Fatalf("unable to unmarshal response body: %v", err)
  1051  	}
  1052  
  1053  	if waitres.StatusCode != 0 {
  1054  		c.Fatalf("Expected wait response StatusCode to be 0, got %d", waitres.StatusCode)
  1055  	}
  1056  }
  1057  
  1058  func (s *DockerSuite) TestContainerApiCopy(c *check.C) {
  1059  	name := "test-container-api-copy"
  1060  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt")
  1061  	_, err := runCommand(runCmd)
  1062  	c.Assert(err, check.IsNil)
  1063  
  1064  	postData := types.CopyConfig{
  1065  		Resource: "/test.txt",
  1066  	}
  1067  
  1068  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1069  	c.Assert(err, check.IsNil)
  1070  	c.Assert(status, check.Equals, http.StatusOK)
  1071  
  1072  	found := false
  1073  	for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
  1074  		h, err := tarReader.Next()
  1075  		if err != nil {
  1076  			if err == io.EOF {
  1077  				break
  1078  			}
  1079  			c.Fatal(err)
  1080  		}
  1081  		if h.Name == "test.txt" {
  1082  			found = true
  1083  			break
  1084  		}
  1085  	}
  1086  	c.Assert(found, check.Equals, true)
  1087  }
  1088  
  1089  func (s *DockerSuite) TestContainerApiCopyResourcePathEmpty(c *check.C) {
  1090  	name := "test-container-api-copy-resource-empty"
  1091  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt")
  1092  	_, err := runCommand(runCmd)
  1093  	c.Assert(err, check.IsNil)
  1094  
  1095  	postData := types.CopyConfig{
  1096  		Resource: "",
  1097  	}
  1098  
  1099  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1100  	c.Assert(err, check.IsNil)
  1101  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1102  	c.Assert(string(body), check.Matches, "Path cannot be empty\n")
  1103  }
  1104  
  1105  func (s *DockerSuite) TestContainerApiCopyResourcePathNotFound(c *check.C) {
  1106  	name := "test-container-api-copy-resource-not-found"
  1107  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox")
  1108  	_, err := runCommand(runCmd)
  1109  	c.Assert(err, check.IsNil)
  1110  
  1111  	postData := types.CopyConfig{
  1112  		Resource: "/notexist",
  1113  	}
  1114  
  1115  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1116  	c.Assert(err, check.IsNil)
  1117  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1118  	c.Assert(string(body), check.Matches, "Could not find the file /notexist in container "+name+"\n")
  1119  }
  1120  
  1121  func (s *DockerSuite) TestContainerApiCopyContainerNotFound(c *check.C) {
  1122  	postData := types.CopyConfig{
  1123  		Resource: "/something",
  1124  	}
  1125  
  1126  	status, _, err := sockRequest("POST", "/containers/notexists/copy", postData)
  1127  	c.Assert(err, check.IsNil)
  1128  	c.Assert(status, check.Equals, http.StatusNotFound)
  1129  }
  1130  
  1131  func (s *DockerSuite) TestContainerApiDelete(c *check.C) {
  1132  	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
  1133  	out, _, err := runCommandWithOutput(runCmd)
  1134  	c.Assert(err, check.IsNil)
  1135  
  1136  	id := strings.TrimSpace(out)
  1137  	c.Assert(waitRun(id), check.IsNil)
  1138  
  1139  	stopCmd := exec.Command(dockerBinary, "stop", id)
  1140  	_, err = runCommand(stopCmd)
  1141  	c.Assert(err, check.IsNil)
  1142  
  1143  	status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  1144  	c.Assert(err, check.IsNil)
  1145  	c.Assert(status, check.Equals, http.StatusNoContent)
  1146  }
  1147  
  1148  func (s *DockerSuite) TestContainerApiDeleteNotExist(c *check.C) {
  1149  	status, body, err := sockRequest("DELETE", "/containers/doesnotexist", nil)
  1150  	c.Assert(err, check.IsNil)
  1151  	c.Assert(status, check.Equals, http.StatusNotFound)
  1152  	c.Assert(string(body), check.Matches, "no such id: doesnotexist\n")
  1153  }
  1154  
  1155  func (s *DockerSuite) TestContainerApiDeleteForce(c *check.C) {
  1156  	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
  1157  	out, _, err := runCommandWithOutput(runCmd)
  1158  	c.Assert(err, check.IsNil)
  1159  
  1160  	id := strings.TrimSpace(out)
  1161  	c.Assert(waitRun(id), check.IsNil)
  1162  
  1163  	status, _, err := sockRequest("DELETE", "/containers/"+id+"?force=1", nil)
  1164  	c.Assert(err, check.IsNil)
  1165  	c.Assert(status, check.Equals, http.StatusNoContent)
  1166  }
  1167  
  1168  func (s *DockerSuite) TestContainerApiDeleteRemoveLinks(c *check.C) {
  1169  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "tlink1", "busybox", "top")
  1170  	out, _, err := runCommandWithOutput(runCmd)
  1171  	c.Assert(err, check.IsNil)
  1172  
  1173  	id := strings.TrimSpace(out)
  1174  	c.Assert(waitRun(id), check.IsNil)
  1175  
  1176  	runCmd = exec.Command(dockerBinary, "run", "--link", "tlink1:tlink1", "--name", "tlink2", "-d", "busybox", "top")
  1177  	out, _, err = runCommandWithOutput(runCmd)
  1178  	c.Assert(err, check.IsNil)
  1179  
  1180  	id2 := strings.TrimSpace(out)
  1181  	c.Assert(waitRun(id2), check.IsNil)
  1182  
  1183  	links, err := inspectFieldJSON(id2, "HostConfig.Links")
  1184  	c.Assert(err, check.IsNil)
  1185  
  1186  	if links != "[\"/tlink1:/tlink2/tlink1\"]" {
  1187  		c.Fatal("expected to have links between containers")
  1188  	}
  1189  
  1190  	status, _, err := sockRequest("DELETE", "/containers/tlink2/tlink1?link=1", nil)
  1191  	c.Assert(err, check.IsNil)
  1192  	c.Assert(status, check.Equals, http.StatusNoContent)
  1193  
  1194  	linksPostRm, err := inspectFieldJSON(id2, "HostConfig.Links")
  1195  	c.Assert(err, check.IsNil)
  1196  
  1197  	if linksPostRm != "null" {
  1198  		c.Fatal("call to api deleteContainer links should have removed the specified links")
  1199  	}
  1200  }
  1201  
  1202  func (s *DockerSuite) TestContainerApiDeleteConflict(c *check.C) {
  1203  	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
  1204  	out, _, err := runCommandWithOutput(runCmd)
  1205  	c.Assert(err, check.IsNil)
  1206  
  1207  	id := strings.TrimSpace(out)
  1208  	c.Assert(waitRun(id), check.IsNil)
  1209  
  1210  	status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  1211  	c.Assert(status, check.Equals, http.StatusConflict)
  1212  	c.Assert(err, check.IsNil)
  1213  }
  1214  
  1215  func (s *DockerSuite) TestContainerApiDeleteRemoveVolume(c *check.C) {
  1216  	testRequires(c, SameHostDaemon)
  1217  
  1218  	runCmd := exec.Command(dockerBinary, "run", "-d", "-v", "/testvolume", "busybox", "top")
  1219  	out, _, err := runCommandWithOutput(runCmd)
  1220  	c.Assert(err, check.IsNil)
  1221  
  1222  	id := strings.TrimSpace(out)
  1223  	c.Assert(waitRun(id), check.IsNil)
  1224  
  1225  	vol, err := inspectFieldMap(id, "Volumes", "/testvolume")
  1226  	c.Assert(err, check.IsNil)
  1227  
  1228  	_, err = os.Stat(vol)
  1229  	c.Assert(err, check.IsNil)
  1230  
  1231  	status, _, err := sockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil)
  1232  	c.Assert(status, check.Equals, http.StatusNoContent)
  1233  	c.Assert(err, check.IsNil)
  1234  
  1235  	if _, err := os.Stat(vol); !os.IsNotExist(err) {
  1236  		c.Fatalf("expected to get ErrNotExist error, got %v", err)
  1237  	}
  1238  }
  1239  
  1240  // Regression test for https://github.com/docker/docker/issues/6231
  1241  func (s *DockerSuite) TestContainersApiChunkedEncoding(c *check.C) {
  1242  	out, _ := dockerCmd(c, "create", "-v", "/foo", "busybox", "true")
  1243  	id := strings.TrimSpace(out)
  1244  
  1245  	conn, err := sockConn(time.Duration(10 * time.Second))
  1246  	if err != nil {
  1247  		c.Fatal(err)
  1248  	}
  1249  	client := httputil.NewClientConn(conn, nil)
  1250  	defer client.Close()
  1251  
  1252  	bindCfg := strings.NewReader(`{"Binds": ["/tmp:/foo"]}`)
  1253  	req, err := http.NewRequest("POST", "/containers/"+id+"/start", bindCfg)
  1254  	if err != nil {
  1255  		c.Fatal(err)
  1256  	}
  1257  	req.Header.Set("Content-Type", "application/json")
  1258  	// This is a cheat to make the http request do chunked encoding
  1259  	// Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
  1260  	// https://golang.org/src/pkg/net/http/request.go?s=11980:12172
  1261  	req.ContentLength = -1
  1262  
  1263  	resp, err := client.Do(req)
  1264  	if err != nil {
  1265  		c.Fatalf("error starting container with chunked encoding: %v", err)
  1266  	}
  1267  	resp.Body.Close()
  1268  	if resp.StatusCode != 204 {
  1269  		c.Fatalf("expected status code 204, got %d", resp.StatusCode)
  1270  	}
  1271  
  1272  	out, err = inspectFieldJSON(id, "HostConfig.Binds")
  1273  	if err != nil {
  1274  		c.Fatal(err)
  1275  	}
  1276  
  1277  	var binds []string
  1278  	if err := json.NewDecoder(strings.NewReader(out)).Decode(&binds); err != nil {
  1279  		c.Fatal(err)
  1280  	}
  1281  	if len(binds) != 1 {
  1282  		c.Fatalf("got unexpected binds: %v", binds)
  1283  	}
  1284  
  1285  	expected := "/tmp:/foo"
  1286  	if binds[0] != expected {
  1287  		c.Fatalf("got incorrect bind spec, wanted %s, got: %s", expected, binds[0])
  1288  	}
  1289  }
  1290  
  1291  func (s *DockerSuite) TestPostContainerStop(c *check.C) {
  1292  	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
  1293  	out, _, err := runCommandWithOutput(runCmd)
  1294  	c.Assert(err, check.IsNil)
  1295  
  1296  	containerID := strings.TrimSpace(out)
  1297  	c.Assert(waitRun(containerID), check.IsNil)
  1298  
  1299  	statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/stop", nil)
  1300  
  1301  	// 204 No Content is expected, not 200
  1302  	c.Assert(statusCode, check.Equals, http.StatusNoContent)
  1303  	c.Assert(err, check.IsNil)
  1304  
  1305  	if err := waitInspect(containerID, "{{ .State.Running  }}", "false", 5); err != nil {
  1306  		c.Fatal(err)
  1307  	}
  1308  }