github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/integration-cli/docker_api_containers_test.go (about)

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