Skip to content

Commit 30fa131

Browse files
committed
test: add missing integration test for PouchContainer
Signed-off-by: Allen Sun <[email protected]>
1 parent ac1a952 commit 30fa131

13 files changed

+189
-86
lines changed

apis/server/exec_bridge.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strconv"
1010

1111
"github.com/alibaba/pouch/apis/types"
12+
"github.com/alibaba/pouch/pkg/errtypes"
1213
"github.com/alibaba/pouch/pkg/httputils"
1314
"github.com/alibaba/pouch/pkg/streams"
1415

@@ -75,6 +76,7 @@ func (s *Server) startContainerExec(ctx context.Context, rw http.ResponseWriter,
7576
)
7677

7778
// TODO(huamin.thm): support detach exec process through http post method
79+
// Do we need to merge the input config.Detach and ContainerExecConfig.ExecCreateConfig.Detach?
7880
if !config.Detach {
7981
stdin, stdout, closeFn, err = openHijackConnection(rw)
8082
if err != nil {
@@ -102,6 +104,12 @@ func (s *Server) startContainerExec(ctx context.Context, rw http.ResponseWriter,
102104
}
103105

104106
if err := s.ContainerMgr.StartExec(ctx, name, attach); err != nil {
107+
if errtypes.IsConflict(err) {
108+
return err
109+
}
110+
if errtypes.IsNotfound(err) {
111+
return err
112+
}
105113
if config.Detach {
106114
return err
107115
}

apis/server/router.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ func HandleErrorResponse(w http.ResponseWriter, err error) {
242242
code = http.StatusNotFound
243243
} else if errtypes.IsInvalidParam(err) {
244244
code = http.StatusBadRequest
245-
} else if errtypes.IsAlreadyExisted(err) {
245+
} else if errtypes.IsAlreadyExisted(err) || errtypes.IsConflict(err) {
246246
code = http.StatusConflict
247247
} else if errtypes.IsNotModified(err) {
248248
code = http.StatusNotModified

apis/swagger.yml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3269,14 +3269,14 @@ definitions:
32693269
properties:
32703270
User:
32713271
type: "string"
3272-
description: "User that will run the command"
3272+
description: "User with whom the exec command will run inside container."
32733273
x-nullable: false
32743274
Privileged:
32753275
type: "boolean"
3276-
description: "Is the container in privileged mode"
3276+
description: "Config whether to run the exec command in container with all privilleges."
32773277
Tty:
32783278
type: "boolean"
3279-
description: "Attach standard streams to a tty"
3279+
description: "Config the created exec whether to allocate a pseudo-TTY."
32803280
AttachStdin:
32813281
type: "boolean"
32823282
description: "Attach the standard input, makes possible user interaction"
@@ -3288,7 +3288,11 @@ definitions:
32883288
description: "Attach the standard output"
32893289
Detach:
32903290
type: "boolean"
3291-
description: "Execute in detach mode"
3291+
description: |
3292+
Config the exec process inside the container detached from the client.
3293+
For example, if set to be true, the CLI command line will be detached from
3294+
the exec processes's stdin/stdout/stderr stream, and command will terminated
3295+
at once while the exec process will be running background in container.
32923296
DetachKeys:
32933297
type: "string"
32943298
description: "Escape keys for detach"
@@ -3333,10 +3337,14 @@ definitions:
33333337
description: ExecStartConfig is a temp struct used by execStart.
33343338
properties:
33353339
Detach:
3336-
description: ExecStart will first check if it's detached
3340+
description: |
3341+
Config the started exec process inside the container detached from the client.
3342+
For example, if set to be true, the CLI command line will be detached from
3343+
the exec processes's stdin/stdout/stderr stream, and command will terminated
3344+
at once while the exec process will be running background in container.
33373345
type: "boolean"
33383346
Tty:
3339-
description: Check if there's a tty
3347+
description: Config the exec start whether to allocate a pseudo-TTY.
33403348
type: "boolean"
33413349
example:
33423350
Detach: false

apis/types/exec_create_config.go

Lines changed: 8 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apis/types/exec_start_config.go

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

daemon/mgr/container.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1678,7 +1678,7 @@ func (mgr *ContainerManager) attachCRILog(c *Container, logPath string) error {
16781678

16791679
func (mgr *ContainerManager) initExecIO(id string, withStdin bool) (*containerio.IO, error) {
16801680
if io := mgr.IOs.Get(id); io != nil {
1681-
return nil, errors.Wrap(errtypes.ErrConflict, "failed to create containerIO")
1681+
return nil, errors.Wrap(errtypes.ErrConflict, "failed to create execIO")
16821682
}
16831683

16841684
cntrio := containerio.NewIO(id, withStdin)

daemon/mgr/container_exec.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ func (mgr *ContainerManager) StartExec(ctx context.Context, execid string, cfg *
7070
return err
7171
}
7272

73+
if !c.IsRunning() {
74+
return errors.Wrap(errtypes.ErrConflict, "cannot start an exec in not running containers")
75+
}
76+
7377
// set exec process user, user decided by exec config
7478
if execConfig.User == "" {
7579
execConfig.User = c.Config.User
@@ -162,7 +166,7 @@ func (mgr *ContainerManager) StartExec(ctx context.Context, execid string, cfg *
162166
IO: eio,
163167
P: process,
164168
}); err != nil {
165-
return err
169+
return errors.Wrapf(err, "failed to exec process in container %s", execConfig.ContainerID)
166170
}
167171
return <-attachErrCh
168172
}

pkg/errtypes/errors.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ func IsPreCheckFailed(err error) bool {
102102
return checkError(err, codePreCheckFailed)
103103
}
104104

105+
// IsConflict checks if the error is conflict.
106+
func IsConflict(err error) bool {
107+
return checkError(err, codeConflict)
108+
}
109+
105110
func checkError(err error, code int) bool {
106111
err = causeError(err)
107112

test/api_container_create_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,29 @@ func testCreateContainerWithBadParam(c *check.C, cname string, obj map[string]in
215215
}
216216

217217
// TestCreateWithBadStopTimeout using bad stopTimeout to create container.
218-
func (suite *APIContainerCreateSuite) TestCreateWithBadStopTimeout(c *check.C) {
218+
func (suite *APIContainerCreateSuite) testCreateWithBadParams(c *check.C) {
219219
testCreateContainerWithBadParam(c,
220220
"TestCreateWithBadStopTimeout",
221221
map[string]interface{}{
222222
"Image": busyboxImage,
223223
"StopTimeout": -1,
224224
})
225+
226+
// too long length
227+
testCreateContainerWithBadParam(c,
228+
"1234567890-1234567890-1234567890-1234567890123456789",
229+
map[string]interface{}{
230+
"Image": busyboxImage,
231+
})
232+
233+
// invalid characters
234+
testCreateContainerWithBadParam(c,
235+
"??????><!@#$%^&*",
236+
map[string]interface{}{
237+
"Image": busyboxImage,
238+
})
239+
240+
// TODO: add more container creation option check
225241
}
226242

227243
func (suite *APIContainerCreateSuite) TestCreateNvidiaConfig(c *check.C) {
Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package main
22

33
import (
4-
"time"
4+
"fmt"
5+
"os/exec"
6+
"strconv"
7+
"strings"
8+
"syscall"
59

6-
"github.com/alibaba/pouch/apis/types"
710
"github.com/alibaba/pouch/test/environment"
811
"github.com/alibaba/pouch/test/request"
912

@@ -26,70 +29,60 @@ func (suite *APIContainerExecInspectSuite) SetUpTest(c *check.C) {
2629

2730
// TestContainerCreateExecOk tests execing containers is OK.
2831
func (suite *APIContainerExecInspectSuite) TestContainerExecInspectOk(c *check.C) {
29-
c.Skip("skip flaky test due to issue#1372")
3032
cname := "TestContainerExecInspectOk"
3133

3234
CreateBusyboxContainerOk(c, cname)
35+
defer DelContainerForceMultyTime(c, cname)
3336

3437
StartContainerOk(c, cname)
3538

36-
obj := map[string]interface{}{
37-
"Cmd": []string{"sleep", "9"},
38-
"Detach": true,
39-
}
40-
body := request.WithJSONBody(obj)
41-
resp, err := request.Post("/containers/"+cname+"/exec", body)
42-
c.Assert(err, check.IsNil)
43-
CheckRespStatus(c, resp, 201)
44-
45-
var execCreateResp types.ExecCreateResp
46-
err = request.DecodeBody(&execCreateResp, resp.Body)
47-
c.Assert(err, check.IsNil)
48-
49-
execid := execCreateResp.ID
50-
51-
// inspect the exec before exec start
52-
resp, err = request.Get("/exec/" + execid + "/json")
53-
c.Assert(err, check.IsNil)
54-
CheckRespStatus(c, resp, 200)
55-
56-
var execInspect01 types.ContainerExecInspect
57-
request.DecodeBody(&execInspect01, resp.Body)
39+
// create an exec and get the execID
40+
// and inspect the exec before exec start
5841

59-
c.Assert(execInspect01.Running, check.Equals, false)
60-
c.Assert(execInspect01.ExitCode, check.Equals, int64(0))
42+
execid := CreateExecCmdOk(c, cname, "sleep", "12345678")
43+
{
44+
execInspectResp := InspectExecOk(c, execid)
45+
c.Assert(execInspectResp.Running, check.Equals, false)
46+
c.Assert(execInspectResp.ExitCode, check.Equals, int64(0))
47+
}
6148

62-
// start the exec
49+
// set the detach to be true
50+
// and start the exec
6351
{
64-
resp, conn, _, err := StartContainerExec(c, execid, false, false)
52+
obj := map[string]interface{}{
53+
"Detach": true,
54+
}
55+
body := request.WithJSONBody(obj)
56+
resp, err := request.Post(fmt.Sprintf("/exec/%s/start", execid), body)
6557
c.Assert(err, check.IsNil)
66-
CheckRespStatus(c, resp, 101)
67-
c.Assert(conn.Close(), check.IsNil)
58+
CheckRespStatus(c, resp, 200)
6859
}
6960

7061
// inspect the exec after exec start
71-
resp, err = request.Get("/exec/" + execid + "/json")
72-
c.Assert(err, check.IsNil)
73-
CheckRespStatus(c, resp, 200)
74-
75-
var execInspect02 types.ContainerExecInspect
76-
request.DecodeBody(&execInspect02, resp.Body)
77-
78-
c.Assert(execInspect02.Running, check.Equals, true)
79-
c.Assert(execInspect02.ExitCode, check.Equals, int64(0))
80-
81-
// sleep 10s to wait the process exit
82-
time.Sleep(10 * time.Second)
62+
{
63+
execInspectResp := InspectExecOk(c, execid)
64+
c.Assert(execInspectResp.Running, check.Equals, true)
65+
c.Assert(execInspectResp.ExitCode, check.Equals, int64(0))
66+
}
8367

84-
resp, err = request.Get("/exec/" + execid + "/json")
85-
c.Assert(err, check.IsNil)
86-
CheckRespStatus(c, resp, 200)
68+
// find the exec command and terminate it.
69+
{
70+
cmd := exec.Command("bash", "-c", "ps aux | grep 'sleep 12345678' | awk '{print $2}'")
71+
output, err := cmd.Output()
72+
c.Assert(err, check.IsNil)
8773

88-
var execInspect03 types.ContainerExecInspect
89-
request.DecodeBody(&execInspect03, resp.Body)
74+
outputStr := strings.TrimSpace(string(output))
75+
pids := strings.SplitN(outputStr, "\n", -1)
76+
c.Assert(len(pids), check.Equals, 1)
9077

91-
c.Assert(execInspect03.Running, check.Equals, false)
92-
c.Assert(execInspect03.ExitCode, check.Equals, int64(0))
78+
// kill the exec process by sending terminal signal
79+
pid, err := strconv.Atoi(pids[0])
80+
c.Assert(err, check.IsNil)
81+
err = syscall.Kill(pid, syscall.SIGTERM)
82+
c.Assert(err, check.IsNil)
9383

94-
DelContainerForceMultyTime(c, cname)
84+
execInspectResp := InspectExecOk(c, execid)
85+
c.Assert(execInspectResp.Running, check.Equals, false)
86+
c.Assert(execInspectResp.ExitCode, check.Equals, int64(0))
87+
}
9588
}

0 commit comments

Comments
 (0)