github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/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/api/types"
    19  	"github.com/docker/docker/pkg/integration"
    20  	"github.com/docker/docker/pkg/integration/checker"
    21  	"github.com/docker/docker/pkg/stringid"
    22  	"github.com/docker/docker/runconfig"
    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) TestContainerApiCreateNetworkMode(c *check.C) {
   656  	testRequires(c, DaemonIsLinux)
   657  	UtilCreateNetworkMode(c, "host")
   658  	UtilCreateNetworkMode(c, "bridge")
   659  	UtilCreateNetworkMode(c, "container:web1")
   660  }
   661  
   662  func UtilCreateNetworkMode(c *check.C, networkMode string) {
   663  	config := map[string]interface{}{
   664  		"Image":      "busybox",
   665  		"HostConfig": map[string]interface{}{"NetworkMode": networkMode},
   666  	}
   667  
   668  	status, body, err := sockRequest("POST", "/containers/create", config)
   669  	c.Assert(err, checker.IsNil)
   670  	c.Assert(status, checker.Equals, http.StatusCreated)
   671  
   672  	var container types.ContainerCreateResponse
   673  	c.Assert(json.Unmarshal(body, &container), checker.IsNil)
   674  
   675  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
   676  	c.Assert(err, checker.IsNil)
   677  	c.Assert(status, checker.Equals, http.StatusOK)
   678  
   679  	var containerJSON types.ContainerJSON
   680  	c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil)
   681  	c.Assert(containerJSON.HostConfig.NetworkMode, checker.Equals, runconfig.NetworkMode(networkMode), check.Commentf("Mismatched NetworkMode"))
   682  }
   683  
   684  func (s *DockerSuite) TestContainerApiCreateWithCpuSharesCpuset(c *check.C) {
   685  	testRequires(c, DaemonIsLinux)
   686  	config := map[string]interface{}{
   687  		"Image":      "busybox",
   688  		"CpuShares":  512,
   689  		"CpusetCpus": "0",
   690  	}
   691  
   692  	status, body, err := sockRequest("POST", "/containers/create", config)
   693  	c.Assert(err, checker.IsNil)
   694  	c.Assert(status, checker.Equals, http.StatusCreated)
   695  
   696  	var container types.ContainerCreateResponse
   697  	c.Assert(json.Unmarshal(body, &container), checker.IsNil)
   698  
   699  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
   700  	c.Assert(err, checker.IsNil)
   701  	c.Assert(status, checker.Equals, http.StatusOK)
   702  
   703  	var containerJSON types.ContainerJSON
   704  
   705  	c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil)
   706  
   707  	out, err := inspectField(containerJSON.ID, "HostConfig.CpuShares")
   708  	c.Assert(err, checker.IsNil)
   709  	c.Assert(out, checker.Equals, "512")
   710  
   711  	outCpuset, errCpuset := inspectField(containerJSON.ID, "HostConfig.CpusetCpus")
   712  	c.Assert(errCpuset, checker.IsNil, check.Commentf("Output: %s", outCpuset))
   713  	c.Assert(outCpuset, checker.Equals, "0")
   714  }
   715  
   716  func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) {
   717  	testRequires(c, DaemonIsLinux)
   718  	config := map[string]interface{}{
   719  		"Image": "busybox",
   720  	}
   721  
   722  	create := func(ct string) (*http.Response, io.ReadCloser, error) {
   723  		jsonData := bytes.NewBuffer(nil)
   724  		c.Assert(json.NewEncoder(jsonData).Encode(config), checker.IsNil)
   725  		return sockRequestRaw("POST", "/containers/create", jsonData, ct)
   726  	}
   727  
   728  	// Try with no content-type
   729  	res, body, err := create("")
   730  	c.Assert(err, checker.IsNil)
   731  	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
   732  	body.Close()
   733  
   734  	// Try with wrong content-type
   735  	res, body, err = create("application/xml")
   736  	c.Assert(err, checker.IsNil)
   737  	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
   738  	body.Close()
   739  
   740  	// now application/json
   741  	res, body, err = create("application/json")
   742  	c.Assert(err, checker.IsNil)
   743  	c.Assert(res.StatusCode, checker.Equals, http.StatusCreated)
   744  	body.Close()
   745  }
   746  
   747  //Issue 14230. daemon should return 500 for invalid port syntax
   748  func (s *DockerSuite) TestContainerApiInvalidPortSyntax(c *check.C) {
   749  	testRequires(c, DaemonIsLinux)
   750  	config := `{
   751  				  "Image": "busybox",
   752  				  "HostConfig": {
   753  					"PortBindings": {
   754  					  "19039;1230": [
   755  						{}
   756  					  ]
   757  					}
   758  				  }
   759  				}`
   760  
   761  	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
   762  	c.Assert(err, checker.IsNil)
   763  	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
   764  
   765  	b, err := readBody(body)
   766  	c.Assert(err, checker.IsNil)
   767  	c.Assert(string(b[:]), checker.Contains, "Invalid port")
   768  }
   769  
   770  // Issue 7941 - test to make sure a "null" in JSON is just ignored.
   771  // W/o this fix a null in JSON would be parsed into a string var as "null"
   772  func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) {
   773  	testRequires(c, DaemonIsLinux)
   774  	config := `{
   775  		"Hostname":"",
   776  		"Domainname":"",
   777  		"Memory":0,
   778  		"MemorySwap":0,
   779  		"CpuShares":0,
   780  		"Cpuset":null,
   781  		"AttachStdin":true,
   782  		"AttachStdout":true,
   783  		"AttachStderr":true,
   784  		"ExposedPorts":{},
   785  		"Tty":true,
   786  		"OpenStdin":true,
   787  		"StdinOnce":true,
   788  		"Env":[],
   789  		"Cmd":"ls",
   790  		"Image":"busybox",
   791  		"Volumes":{},
   792  		"WorkingDir":"",
   793  		"Entrypoint":null,
   794  		"NetworkDisabled":false,
   795  		"OnBuild":null}`
   796  
   797  	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
   798  	c.Assert(err, checker.IsNil)
   799  	c.Assert(res.StatusCode, checker.Equals, http.StatusCreated)
   800  
   801  	b, err := readBody(body)
   802  	c.Assert(err, checker.IsNil)
   803  	type createResp struct {
   804  		ID string
   805  	}
   806  	var container createResp
   807  	c.Assert(json.Unmarshal(b, &container), checker.IsNil)
   808  
   809  	out, err := inspectField(container.ID, "HostConfig.CpusetCpus")
   810  	c.Assert(err, checker.IsNil)
   811  	c.Assert(out, checker.Equals, "")
   812  
   813  	outMemory, errMemory := inspectField(container.ID, "HostConfig.Memory")
   814  	c.Assert(outMemory, checker.Equals, "0")
   815  	c.Assert(errMemory, checker.IsNil)
   816  	outMemorySwap, errMemorySwap := inspectField(container.ID, "HostConfig.MemorySwap")
   817  	c.Assert(outMemorySwap, checker.Equals, "0")
   818  	c.Assert(errMemorySwap, checker.IsNil)
   819  }
   820  
   821  func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) {
   822  	testRequires(c, DaemonIsLinux)
   823  	config := `{
   824  		"Image":     "busybox",
   825  		"Cmd":       "ls",
   826  		"OpenStdin": true,
   827  		"CpuShares": 100,
   828  		"Memory":    524287
   829  	}`
   830  
   831  	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
   832  	c.Assert(err, checker.IsNil)
   833  	b, err2 := readBody(body)
   834  	c.Assert(err2, checker.IsNil)
   835  
   836  	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
   837  	c.Assert(string(b), checker.Contains, "Minimum memory limit allowed is 4MB")
   838  }
   839  
   840  func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) {
   841  	testRequires(c, DaemonIsLinux)
   842  	out, _ := dockerCmd(c, "create", "busybox")
   843  
   844  	containerID := strings.TrimSpace(out)
   845  
   846  	config := `{
   847                  "CpuShares": 100,
   848                  "Memory":    524287
   849          }`
   850  
   851  	res, body, err := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
   852  	c.Assert(err, checker.IsNil)
   853  	b, err2 := readBody(body)
   854  	c.Assert(err2, checker.IsNil)
   855  	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
   856  	c.Assert(string(b), checker.Contains, "Minimum memory limit allowed is 4MB")
   857  }
   858  
   859  func (s *DockerSuite) TestContainerApiRename(c *check.C) {
   860  	testRequires(c, DaemonIsLinux)
   861  	out, _ := dockerCmd(c, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh")
   862  
   863  	containerID := strings.TrimSpace(out)
   864  	newName := "TestContainerApiRenameNew"
   865  	statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil)
   866  	c.Assert(err, checker.IsNil)
   867  	// 204 No Content is expected, not 200
   868  	c.Assert(statusCode, checker.Equals, http.StatusNoContent)
   869  
   870  	name, err := inspectField(containerID, "Name")
   871  	c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container"))
   872  }
   873  
   874  func (s *DockerSuite) TestContainerApiKill(c *check.C) {
   875  	testRequires(c, DaemonIsLinux)
   876  	name := "test-api-kill"
   877  	dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
   878  
   879  	status, _, err := sockRequest("POST", "/containers/"+name+"/kill", nil)
   880  	c.Assert(err, checker.IsNil)
   881  	c.Assert(status, checker.Equals, http.StatusNoContent)
   882  
   883  	state, err := inspectField(name, "State.Running")
   884  	c.Assert(err, checker.IsNil)
   885  	c.Assert(state, checker.Equals, "false", check.Commentf("got wrong State from container %s: %q", name, state))
   886  }
   887  
   888  func (s *DockerSuite) TestContainerApiRestart(c *check.C) {
   889  	testRequires(c, DaemonIsLinux)
   890  	name := "test-api-restart"
   891  	dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
   892  
   893  	status, _, err := sockRequest("POST", "/containers/"+name+"/restart?t=1", nil)
   894  	c.Assert(err, checker.IsNil)
   895  	c.Assert(status, checker.Equals, http.StatusNoContent)
   896  	c.Assert(waitInspect(name, "{{ .State.Restarting  }} {{ .State.Running  }}", "false true", 5*time.Second), checker.IsNil)
   897  }
   898  
   899  func (s *DockerSuite) TestContainerApiRestartNotimeoutParam(c *check.C) {
   900  	testRequires(c, DaemonIsLinux)
   901  	name := "test-api-restart-no-timeout-param"
   902  	out, _ := dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
   903  	id := strings.TrimSpace(out)
   904  	c.Assert(waitRun(id), checker.IsNil)
   905  
   906  	status, _, err := sockRequest("POST", "/containers/"+name+"/restart", nil)
   907  	c.Assert(err, checker.IsNil)
   908  	c.Assert(status, checker.Equals, http.StatusNoContent)
   909  	c.Assert(waitInspect(name, "{{ .State.Restarting  }} {{ .State.Running  }}", "false true", 5*time.Second), checker.IsNil)
   910  }
   911  
   912  func (s *DockerSuite) TestContainerApiStart(c *check.C) {
   913  	testRequires(c, DaemonIsLinux)
   914  	name := "testing-start"
   915  	config := map[string]interface{}{
   916  		"Image":     "busybox",
   917  		"Cmd":       []string{"/bin/sh", "-c", "/bin/top"},
   918  		"OpenStdin": true,
   919  	}
   920  
   921  	status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
   922  	c.Assert(err, checker.IsNil)
   923  	c.Assert(status, checker.Equals, http.StatusCreated)
   924  
   925  	conf := make(map[string]interface{})
   926  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
   927  	c.Assert(err, checker.IsNil)
   928  	c.Assert(status, checker.Equals, http.StatusNoContent)
   929  
   930  	// second call to start should give 304
   931  	status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
   932  	c.Assert(err, checker.IsNil)
   933  	c.Assert(status, checker.Equals, http.StatusNotModified)
   934  }
   935  
   936  func (s *DockerSuite) TestContainerApiStop(c *check.C) {
   937  	testRequires(c, DaemonIsLinux)
   938  	name := "test-api-stop"
   939  	dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
   940  
   941  	status, _, err := sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
   942  	c.Assert(err, checker.IsNil)
   943  	c.Assert(status, checker.Equals, http.StatusNoContent)
   944  	c.Assert(waitInspect(name, "{{ .State.Running  }}", "false", 5*time.Second), checker.IsNil)
   945  
   946  	// second call to start should give 304
   947  	status, _, err = sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
   948  	c.Assert(err, checker.IsNil)
   949  	c.Assert(status, checker.Equals, http.StatusNotModified)
   950  }
   951  
   952  func (s *DockerSuite) TestContainerApiWait(c *check.C) {
   953  	testRequires(c, DaemonIsLinux)
   954  	name := "test-api-wait"
   955  	dockerCmd(c, "run", "--name", name, "busybox", "sleep", "5")
   956  
   957  	status, body, err := sockRequest("POST", "/containers/"+name+"/wait", nil)
   958  	c.Assert(err, checker.IsNil)
   959  	c.Assert(status, checker.Equals, http.StatusOK)
   960  	c.Assert(waitInspect(name, "{{ .State.Running  }}", "false", 5*time.Second), checker.IsNil)
   961  
   962  	var waitres types.ContainerWaitResponse
   963  	c.Assert(json.Unmarshal(body, &waitres), checker.IsNil)
   964  	c.Assert(waitres.StatusCode, checker.Equals, 0)
   965  }
   966  
   967  func (s *DockerSuite) TestContainerApiCopy(c *check.C) {
   968  	testRequires(c, DaemonIsLinux)
   969  	name := "test-container-api-copy"
   970  	dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
   971  
   972  	postData := types.CopyConfig{
   973  		Resource: "/test.txt",
   974  	}
   975  
   976  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
   977  	c.Assert(err, checker.IsNil)
   978  	c.Assert(status, checker.Equals, http.StatusOK)
   979  
   980  	found := false
   981  	for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
   982  		h, err := tarReader.Next()
   983  		if err != nil {
   984  			if err == io.EOF {
   985  				break
   986  			}
   987  			c.Fatal(err)
   988  		}
   989  		if h.Name == "test.txt" {
   990  			found = true
   991  			break
   992  		}
   993  	}
   994  	c.Assert(found, checker.True)
   995  }
   996  
   997  func (s *DockerSuite) TestContainerApiCopyResourcePathEmpty(c *check.C) {
   998  	testRequires(c, DaemonIsLinux)
   999  	name := "test-container-api-copy-resource-empty"
  1000  	dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
  1001  
  1002  	postData := types.CopyConfig{
  1003  		Resource: "",
  1004  	}
  1005  
  1006  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1007  	c.Assert(err, checker.IsNil)
  1008  	c.Assert(status, checker.Equals, http.StatusInternalServerError)
  1009  	c.Assert(string(body), checker.Matches, "Path cannot be empty\n")
  1010  }
  1011  
  1012  func (s *DockerSuite) TestContainerApiCopyResourcePathNotFound(c *check.C) {
  1013  	testRequires(c, DaemonIsLinux)
  1014  	name := "test-container-api-copy-resource-not-found"
  1015  	dockerCmd(c, "run", "--name", name, "busybox")
  1016  
  1017  	postData := types.CopyConfig{
  1018  		Resource: "/notexist",
  1019  	}
  1020  
  1021  	status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  1022  	c.Assert(err, checker.IsNil)
  1023  	c.Assert(status, checker.Equals, http.StatusInternalServerError)
  1024  	c.Assert(string(body), checker.Matches, "Could not find the file /notexist in container "+name+"\n")
  1025  }
  1026  
  1027  func (s *DockerSuite) TestContainerApiCopyContainerNotFound(c *check.C) {
  1028  	postData := types.CopyConfig{
  1029  		Resource: "/something",
  1030  	}
  1031  
  1032  	status, _, err := sockRequest("POST", "/containers/notexists/copy", postData)
  1033  	c.Assert(err, checker.IsNil)
  1034  	c.Assert(status, checker.Equals, http.StatusNotFound)
  1035  }
  1036  
  1037  func (s *DockerSuite) TestContainerApiDelete(c *check.C) {
  1038  	testRequires(c, DaemonIsLinux)
  1039  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1040  
  1041  	id := strings.TrimSpace(out)
  1042  	c.Assert(waitRun(id), checker.IsNil)
  1043  
  1044  	dockerCmd(c, "stop", id)
  1045  
  1046  	status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  1047  	c.Assert(err, checker.IsNil)
  1048  	c.Assert(status, checker.Equals, http.StatusNoContent)
  1049  }
  1050  
  1051  func (s *DockerSuite) TestContainerApiDeleteNotExist(c *check.C) {
  1052  	status, body, err := sockRequest("DELETE", "/containers/doesnotexist", nil)
  1053  	c.Assert(err, checker.IsNil)
  1054  	c.Assert(status, checker.Equals, http.StatusNotFound)
  1055  	c.Assert(string(body), checker.Matches, "No such container: doesnotexist\n")
  1056  }
  1057  
  1058  func (s *DockerSuite) TestContainerApiDeleteForce(c *check.C) {
  1059  	testRequires(c, DaemonIsLinux)
  1060  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1061  
  1062  	id := strings.TrimSpace(out)
  1063  	c.Assert(waitRun(id), checker.IsNil)
  1064  
  1065  	status, _, err := sockRequest("DELETE", "/containers/"+id+"?force=1", nil)
  1066  	c.Assert(err, checker.IsNil)
  1067  	c.Assert(status, checker.Equals, http.StatusNoContent)
  1068  }
  1069  
  1070  func (s *DockerSuite) TestContainerApiDeleteRemoveLinks(c *check.C) {
  1071  	testRequires(c, DaemonIsLinux)
  1072  	out, _ := dockerCmd(c, "run", "-d", "--name", "tlink1", "busybox", "top")
  1073  
  1074  	id := strings.TrimSpace(out)
  1075  	c.Assert(waitRun(id), checker.IsNil)
  1076  
  1077  	out, _ = dockerCmd(c, "run", "--link", "tlink1:tlink1", "--name", "tlink2", "-d", "busybox", "top")
  1078  
  1079  	id2 := strings.TrimSpace(out)
  1080  	c.Assert(waitRun(id2), checker.IsNil)
  1081  
  1082  	links, err := inspectFieldJSON(id2, "HostConfig.Links")
  1083  	c.Assert(err, checker.IsNil)
  1084  	c.Assert(links, checker.Equals, "[\"/tlink1:/tlink2/tlink1\"]", check.Commentf("expected to have links between containers"))
  1085  
  1086  	status, _, err := sockRequest("DELETE", "/containers/tlink2/tlink1?link=1", nil)
  1087  	c.Assert(err, checker.IsNil)
  1088  	c.Assert(status, checker.Equals, http.StatusNoContent)
  1089  
  1090  	linksPostRm, err := inspectFieldJSON(id2, "HostConfig.Links")
  1091  	c.Assert(err, checker.IsNil)
  1092  	c.Assert(linksPostRm, checker.Equals, "null", check.Commentf("call to api deleteContainer links should have removed the specified links"))
  1093  }
  1094  
  1095  func (s *DockerSuite) TestContainerApiDeleteConflict(c *check.C) {
  1096  	testRequires(c, DaemonIsLinux)
  1097  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1098  
  1099  	id := strings.TrimSpace(out)
  1100  	c.Assert(waitRun(id), checker.IsNil)
  1101  
  1102  	status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  1103  	c.Assert(err, checker.IsNil)
  1104  	c.Assert(status, checker.Equals, http.StatusConflict)
  1105  }
  1106  
  1107  func (s *DockerSuite) TestContainerApiDeleteRemoveVolume(c *check.C) {
  1108  	testRequires(c, DaemonIsLinux)
  1109  	testRequires(c, SameHostDaemon)
  1110  
  1111  	out, _ := dockerCmd(c, "run", "-d", "-v", "/testvolume", "busybox", "top")
  1112  
  1113  	id := strings.TrimSpace(out)
  1114  	c.Assert(waitRun(id), checker.IsNil)
  1115  
  1116  	source, err := inspectMountSourceField(id, "/testvolume")
  1117  	_, err = os.Stat(source)
  1118  	c.Assert(err, checker.IsNil)
  1119  
  1120  	status, _, err := sockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil)
  1121  	c.Assert(err, checker.IsNil)
  1122  	c.Assert(status, checker.Equals, http.StatusNoContent)
  1123  	_, err = os.Stat(source)
  1124  	c.Assert(os.IsNotExist(err), checker.True, check.Commentf("expected to get ErrNotExist error, got %v", err))
  1125  }
  1126  
  1127  // Regression test for https://github.com/docker/docker/issues/6231
  1128  func (s *DockerSuite) TestContainersApiChunkedEncoding(c *check.C) {
  1129  	testRequires(c, DaemonIsLinux)
  1130  	out, _ := dockerCmd(c, "create", "-v", "/foo", "busybox", "true")
  1131  	id := strings.TrimSpace(out)
  1132  
  1133  	conn, err := sockConn(time.Duration(10 * time.Second))
  1134  	c.Assert(err, checker.IsNil)
  1135  	client := httputil.NewClientConn(conn, nil)
  1136  	defer client.Close()
  1137  
  1138  	bindCfg := strings.NewReader(`{"Binds": ["/tmp:/foo"]}`)
  1139  	req, err := http.NewRequest("POST", "/containers/"+id+"/start", bindCfg)
  1140  	c.Assert(err, checker.IsNil)
  1141  	req.Header.Set("Content-Type", "application/json")
  1142  	// This is a cheat to make the http request do chunked encoding
  1143  	// Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
  1144  	// https://golang.org/src/pkg/net/http/request.go?s=11980:12172
  1145  	req.ContentLength = -1
  1146  
  1147  	resp, err := client.Do(req)
  1148  	c.Assert(err, checker.IsNil, check.Commentf("error starting container with chunked encoding"))
  1149  	resp.Body.Close()
  1150  	c.Assert(resp.StatusCode, checker.Equals, 204)
  1151  
  1152  	out, err = inspectFieldJSON(id, "HostConfig.Binds")
  1153  	c.Assert(err, checker.IsNil)
  1154  
  1155  	var binds []string
  1156  	c.Assert(json.NewDecoder(strings.NewReader(out)).Decode(&binds), checker.IsNil)
  1157  	c.Assert(binds, checker.HasLen, 1, check.Commentf("Got unexpected binds: %v", binds))
  1158  
  1159  	expected := "/tmp:/foo"
  1160  	c.Assert(binds[0], checker.Equals, expected, check.Commentf("got incorrect bind spec"))
  1161  }
  1162  
  1163  func (s *DockerSuite) TestPostContainerStop(c *check.C) {
  1164  	testRequires(c, DaemonIsLinux)
  1165  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1166  
  1167  	containerID := strings.TrimSpace(out)
  1168  	c.Assert(waitRun(containerID), checker.IsNil)
  1169  
  1170  	statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/stop", nil)
  1171  	c.Assert(err, checker.IsNil)
  1172  	// 204 No Content is expected, not 200
  1173  	c.Assert(statusCode, checker.Equals, http.StatusNoContent)
  1174  	c.Assert(waitInspect(containerID, "{{ .State.Running  }}", "false", 5*time.Second), checker.IsNil)
  1175  }
  1176  
  1177  // #14170
  1178  func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceEntrypoint(c *check.C) {
  1179  	testRequires(c, DaemonIsLinux)
  1180  	config := struct {
  1181  		Image      string
  1182  		Entrypoint string
  1183  		Cmd        []string
  1184  	}{"busybox", "echo", []string{"hello", "world"}}
  1185  	_, _, err := sockRequest("POST", "/containers/create?name=echotest", config)
  1186  	c.Assert(err, checker.IsNil)
  1187  	out, _ := dockerCmd(c, "start", "-a", "echotest")
  1188  	c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1189  
  1190  	config2 := struct {
  1191  		Image      string
  1192  		Entrypoint []string
  1193  		Cmd        []string
  1194  	}{"busybox", []string{"echo"}, []string{"hello", "world"}}
  1195  	_, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2)
  1196  	c.Assert(err, checker.IsNil)
  1197  	out, _ = dockerCmd(c, "start", "-a", "echotest2")
  1198  	c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1199  }
  1200  
  1201  // #14170
  1202  func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *check.C) {
  1203  	testRequires(c, DaemonIsLinux)
  1204  	config := struct {
  1205  		Image      string
  1206  		Entrypoint string
  1207  		Cmd        string
  1208  	}{"busybox", "echo", "hello world"}
  1209  	_, _, err := sockRequest("POST", "/containers/create?name=echotest", config)
  1210  	c.Assert(err, checker.IsNil)
  1211  	out, _ := dockerCmd(c, "start", "-a", "echotest")
  1212  	c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1213  
  1214  	config2 := struct {
  1215  		Image string
  1216  		Cmd   []string
  1217  	}{"busybox", []string{"echo", "hello", "world"}}
  1218  	_, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2)
  1219  	c.Assert(err, checker.IsNil)
  1220  	out, _ = dockerCmd(c, "start", "-a", "echotest2")
  1221  	c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1222  }
  1223  
  1224  // regression #14318
  1225  func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *check.C) {
  1226  	testRequires(c, DaemonIsLinux)
  1227  	config := struct {
  1228  		Image   string
  1229  		CapAdd  string
  1230  		CapDrop string
  1231  	}{"busybox", "NET_ADMIN", "SYS_ADMIN"}
  1232  	status, _, err := sockRequest("POST", "/containers/create?name=capaddtest0", config)
  1233  	c.Assert(err, checker.IsNil)
  1234  	c.Assert(status, checker.Equals, http.StatusCreated)
  1235  
  1236  	config2 := struct {
  1237  		Image   string
  1238  		CapAdd  []string
  1239  		CapDrop []string
  1240  	}{"busybox", []string{"NET_ADMIN", "SYS_ADMIN"}, []string{"SETGID"}}
  1241  	status, _, err = sockRequest("POST", "/containers/create?name=capaddtest1", config2)
  1242  	c.Assert(err, checker.IsNil)
  1243  	c.Assert(status, checker.Equals, http.StatusCreated)
  1244  }
  1245  
  1246  // #14640
  1247  func (s *DockerSuite) TestPostContainersStartWithoutLinksInHostConfig(c *check.C) {
  1248  	testRequires(c, DaemonIsLinux)
  1249  	name := "test-host-config-links"
  1250  	dockerCmd(c, "create", "--name", name, "busybox", "top")
  1251  
  1252  	hc, err := inspectFieldJSON(name, "HostConfig")
  1253  	c.Assert(err, checker.IsNil)
  1254  	config := `{"HostConfig":` + hc + `}`
  1255  
  1256  	res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1257  	c.Assert(err, checker.IsNil)
  1258  	c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1259  	b.Close()
  1260  }
  1261  
  1262  // #14640
  1263  func (s *DockerSuite) TestPostContainersStartWithLinksInHostConfig(c *check.C) {
  1264  	testRequires(c, DaemonIsLinux)
  1265  	name := "test-host-config-links"
  1266  	dockerCmd(c, "run", "--name", "foo", "-d", "busybox", "top")
  1267  	dockerCmd(c, "create", "--name", name, "--link", "foo:bar", "busybox", "top")
  1268  
  1269  	hc, err := inspectFieldJSON(name, "HostConfig")
  1270  	c.Assert(err, checker.IsNil)
  1271  	config := `{"HostConfig":` + hc + `}`
  1272  
  1273  	res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1274  	c.Assert(err, checker.IsNil)
  1275  	c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1276  	b.Close()
  1277  }
  1278  
  1279  // #14640
  1280  func (s *DockerSuite) TestPostContainersStartWithLinksInHostConfigIdLinked(c *check.C) {
  1281  	testRequires(c, DaemonIsLinux)
  1282  	name := "test-host-config-links"
  1283  	out, _ := dockerCmd(c, "run", "--name", "link0", "-d", "busybox", "top")
  1284  	id := strings.TrimSpace(out)
  1285  	dockerCmd(c, "create", "--name", name, "--link", id, "busybox", "top")
  1286  
  1287  	hc, err := inspectFieldJSON(name, "HostConfig")
  1288  	c.Assert(err, checker.IsNil)
  1289  	config := `{"HostConfig":` + hc + `}`
  1290  
  1291  	res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1292  	c.Assert(err, checker.IsNil)
  1293  	c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1294  	b.Close()
  1295  }
  1296  
  1297  // #14915
  1298  func (s *DockerSuite) TestContainersApiCreateNoHostConfig118(c *check.C) {
  1299  	testRequires(c, DaemonIsLinux)
  1300  	config := struct {
  1301  		Image string
  1302  	}{"busybox"}
  1303  	status, _, err := sockRequest("POST", "/v1.18/containers/create", config)
  1304  	c.Assert(err, checker.IsNil)
  1305  	c.Assert(status, checker.Equals, http.StatusCreated)
  1306  }
  1307  
  1308  // Ensure an error occurs when you have a container read-only rootfs but you
  1309  // extract an archive to a symlink in a writable volume which points to a
  1310  // directory outside of the volume.
  1311  func (s *DockerSuite) TestPutContainerArchiveErrSymlinkInVolumeToReadOnlyRootfs(c *check.C) {
  1312  	// Requires local volume mount bind.
  1313  	// --read-only + userns has remount issues
  1314  	testRequires(c, SameHostDaemon, NotUserNamespace)
  1315  
  1316  	testVol := getTestDir(c, "test-put-container-archive-err-symlink-in-volume-to-read-only-rootfs-")
  1317  	defer os.RemoveAll(testVol)
  1318  
  1319  	makeTestContentInDir(c, testVol)
  1320  
  1321  	cID := makeTestContainer(c, testContainerOptions{
  1322  		readOnly: true,
  1323  		volumes:  defaultVolumes(testVol), // Our bind mount is at /vol2
  1324  	})
  1325  	defer deleteContainer(cID)
  1326  
  1327  	// Attempt to extract to a symlink in the volume which points to a
  1328  	// directory outside the volume. This should cause an error because the
  1329  	// rootfs is read-only.
  1330  	query := make(url.Values, 1)
  1331  	query.Set("path", "/vol2/symlinkToAbsDir")
  1332  	urlPath := fmt.Sprintf("/v1.20/containers/%s/archive?%s", cID, query.Encode())
  1333  
  1334  	statusCode, body, err := sockRequest("PUT", urlPath, nil)
  1335  	c.Assert(err, checker.IsNil)
  1336  
  1337  	if !isCpCannotCopyReadOnly(fmt.Errorf(string(body))) {
  1338  		c.Fatalf("expected ErrContainerRootfsReadonly error, but got %d: %s", statusCode, string(body))
  1339  	}
  1340  }
  1341  
  1342  func (s *DockerSuite) TestContainersApiGetContainersJSONEmpty(c *check.C) {
  1343  	testRequires(c, DaemonIsLinux)
  1344  
  1345  	status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
  1346  	c.Assert(err, checker.IsNil)
  1347  	c.Assert(status, checker.Equals, http.StatusOK)
  1348  	c.Assert(string(body), checker.Equals, "[]\n")
  1349  }
  1350  
  1351  func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *check.C) {
  1352  	testRequires(c, DaemonIsLinux)
  1353  
  1354  	c1 := struct {
  1355  		Image      string
  1356  		CpusetCpus string
  1357  	}{"busybox", "1-42,,"}
  1358  	name := "wrong-cpuset-cpus"
  1359  	status, body, err := sockRequest("POST", "/containers/create?name="+name, c1)
  1360  	c.Assert(err, checker.IsNil)
  1361  	c.Assert(status, checker.Equals, http.StatusInternalServerError)
  1362  	expected := "Invalid value 1-42,, for cpuset cpus.\n"
  1363  	c.Assert(string(body), checker.Equals, expected)
  1364  
  1365  	c2 := struct {
  1366  		Image      string
  1367  		CpusetMems string
  1368  	}{"busybox", "42-3,1--"}
  1369  	name = "wrong-cpuset-mems"
  1370  	status, body, err = sockRequest("POST", "/containers/create?name="+name, c2)
  1371  	c.Assert(err, checker.IsNil)
  1372  	c.Assert(status, checker.Equals, http.StatusInternalServerError)
  1373  	expected = "Invalid value 42-3,1-- for cpuset mems.\n"
  1374  	c.Assert(string(body), checker.Equals, expected)
  1375  }
  1376  
  1377  func (s *DockerSuite) TestStartWithNilDNS(c *check.C) {
  1378  	testRequires(c, DaemonIsLinux)
  1379  	out, _ := dockerCmd(c, "create", "busybox")
  1380  	containerID := strings.TrimSpace(out)
  1381  
  1382  	config := `{"HostConfig": {"Dns": null}}`
  1383  
  1384  	res, b, err := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
  1385  	c.Assert(err, checker.IsNil)
  1386  	c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1387  	b.Close()
  1388  
  1389  	dns, err := inspectFieldJSON(containerID, "HostConfig.Dns")
  1390  	c.Assert(err, checker.IsNil)
  1391  	c.Assert(dns, checker.Equals, "[]")
  1392  }
  1393  
  1394  func (s *DockerSuite) TestPostContainersCreateShmSizeNegative(c *check.C) {
  1395  	config := map[string]interface{}{
  1396  		"Image":      "busybox",
  1397  		"HostConfig": map[string]interface{}{"ShmSize": -1},
  1398  	}
  1399  
  1400  	status, body, err := sockRequest("POST", "/containers/create", config)
  1401  	c.Assert(err, check.IsNil)
  1402  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1403  	c.Assert(string(body), checker.Contains, "SHM size must be greater then 0")
  1404  }
  1405  
  1406  func (s *DockerSuite) TestPostContainersCreateShmSizeZero(c *check.C) {
  1407  	config := map[string]interface{}{
  1408  		"Image":      "busybox",
  1409  		"HostConfig": map[string]interface{}{"ShmSize": 0},
  1410  	}
  1411  
  1412  	status, body, err := sockRequest("POST", "/containers/create", config)
  1413  	c.Assert(err, check.IsNil)
  1414  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1415  	c.Assert(string(body), checker.Contains, "SHM size must be greater then 0")
  1416  }
  1417  
  1418  func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *check.C) {
  1419  	var defaultSHMSize int64 = 67108864
  1420  	config := map[string]interface{}{
  1421  		"Image": "busybox",
  1422  		"Cmd":   "mount",
  1423  	}
  1424  
  1425  	status, body, err := sockRequest("POST", "/containers/create", config)
  1426  	c.Assert(err, check.IsNil)
  1427  	c.Assert(status, check.Equals, http.StatusCreated)
  1428  
  1429  	var container types.ContainerCreateResponse
  1430  	c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1431  
  1432  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1433  	c.Assert(err, check.IsNil)
  1434  	c.Assert(status, check.Equals, http.StatusOK)
  1435  
  1436  	var containerJSON types.ContainerJSON
  1437  	c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1438  
  1439  	c.Assert(*containerJSON.HostConfig.ShmSize, check.Equals, defaultSHMSize)
  1440  
  1441  	out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
  1442  	shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`)
  1443  	if !shmRegexp.MatchString(out) {
  1444  		c.Fatalf("Expected shm of 64MB in mount command, got %v", out)
  1445  	}
  1446  }
  1447  
  1448  func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *check.C) {
  1449  	config := map[string]interface{}{
  1450  		"Image":      "busybox",
  1451  		"HostConfig": map[string]interface{}{},
  1452  		"Cmd":        "mount",
  1453  	}
  1454  
  1455  	status, body, err := sockRequest("POST", "/containers/create", config)
  1456  	c.Assert(err, check.IsNil)
  1457  	c.Assert(status, check.Equals, http.StatusCreated)
  1458  
  1459  	var container types.ContainerCreateResponse
  1460  	c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1461  
  1462  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1463  	c.Assert(err, check.IsNil)
  1464  	c.Assert(status, check.Equals, http.StatusOK)
  1465  
  1466  	var containerJSON types.ContainerJSON
  1467  	c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1468  
  1469  	c.Assert(*containerJSON.HostConfig.ShmSize, check.Equals, int64(67108864))
  1470  
  1471  	out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
  1472  	shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`)
  1473  	if !shmRegexp.MatchString(out) {
  1474  		c.Fatalf("Expected shm of 64MB in mount command, got %v", out)
  1475  	}
  1476  }
  1477  
  1478  func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *check.C) {
  1479  	config := map[string]interface{}{
  1480  		"Image":      "busybox",
  1481  		"Cmd":        "mount",
  1482  		"HostConfig": map[string]interface{}{"ShmSize": 1073741824},
  1483  	}
  1484  
  1485  	status, body, err := sockRequest("POST", "/containers/create", config)
  1486  	c.Assert(err, check.IsNil)
  1487  	c.Assert(status, check.Equals, http.StatusCreated)
  1488  
  1489  	var container types.ContainerCreateResponse
  1490  	c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1491  
  1492  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1493  	c.Assert(err, check.IsNil)
  1494  	c.Assert(status, check.Equals, http.StatusOK)
  1495  
  1496  	var containerJSON types.ContainerJSON
  1497  	c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1498  
  1499  	c.Assert(*containerJSON.HostConfig.ShmSize, check.Equals, int64(1073741824))
  1500  
  1501  	out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
  1502  	shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=1048576k`)
  1503  	if !shmRegex.MatchString(out) {
  1504  		c.Fatalf("Expected shm of 1GB in mount command, got %v", out)
  1505  	}
  1506  }
  1507  
  1508  func (s *DockerSuite) TestPostContainersCreateMemorySwappinessHostConfigOmitted(c *check.C) {
  1509  	config := map[string]interface{}{
  1510  		"Image": "busybox",
  1511  	}
  1512  
  1513  	status, body, err := sockRequest("POST", "/containers/create", config)
  1514  	c.Assert(err, check.IsNil)
  1515  	c.Assert(status, check.Equals, http.StatusCreated)
  1516  
  1517  	var container types.ContainerCreateResponse
  1518  	c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1519  
  1520  	status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1521  	c.Assert(err, check.IsNil)
  1522  	c.Assert(status, check.Equals, http.StatusOK)
  1523  
  1524  	var containerJSON types.ContainerJSON
  1525  	c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1526  
  1527  	c.Assert(*containerJSON.HostConfig.MemorySwappiness, check.Equals, int64(-1))
  1528  }
  1529  
  1530  // check validation is done daemon side and not only in cli
  1531  func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *check.C) {
  1532  	testRequires(c, DaemonIsLinux)
  1533  
  1534  	config := struct {
  1535  		Image       string
  1536  		OomScoreAdj int
  1537  	}{"busybox", 1001}
  1538  	name := "oomscoreadj-over"
  1539  	status, b, err := sockRequest("POST", "/containers/create?name="+name, config)
  1540  	c.Assert(err, check.IsNil)
  1541  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1542  	expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]."
  1543  	if !strings.Contains(string(b), expected) {
  1544  		c.Fatalf("Expected output to contain %q, got %q", expected, string(b))
  1545  	}
  1546  
  1547  	config = struct {
  1548  		Image       string
  1549  		OomScoreAdj int
  1550  	}{"busybox", -1001}
  1551  	name = "oomscoreadj-low"
  1552  	status, b, err = sockRequest("POST", "/containers/create?name="+name, config)
  1553  	c.Assert(err, check.IsNil)
  1554  	c.Assert(status, check.Equals, http.StatusInternalServerError)
  1555  	expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]."
  1556  	if !strings.Contains(string(b), expected) {
  1557  		c.Fatalf("Expected output to contain %q, got %q", expected, string(b))
  1558  	}
  1559  }