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