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