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