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