github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/integration-cli/docker_api_exec_test.go (about)

     1  // +build !test_no_exec
     2  
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/json"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"time"
    12  
    13  	"github.com/docker/docker/integration-cli/checker"
    14  	"github.com/docker/docker/integration-cli/request"
    15  	"github.com/docker/docker/pkg/testutil"
    16  	"github.com/go-check/check"
    17  )
    18  
    19  // Regression test for #9414
    20  func (s *DockerSuite) TestExecAPICreateNoCmd(c *check.C) {
    21  	name := "exec_test"
    22  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
    23  
    24  	status, body, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": nil}, daemonHost())
    25  	c.Assert(err, checker.IsNil)
    26  	c.Assert(status, checker.Equals, http.StatusInternalServerError)
    27  
    28  	comment := check.Commentf("Expected message when creating exec command with no Cmd specified")
    29  	c.Assert(getErrorMessage(c, body), checker.Contains, "No exec command specified", comment)
    30  }
    31  
    32  func (s *DockerSuite) TestExecAPICreateNoValidContentType(c *check.C) {
    33  	name := "exec_test"
    34  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
    35  
    36  	jsonData := bytes.NewBuffer(nil)
    37  	if err := json.NewEncoder(jsonData).Encode(map[string]interface{}{"Cmd": nil}); err != nil {
    38  		c.Fatalf("Can not encode data to json %s", err)
    39  	}
    40  
    41  	res, body, err := request.Post(fmt.Sprintf("/containers/%s/exec", name), request.RawContent(ioutil.NopCloser(jsonData)), request.ContentType("test/plain"))
    42  	c.Assert(err, checker.IsNil)
    43  	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
    44  
    45  	b, err := testutil.ReadBody(body)
    46  	c.Assert(err, checker.IsNil)
    47  
    48  	comment := check.Commentf("Expected message when creating exec command with invalid Content-Type specified")
    49  	c.Assert(getErrorMessage(c, b), checker.Contains, "Content-Type specified", comment)
    50  }
    51  
    52  func (s *DockerSuite) TestExecAPICreateContainerPaused(c *check.C) {
    53  	// Not relevant on Windows as Windows containers cannot be paused
    54  	testRequires(c, DaemonIsLinux)
    55  	name := "exec_create_test"
    56  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
    57  
    58  	dockerCmd(c, "pause", name)
    59  	status, body, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": []string{"true"}}, daemonHost())
    60  	c.Assert(err, checker.IsNil)
    61  	c.Assert(status, checker.Equals, http.StatusConflict)
    62  
    63  	comment := check.Commentf("Expected message when creating exec command with Container %s is paused", name)
    64  	c.Assert(getErrorMessage(c, body), checker.Contains, "Container "+name+" is paused, unpause the container before exec", comment)
    65  }
    66  
    67  func (s *DockerSuite) TestExecAPIStart(c *check.C) {
    68  	testRequires(c, DaemonIsLinux) // Uses pause/unpause but bits may be salvageable to Windows to Windows CI
    69  	dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
    70  
    71  	id := createExec(c, "test")
    72  	startExec(c, id, http.StatusOK)
    73  
    74  	var execJSON struct{ PID int }
    75  	inspectExec(c, id, &execJSON)
    76  	c.Assert(execJSON.PID, checker.GreaterThan, 1)
    77  
    78  	id = createExec(c, "test")
    79  	dockerCmd(c, "stop", "test")
    80  
    81  	startExec(c, id, http.StatusNotFound)
    82  
    83  	dockerCmd(c, "start", "test")
    84  	startExec(c, id, http.StatusNotFound)
    85  
    86  	// make sure exec is created before pausing
    87  	id = createExec(c, "test")
    88  	dockerCmd(c, "pause", "test")
    89  	startExec(c, id, http.StatusConflict)
    90  	dockerCmd(c, "unpause", "test")
    91  	startExec(c, id, http.StatusOK)
    92  }
    93  
    94  func (s *DockerSuite) TestExecAPIStartEnsureHeaders(c *check.C) {
    95  	testRequires(c, DaemonIsLinux)
    96  	dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
    97  
    98  	id := createExec(c, "test")
    99  	resp, _, err := request.Post(fmt.Sprintf("/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.JSON)
   100  	c.Assert(err, checker.IsNil)
   101  	c.Assert(resp.Header.Get("Server"), checker.Not(checker.Equals), "")
   102  }
   103  
   104  func (s *DockerSuite) TestExecAPIStartBackwardsCompatible(c *check.C) {
   105  	testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
   106  	runSleepingContainer(c, "-d", "--name", "test")
   107  	id := createExec(c, "test")
   108  
   109  	resp, body, err := request.Post(fmt.Sprintf("/v1.20/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.ContentType("text/plain"))
   110  	c.Assert(err, checker.IsNil)
   111  
   112  	b, err := testutil.ReadBody(body)
   113  	comment := check.Commentf("response body: %s", b)
   114  	c.Assert(err, checker.IsNil, comment)
   115  	c.Assert(resp.StatusCode, checker.Equals, http.StatusOK, comment)
   116  }
   117  
   118  // #19362
   119  func (s *DockerSuite) TestExecAPIStartMultipleTimesError(c *check.C) {
   120  	runSleepingContainer(c, "-d", "--name", "test")
   121  	execID := createExec(c, "test")
   122  	startExec(c, execID, http.StatusOK)
   123  	waitForExec(c, execID)
   124  
   125  	startExec(c, execID, http.StatusConflict)
   126  }
   127  
   128  // #20638
   129  func (s *DockerSuite) TestExecAPIStartWithDetach(c *check.C) {
   130  	name := "foo"
   131  	runSleepingContainer(c, "-d", "-t", "--name", name)
   132  	data := map[string]interface{}{
   133  		"cmd":         []string{"true"},
   134  		"AttachStdin": true,
   135  	}
   136  	_, b, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), data, daemonHost())
   137  	c.Assert(err, checker.IsNil, check.Commentf(string(b)))
   138  
   139  	createResp := struct {
   140  		ID string `json:"Id"`
   141  	}{}
   142  	c.Assert(json.Unmarshal(b, &createResp), checker.IsNil, check.Commentf(string(b)))
   143  
   144  	_, body, err := request.Post(fmt.Sprintf("/exec/%s/start", createResp.ID), request.RawString(`{"Detach": true}`), request.JSON)
   145  	c.Assert(err, checker.IsNil)
   146  
   147  	b, err = testutil.ReadBody(body)
   148  	comment := check.Commentf("response body: %s", b)
   149  	c.Assert(err, checker.IsNil, comment)
   150  
   151  	resp, _, err := request.Get("/_ping")
   152  	c.Assert(err, checker.IsNil)
   153  	if resp.StatusCode != http.StatusOK {
   154  		c.Fatal("daemon is down, it should alive")
   155  	}
   156  }
   157  
   158  // #30311
   159  func (s *DockerSuite) TestExecAPIStartValidCommand(c *check.C) {
   160  	name := "exec_test"
   161  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
   162  
   163  	id := createExecCmd(c, name, "true")
   164  	startExec(c, id, http.StatusOK)
   165  
   166  	waitForExec(c, id)
   167  
   168  	var inspectJSON struct{ ExecIDs []string }
   169  	inspectContainer(c, name, &inspectJSON)
   170  
   171  	c.Assert(inspectJSON.ExecIDs, checker.IsNil)
   172  }
   173  
   174  // #30311
   175  func (s *DockerSuite) TestExecAPIStartInvalidCommand(c *check.C) {
   176  	name := "exec_test"
   177  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
   178  
   179  	id := createExecCmd(c, name, "invalid")
   180  	startExec(c, id, http.StatusNotFound)
   181  	waitForExec(c, id)
   182  
   183  	var inspectJSON struct{ ExecIDs []string }
   184  	inspectContainer(c, name, &inspectJSON)
   185  
   186  	c.Assert(inspectJSON.ExecIDs, checker.IsNil)
   187  }
   188  
   189  func createExec(c *check.C, name string) string {
   190  	return createExecCmd(c, name, "true")
   191  }
   192  
   193  func createExecCmd(c *check.C, name string, cmd string) string {
   194  	_, reader, err := request.Post(fmt.Sprintf("/containers/%s/exec", name), request.JSONBody(map[string]interface{}{"Cmd": []string{cmd}}))
   195  	c.Assert(err, checker.IsNil)
   196  	b, err := ioutil.ReadAll(reader)
   197  	c.Assert(err, checker.IsNil)
   198  	defer reader.Close()
   199  	createResp := struct {
   200  		ID string `json:"Id"`
   201  	}{}
   202  	c.Assert(json.Unmarshal(b, &createResp), checker.IsNil, check.Commentf(string(b)))
   203  	return createResp.ID
   204  }
   205  
   206  func startExec(c *check.C, id string, code int) {
   207  	resp, body, err := request.Post(fmt.Sprintf("/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.JSON)
   208  	c.Assert(err, checker.IsNil)
   209  
   210  	b, err := testutil.ReadBody(body)
   211  	comment := check.Commentf("response body: %s", b)
   212  	c.Assert(err, checker.IsNil, comment)
   213  	c.Assert(resp.StatusCode, checker.Equals, code, comment)
   214  }
   215  
   216  func inspectExec(c *check.C, id string, out interface{}) {
   217  	resp, body, err := request.Get(fmt.Sprintf("/exec/%s/json", id))
   218  	c.Assert(err, checker.IsNil)
   219  	defer body.Close()
   220  	c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
   221  	err = json.NewDecoder(body).Decode(out)
   222  	c.Assert(err, checker.IsNil)
   223  }
   224  
   225  func waitForExec(c *check.C, id string) {
   226  	timeout := time.After(60 * time.Second)
   227  	var execJSON struct{ Running bool }
   228  	for {
   229  		select {
   230  		case <-timeout:
   231  			c.Fatal("timeout waiting for exec to start")
   232  		default:
   233  		}
   234  
   235  		inspectExec(c, id, &execJSON)
   236  		if !execJSON.Running {
   237  			break
   238  		}
   239  	}
   240  }
   241  
   242  func inspectContainer(c *check.C, id string, out interface{}) {
   243  	resp, body, err := request.Get(fmt.Sprintf("/containers/%s/json", id))
   244  	c.Assert(err, checker.IsNil)
   245  	defer body.Close()
   246  	c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
   247  	err = json.NewDecoder(body).Decode(out)
   248  	c.Assert(err, checker.IsNil)
   249  }