github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/integration-cli/docker_api_containers_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io"
     7  	"net/http"
     8  	"os/exec"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/pkg/stringid"
    14  	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
    15  	"github.com/go-check/check"
    16  )
    17  
    18  func (s *DockerSuite) TestContainerApiGetAll(c *check.C) {
    19  	startCount, err := getContainerCount()
    20  	if err != nil {
    21  		c.Fatalf("Cannot query container count: %v", err)
    22  	}
    23  
    24  	name := "getall"
    25  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true")
    26  	out, _, err := runCommandWithOutput(runCmd)
    27  	if err != nil {
    28  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
    29  	}
    30  
    31  	status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
    32  	c.Assert(status, check.Equals, http.StatusOK)
    33  	c.Assert(err, check.IsNil)
    34  
    35  	var inspectJSON []struct {
    36  		Names []string
    37  	}
    38  	if err = json.Unmarshal(body, &inspectJSON); err != nil {
    39  		c.Fatalf("unable to unmarshal response body: %v", err)
    40  	}
    41  
    42  	if len(inspectJSON) != startCount+1 {
    43  		c.Fatalf("Expected %d container(s), %d found (started with: %d)", startCount+1, len(inspectJSON), startCount)
    44  	}
    45  
    46  	if actual := inspectJSON[0].Names[0]; actual != "/"+name {
    47  		c.Fatalf("Container Name mismatch. Expected: %q, received: %q\n", "/"+name, actual)
    48  	}
    49  }
    50  
    51  func (s *DockerSuite) TestContainerApiGetExport(c *check.C) {
    52  	name := "exportcontainer"
    53  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test")
    54  	out, _, err := runCommandWithOutput(runCmd)
    55  	if err != nil {
    56  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
    57  	}
    58  
    59  	status, body, err := sockRequest("GET", "/containers/"+name+"/export", nil)
    60  	c.Assert(status, check.Equals, http.StatusOK)
    61  	c.Assert(err, check.IsNil)
    62  
    63  	found := false
    64  	for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
    65  		h, err := tarReader.Next()
    66  		if err != nil {
    67  			if err == io.EOF {
    68  				break
    69  			}
    70  			c.Fatal(err)
    71  		}
    72  		if h.Name == "test" {
    73  			found = true
    74  			break
    75  		}
    76  	}
    77  
    78  	if !found {
    79  		c.Fatalf("The created test file has not been found in the exported image")
    80  	}
    81  }
    82  
    83  func (s *DockerSuite) TestContainerApiGetChanges(c *check.C) {
    84  	name := "changescontainer"
    85  	runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "rm", "/etc/passwd")
    86  	out, _, err := runCommandWithOutput(runCmd)
    87  	if err != nil {
    88  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
    89  	}
    90  
    91  	status, body, err := sockRequest("GET", "/containers/"+name+"/changes", nil)
    92  	c.Assert(status, check.Equals, http.StatusOK)
    93  	c.Assert(err, check.IsNil)
    94  
    95  	changes := []struct {
    96  		Kind int
    97  		Path string
    98  	}{}
    99  	if err = json.Unmarshal(body, &changes); err != nil {
   100  		c.Fatalf("unable to unmarshal response body: %v", err)
   101  	}
   102  
   103  	// Check the changelog for removal of /etc/passwd
   104  	success := false
   105  	for _, elem := range changes {
   106  		if elem.Path == "/etc/passwd" && elem.Kind == 2 {
   107  			success = true
   108  		}
   109  	}
   110  	if !success {
   111  		c.Fatalf("/etc/passwd has been removed but is not present in the diff")
   112  	}
   113  }
   114  
   115  func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) {
   116  	name := "testing"
   117  	config := map[string]interface{}{
   118  		"Image":   "busybox",
   119  		"Volumes": map[string]struct{}{"/tmp": {}},
   120  	}
   121  
   122  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   123  	c.Assert(status, check.Equals, http.StatusCreated)
   124  	c.Assert(err, check.IsNil)
   125  
   126  	bindPath := randomUnixTmpDirPath("test")
   127  	config = map[string]interface{}{
   128  		"Binds": []string{bindPath + ":/tmp"},
   129  	}
   130  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   131  	c.Assert(status, check.Equals, http.StatusNoContent)
   132  	c.Assert(err, check.IsNil)
   133  
   134  	pth, err := inspectFieldMap(name, "Volumes", "/tmp")
   135  	if err != nil {
   136  		c.Fatal(err)
   137  	}
   138  
   139  	if pth != bindPath {
   140  		c.Fatalf("expected volume host path to be %s, got %s", bindPath, pth)
   141  	}
   142  }
   143  
   144  // Test for GH#10618
   145  func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) {
   146  	name := "testdups"
   147  	config := map[string]interface{}{
   148  		"Image":   "busybox",
   149  		"Volumes": map[string]struct{}{"/tmp": {}},
   150  	}
   151  
   152  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   153  	c.Assert(status, check.Equals, http.StatusCreated)
   154  	c.Assert(err, check.IsNil)
   155  
   156  	bindPath1 := randomUnixTmpDirPath("test1")
   157  	bindPath2 := randomUnixTmpDirPath("test2")
   158  
   159  	config = map[string]interface{}{
   160  		"Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"},
   161  	}
   162  	status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
   163  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   164  	c.Assert(err, check.IsNil)
   165  
   166  	if !strings.Contains(string(body), "Duplicate volume") {
   167  		c.Fatalf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err)
   168  	}
   169  }
   170  
   171  func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
   172  	volName := "voltst"
   173  	volPath := "/tmp"
   174  
   175  	if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil {
   176  		c.Fatal(out, err)
   177  	}
   178  
   179  	name := "TestContainerApiStartDupVolumeBinds"
   180  	config := map[string]interface{}{
   181  		"Image":   "busybox",
   182  		"Volumes": map[string]struct{}{volPath: {}},
   183  	}
   184  
   185  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   186  	c.Assert(status, check.Equals, http.StatusCreated)
   187  	c.Assert(err, check.IsNil)
   188  
   189  	config = map[string]interface{}{
   190  		"VolumesFrom": []string{volName},
   191  	}
   192  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   193  	c.Assert(status, check.Equals, http.StatusNoContent)
   194  	c.Assert(err, check.IsNil)
   195  
   196  	pth, err := inspectFieldMap(name, "Volumes", volPath)
   197  	if err != nil {
   198  		c.Fatal(err)
   199  	}
   200  	pth2, err := inspectFieldMap(volName, "Volumes", volPath)
   201  	if err != nil {
   202  		c.Fatal(err)
   203  	}
   204  
   205  	if pth != pth2 {
   206  		c.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
   207  	}
   208  }
   209  
   210  // Ensure that volumes-from has priority over binds/anything else
   211  // This is pretty much the same as TestRunApplyVolumesFromBeforeVolumes, except with passing the VolumesFrom and the bind on start
   212  func (s *DockerSuite) TestVolumesFromHasPriority(c *check.C) {
   213  	volName := "voltst2"
   214  	volPath := "/tmp"
   215  
   216  	if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil {
   217  		c.Fatal(out, err)
   218  	}
   219  
   220  	name := "testing"
   221  	config := map[string]interface{}{
   222  		"Image":   "busybox",
   223  		"Volumes": map[string]struct{}{volPath: {}},
   224  	}
   225  
   226  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   227  	c.Assert(status, check.Equals, http.StatusCreated)
   228  	c.Assert(err, check.IsNil)
   229  
   230  	bindPath := randomUnixTmpDirPath("test")
   231  	config = map[string]interface{}{
   232  		"VolumesFrom": []string{volName},
   233  		"Binds":       []string{bindPath + ":/tmp"},
   234  	}
   235  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
   236  	c.Assert(status, check.Equals, http.StatusNoContent)
   237  	c.Assert(err, check.IsNil)
   238  
   239  	pth, err := inspectFieldMap(name, "Volumes", volPath)
   240  	if err != nil {
   241  		c.Fatal(err)
   242  	}
   243  	pth2, err := inspectFieldMap(volName, "Volumes", volPath)
   244  	if err != nil {
   245  		c.Fatal(err)
   246  	}
   247  
   248  	if pth != pth2 {
   249  		c.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
   250  	}
   251  }
   252  
   253  func (s *DockerSuite) TestGetContainerStats(c *check.C) {
   254  	var (
   255  		name   = "statscontainer"
   256  		runCmd = exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "top")
   257  	)
   258  	out, _, err := runCommandWithOutput(runCmd)
   259  	if err != nil {
   260  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
   261  	}
   262  	type b struct {
   263  		body []byte
   264  		err  error
   265  	}
   266  	bc := make(chan b, 1)
   267  	go func() {
   268  		status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
   269  		c.Assert(status, check.Equals, http.StatusOK)
   270  		c.Assert(err, check.IsNil)
   271  		bc <- b{body, err}
   272  	}()
   273  
   274  	// allow some time to stream the stats from the container
   275  	time.Sleep(4 * time.Second)
   276  	if _, err := runCommand(exec.Command(dockerBinary, "rm", "-f", name)); err != nil {
   277  		c.Fatal(err)
   278  	}
   279  
   280  	// collect the results from the stats stream or timeout and fail
   281  	// if the stream was not disconnected.
   282  	select {
   283  	case <-time.After(2 * time.Second):
   284  		c.Fatal("stream was not closed after container was removed")
   285  	case sr := <-bc:
   286  		if sr.err != nil {
   287  			c.Fatal(sr.err)
   288  		}
   289  
   290  		dec := json.NewDecoder(bytes.NewBuffer(sr.body))
   291  		var s *types.Stats
   292  		// decode only one object from the stream
   293  		if err := dec.Decode(&s); err != nil {
   294  			c.Fatal(err)
   295  		}
   296  	}
   297  }
   298  
   299  func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
   300  	var (
   301  		name   = "statscontainer"
   302  		runCmd = exec.Command(dockerBinary, "create", "--name", name, "busybox", "top")
   303  	)
   304  	out, _, err := runCommandWithOutput(runCmd)
   305  	if err != nil {
   306  		c.Fatalf("Error on container creation: %v, output: %q", err, out)
   307  	}
   308  
   309  	go func() {
   310  		// We'll never get return for GET stats from sockRequest as of now,
   311  		// just send request and see if panic or error would happen on daemon side.
   312  		status, _, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
   313  		c.Assert(status, check.Equals, http.StatusOK)
   314  		c.Assert(err, check.IsNil)
   315  	}()
   316  
   317  	// allow some time to send request and let daemon deal with it
   318  	time.Sleep(1 * time.Second)
   319  }
   320  
   321  func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
   322  	// Test to make sure we stop people from trying to leave the
   323  	// build context when specifying the path to the dockerfile
   324  	buffer := new(bytes.Buffer)
   325  	tw := tar.NewWriter(buffer)
   326  	defer tw.Close()
   327  
   328  	dockerfile := []byte("FROM busybox")
   329  	if err := tw.WriteHeader(&tar.Header{
   330  		Name: "Dockerfile",
   331  		Size: int64(len(dockerfile)),
   332  	}); err != nil {
   333  		c.Fatalf("failed to write tar file header: %v", err)
   334  	}
   335  	if _, err := tw.Write(dockerfile); err != nil {
   336  		c.Fatalf("failed to write tar file content: %v", err)
   337  	}
   338  	if err := tw.Close(); err != nil {
   339  		c.Fatalf("failed to close tar archive: %v", err)
   340  	}
   341  
   342  	status, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
   343  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   344  	c.Assert(err, check.IsNil)
   345  
   346  	out, err := readBody(body)
   347  	if err != nil {
   348  		c.Fatal(err)
   349  	}
   350  
   351  	if !strings.Contains(string(out), "must be within the build context") {
   352  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   353  	}
   354  }
   355  
   356  func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
   357  	server, err := fakeStorage(map[string]string{
   358  		"testD": `FROM busybox
   359  COPY * /tmp/
   360  RUN find / -name ba*
   361  RUN find /tmp/`,
   362  	})
   363  	if err != nil {
   364  		c.Fatal(err)
   365  	}
   366  	defer server.Close()
   367  
   368  	status, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
   369  	c.Assert(status, check.Equals, http.StatusOK)
   370  	c.Assert(err, check.IsNil)
   371  
   372  	buf, err := readBody(body)
   373  	if err != nil {
   374  		c.Fatal(err)
   375  	}
   376  
   377  	// Make sure Dockerfile exists.
   378  	// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
   379  	out := string(buf)
   380  	if !strings.Contains(out, "/tmp/Dockerfile") ||
   381  		strings.Contains(out, "baz") {
   382  		c.Fatalf("Incorrect output: %s", out)
   383  	}
   384  }
   385  
   386  func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
   387  	git, err := fakeGIT("repo", map[string]string{
   388  		"dockerfile": `FROM busybox
   389  RUN echo from dockerfile`,
   390  	}, false)
   391  	if err != nil {
   392  		c.Fatal(err)
   393  	}
   394  	defer git.Close()
   395  
   396  	status, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   397  	c.Assert(status, check.Equals, http.StatusOK)
   398  	c.Assert(err, check.IsNil)
   399  
   400  	buf, err := readBody(body)
   401  	if err != nil {
   402  		c.Fatal(err)
   403  	}
   404  
   405  	out := string(buf)
   406  	if !strings.Contains(out, "from dockerfile") {
   407  		c.Fatalf("Incorrect output: %s", out)
   408  	}
   409  }
   410  
   411  func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
   412  	git, err := fakeGIT("repo", map[string]string{
   413  		"baz": `FROM busybox
   414  RUN echo from baz`,
   415  		"Dockerfile": `FROM busybox
   416  RUN echo from Dockerfile`,
   417  	}, false)
   418  	if err != nil {
   419  		c.Fatal(err)
   420  	}
   421  	defer git.Close()
   422  
   423  	// Make sure it tries to 'dockerfile' query param value
   424  	status, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
   425  	c.Assert(status, check.Equals, http.StatusOK)
   426  	c.Assert(err, check.IsNil)
   427  
   428  	buf, err := readBody(body)
   429  	if err != nil {
   430  		c.Fatal(err)
   431  	}
   432  
   433  	out := string(buf)
   434  	if !strings.Contains(out, "from baz") {
   435  		c.Fatalf("Incorrect output: %s", out)
   436  	}
   437  }
   438  
   439  func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
   440  	testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
   441  	git, err := fakeGIT("repo", map[string]string{
   442  		"Dockerfile": `FROM busybox
   443  RUN echo from Dockerfile`,
   444  		"dockerfile": `FROM busybox
   445  RUN echo from dockerfile`,
   446  	}, false)
   447  	if err != nil {
   448  		c.Fatal(err)
   449  	}
   450  	defer git.Close()
   451  
   452  	// Make sure it tries to 'dockerfile' query param value
   453  	status, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   454  	c.Assert(status, check.Equals, http.StatusOK)
   455  	c.Assert(err, check.IsNil)
   456  
   457  	buf, err := readBody(body)
   458  	if err != nil {
   459  		c.Fatal(err)
   460  	}
   461  
   462  	out := string(buf)
   463  	if !strings.Contains(out, "from Dockerfile") {
   464  		c.Fatalf("Incorrect output: %s", out)
   465  	}
   466  }
   467  
   468  func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
   469  	// Test to make sure we stop people from trying to leave the
   470  	// build context when specifying a symlink as the path to the dockerfile
   471  	buffer := new(bytes.Buffer)
   472  	tw := tar.NewWriter(buffer)
   473  	defer tw.Close()
   474  
   475  	if err := tw.WriteHeader(&tar.Header{
   476  		Name:     "Dockerfile",
   477  		Typeflag: tar.TypeSymlink,
   478  		Linkname: "/etc/passwd",
   479  	}); err != nil {
   480  		c.Fatalf("failed to write tar file header: %v", err)
   481  	}
   482  	if err := tw.Close(); err != nil {
   483  		c.Fatalf("failed to close tar archive: %v", err)
   484  	}
   485  
   486  	status, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
   487  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   488  	c.Assert(err, check.IsNil)
   489  
   490  	out, err := readBody(body)
   491  	if err != nil {
   492  		c.Fatal(err)
   493  	}
   494  
   495  	// The reason the error is "Cannot locate specified Dockerfile" is because
   496  	// in the builder, the symlink is resolved within the context, therefore
   497  	// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
   498  	// a nonexistent file.
   499  	if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") {
   500  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   501  	}
   502  }
   503  
   504  // #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
   505  func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) {
   506  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=one", "busybox"))
   507  	if err != nil {
   508  		c.Fatal(err, out)
   509  	}
   510  
   511  	fooDir, err := inspectFieldMap("one", "Volumes", "/foo")
   512  	if err != nil {
   513  		c.Fatal(err)
   514  	}
   515  
   516  	out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=two", "busybox"))
   517  	if err != nil {
   518  		c.Fatal(err, out)
   519  	}
   520  
   521  	bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}}
   522  	status, _, err := sockRequest("POST", "/containers/two/start", bindSpec)
   523  	c.Assert(status, check.Equals, http.StatusNoContent)
   524  	c.Assert(err, check.IsNil)
   525  
   526  	fooDir2, err := inspectFieldMap("two", "Volumes", "/foo")
   527  	if err != nil {
   528  		c.Fatal(err)
   529  	}
   530  
   531  	if fooDir2 != fooDir {
   532  		c.Fatalf("expected volume path to be %s, got: %s", fooDir, fooDir2)
   533  	}
   534  }
   535  
   536  func (s *DockerSuite) TestContainerApiPause(c *check.C) {
   537  	defer unpauseAllContainers()
   538  	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep", "30")
   539  	out, _, err := runCommandWithOutput(runCmd)
   540  
   541  	if err != nil {
   542  		c.Fatalf("failed to create a container: %s, %v", out, err)
   543  	}
   544  	ContainerID := strings.TrimSpace(out)
   545  
   546  	status, _, err := sockRequest("POST", "/containers/"+ContainerID+"/pause", nil)
   547  	c.Assert(status, check.Equals, http.StatusNoContent)
   548  	c.Assert(err, check.IsNil)
   549  
   550  	pausedContainers, err := getSliceOfPausedContainers()
   551  
   552  	if err != nil {
   553  		c.Fatalf("error thrown while checking if containers were paused: %v", err)
   554  	}
   555  
   556  	if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] {
   557  		c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
   558  	}
   559  
   560  	status, _, err = sockRequest("POST", "/containers/"+ContainerID+"/unpause", nil)
   561  	c.Assert(status, check.Equals, http.StatusNoContent)
   562  	c.Assert(err, check.IsNil)
   563  
   564  	pausedContainers, err = getSliceOfPausedContainers()
   565  
   566  	if err != nil {
   567  		c.Fatalf("error thrown while checking if containers were paused: %v", err)
   568  	}
   569  
   570  	if pausedContainers != nil {
   571  		c.Fatalf("There should be no paused container.")
   572  	}
   573  }
   574  
   575  func (s *DockerSuite) TestContainerApiTop(c *check.C) {
   576  	out, err := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", "top").CombinedOutput()
   577  	if err != nil {
   578  		c.Fatal(err, out)
   579  	}
   580  	id := strings.TrimSpace(string(out))
   581  	if err := waitRun(id); err != nil {
   582  		c.Fatal(err)
   583  	}
   584  
   585  	type topResp struct {
   586  		Titles    []string
   587  		Processes [][]string
   588  	}
   589  	var top topResp
   590  	status, b, err := sockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil)
   591  	c.Assert(status, check.Equals, http.StatusOK)
   592  	c.Assert(err, check.IsNil)
   593  
   594  	if err := json.Unmarshal(b, &top); err != nil {
   595  		c.Fatal(err)
   596  	}
   597  
   598  	if len(top.Titles) != 11 {
   599  		c.Fatalf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles)
   600  	}
   601  
   602  	if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" {
   603  		c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles)
   604  	}
   605  	if len(top.Processes) != 2 {
   606  		c.Fatalf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes)
   607  	}
   608  	if top.Processes[0][10] != "/bin/sh -c top" {
   609  		c.Fatalf("expected `/bin/sh -c top`, found: %s", top.Processes[0][10])
   610  	}
   611  	if top.Processes[1][10] != "top" {
   612  		c.Fatalf("expected `top`, found: %s", top.Processes[1][10])
   613  	}
   614  }
   615  
   616  func (s *DockerSuite) TestContainerApiCommit(c *check.C) {
   617  	cName := "testapicommit"
   618  	out, err := exec.Command(dockerBinary, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test").CombinedOutput()
   619  	if err != nil {
   620  		c.Fatal(err, out)
   621  	}
   622  
   623  	name := "TestContainerApiCommit"
   624  	status, b, err := sockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil)
   625  	c.Assert(status, check.Equals, http.StatusCreated)
   626  	c.Assert(err, check.IsNil)
   627  
   628  	type resp struct {
   629  		Id string
   630  	}
   631  	var img resp
   632  	if err := json.Unmarshal(b, &img); err != nil {
   633  		c.Fatal(err)
   634  	}
   635  
   636  	cmd, err := inspectField(img.Id, "Config.Cmd")
   637  	if err != nil {
   638  		c.Fatal(err)
   639  	}
   640  	if cmd != "{[/bin/sh -c touch /test]}" {
   641  		c.Fatalf("got wrong Cmd from commit: %q", cmd)
   642  	}
   643  	// sanity check, make sure the image is what we think it is
   644  	out, err = exec.Command(dockerBinary, "run", img.Id, "ls", "/test").CombinedOutput()
   645  	if err != nil {
   646  		c.Fatalf("error checking committed image: %v - %q", err, string(out))
   647  	}
   648  }
   649  
   650  func (s *DockerSuite) TestContainerApiCreate(c *check.C) {
   651  	config := map[string]interface{}{
   652  		"Image": "busybox",
   653  		"Cmd":   []string{"/bin/sh", "-c", "touch /test && ls /test"},
   654  	}
   655  
   656  	status, b, err := sockRequest("POST", "/containers/create", config)
   657  	c.Assert(status, check.Equals, http.StatusCreated)
   658  	c.Assert(err, check.IsNil)
   659  
   660  	type createResp struct {
   661  		Id string
   662  	}
   663  	var container createResp
   664  	if err := json.Unmarshal(b, &container); err != nil {
   665  		c.Fatal(err)
   666  	}
   667  
   668  	out, err := exec.Command(dockerBinary, "start", "-a", container.Id).CombinedOutput()
   669  	if err != nil {
   670  		c.Fatal(out, err)
   671  	}
   672  	if strings.TrimSpace(string(out)) != "/test" {
   673  		c.Fatalf("expected output `/test`, got %q", out)
   674  	}
   675  }
   676  
   677  func (s *DockerSuite) TestContainerApiCreateWithHostName(c *check.C) {
   678  	var hostName = "test-host"
   679  	config := map[string]interface{}{
   680  		"Image":    "busybox",
   681  		"Hostname": hostName,
   682  	}
   683  
   684  	_, b, err := sockRequest("POST", "/containers/create", config)
   685  	if err != nil && !strings.Contains(err.Error(), "200 OK: 201") {
   686  		c.Fatal(err)
   687  	}
   688  	type createResp struct {
   689  		Id string
   690  	}
   691  	var container createResp
   692  	if err := json.Unmarshal(b, &container); err != nil {
   693  		c.Fatal(err)
   694  	}
   695  
   696  	var id = container.Id
   697  
   698  	_, bodyGet, err := sockRequest("GET", "/containers/"+id+"/json", nil)
   699  
   700  	type configLocal struct {
   701  		Hostname string
   702  	}
   703  	type getResponse struct {
   704  		Id     string
   705  		Config configLocal
   706  	}
   707  
   708  	var containerInfo getResponse
   709  	if err := json.Unmarshal(bodyGet, &containerInfo); err != nil {
   710  		c.Fatal(err)
   711  	}
   712  	var hostNameActual = containerInfo.Config.Hostname
   713  	if hostNameActual != "test-host" {
   714  		c.Fatalf("Mismatched Hostname, Expected %v, Actual: %v ", hostName, hostNameActual)
   715  	}
   716  }
   717  
   718  func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) {
   719  	config := map[string]interface{}{
   720  		"Image": "busybox",
   721  	}
   722  
   723  	create := func(ct string) (int, io.ReadCloser, error) {
   724  		jsonData := bytes.NewBuffer(nil)
   725  		if err := json.NewEncoder(jsonData).Encode(config); err != nil {
   726  			c.Fatal(err)
   727  		}
   728  		return sockRequestRaw("POST", "/containers/create", jsonData, ct)
   729  	}
   730  
   731  	// Try with no content-type
   732  	status, body, err := create("")
   733  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   734  	c.Assert(err, check.IsNil)
   735  	body.Close()
   736  
   737  	// Try with wrong content-type
   738  	status, body, err = create("application/xml")
   739  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   740  	c.Assert(err, check.IsNil)
   741  	body.Close()
   742  
   743  	// now application/json
   744  	status, body, err = create("application/json")
   745  	c.Assert(status, check.Equals, http.StatusCreated)
   746  	c.Assert(err, check.IsNil)
   747  	body.Close()
   748  }
   749  
   750  // Issue 7941 - test to make sure a "null" in JSON is just ignored.
   751  // W/o this fix a null in JSON would be parsed into a string var as "null"
   752  func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) {
   753  	config := `{
   754  		"Hostname":"",
   755  		"Domainname":"",
   756  		"Memory":0,
   757  		"MemorySwap":0,
   758  		"CpuShares":0,
   759  		"Cpuset":null,
   760  		"AttachStdin":true,
   761  		"AttachStdout":true,
   762  		"AttachStderr":true,
   763  		"PortSpecs":null,
   764  		"ExposedPorts":{},
   765  		"Tty":true,
   766  		"OpenStdin":true,
   767  		"StdinOnce":true,
   768  		"Env":[],
   769  		"Cmd":"ls",
   770  		"Image":"busybox",
   771  		"Volumes":{},
   772  		"WorkingDir":"",
   773  		"Entrypoint":null,
   774  		"NetworkDisabled":false,
   775  		"OnBuild":null}`
   776  
   777  	status, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
   778  	c.Assert(status, check.Equals, http.StatusCreated)
   779  	c.Assert(err, check.IsNil)
   780  
   781  	b, err := readBody(body)
   782  	if err != nil {
   783  		c.Fatal(err)
   784  	}
   785  	type createResp struct {
   786  		Id string
   787  	}
   788  	var container createResp
   789  	if err := json.Unmarshal(b, &container); err != nil {
   790  		c.Fatal(err)
   791  	}
   792  
   793  	out, err := inspectField(container.Id, "HostConfig.CpusetCpus")
   794  	if err != nil {
   795  		c.Fatal(err, out)
   796  	}
   797  	if out != "" {
   798  		c.Fatalf("expected empty string, got %q", out)
   799  	}
   800  }
   801  
   802  func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) {
   803  	config := `{
   804  		"Image":     "busybox",
   805  		"Cmd":       "ls",
   806  		"OpenStdin": true,
   807  		"CpuShares": 100,
   808  		"Memory":    524287
   809  	}`
   810  
   811  	status, body, _ := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
   812  	b, err2 := readBody(body)
   813  	if err2 != nil {
   814  		c.Fatal(err2)
   815  	}
   816  
   817  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   818  	c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
   819  }
   820  
   821  func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) {
   822  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "busybox"))
   823  	if err != nil {
   824  		c.Fatal(err, out)
   825  	}
   826  
   827  	containerID := strings.TrimSpace(out)
   828  
   829  	config := `{
   830                  "CpuShares": 100,
   831                  "Memory":    524287
   832          }`
   833  
   834  	status, body, _ := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
   835  	b, err2 := readBody(body)
   836  	if err2 != nil {
   837  		c.Fatal(err2)
   838  	}
   839  
   840  	c.Assert(status, check.Equals, http.StatusInternalServerError)
   841  	c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
   842  }
   843  
   844  func (s *DockerSuite) TestContainerApiRename(c *check.C) {
   845  	runCmd := exec.Command(dockerBinary, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh")
   846  	out, _, err := runCommandWithOutput(runCmd)
   847  	c.Assert(err, check.IsNil)
   848  
   849  	containerID := strings.TrimSpace(out)
   850  	newName := "TestContainerApiRenameNew"
   851  	statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil)
   852  
   853  	// 204 No Content is expected, not 200
   854  	c.Assert(statusCode, check.Equals, http.StatusNoContent)
   855  	c.Assert(err, check.IsNil)
   856  
   857  	name, err := inspectField(containerID, "Name")
   858  	if name != "/"+newName {
   859  		c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name)
   860  	}
   861  }