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