diff --git a/apis/server/router.go b/apis/server/router.go index a7ddc03bf..9c1864675 100644 --- a/apis/server/router.go +++ b/apis/server/router.go @@ -226,6 +226,8 @@ func HandleErrorResponse(w http.ResponseWriter, err error) { code = http.StatusBadRequest } else if errtypes.IsAlreadyExisted(err) { code = http.StatusConflict + } else if errtypes.IsNotModified(err) { + code = http.StatusNotModified } w.Header().Set("Content-Type", "application/json") diff --git a/apis/swagger.yml b/apis/swagger.yml index acdd7c99d..6b0dff6da 100644 --- a/apis/swagger.yml +++ b/apis/swagger.yml @@ -588,6 +588,8 @@ paths: responses: 204: description: "no error" + 304: + description: "container already started" 404: $ref: "#/responses/404ErrorResponse" 409: diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index 53a0c526d..9044272c8 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -479,6 +479,11 @@ func (mgr *ContainerManager) Start(ctx context.Context, id string, options *type return err } + // check if container's status is running + if c.IsRunning() { + return errors.Wrapf(errtypes.ErrNotModified, "container already started") + } + return mgr.start(ctx, c, options) } diff --git a/pkg/errtypes/errors.go b/pkg/errtypes/errors.go index 00ee91289..d025d4ac4 100644 --- a/pkg/errtypes/errors.go +++ b/pkg/errtypes/errors.go @@ -34,6 +34,9 @@ var ( // ErrVolumeNotFound represents that no such volume. ErrVolumeNotFound = errorType{codeNotFound, "no such volume"} + + // ErrNotModified represents that the resource is not modified + ErrNotModified = errorType{codeNotModified, "not modified"} ) const ( @@ -46,6 +49,7 @@ const ( codeLockfailed codeNotImplemented codeInUse + codeNotModified ) type errorType struct { @@ -82,6 +86,11 @@ func IsInUse(err error) bool { return checkError(err, codeInUse) } +// IsNotModified checks the error is not modified erro or not. +func IsNotModified(err error) bool { + return checkError(err, codeNotModified) +} + func checkError(err error, code int) bool { err = causeError(err) diff --git a/test/api_container_start_test.go b/test/api_container_start_test.go index 0e3e4c76f..68e9f63fa 100644 --- a/test/api_container_start_test.go +++ b/test/api_container_start_test.go @@ -92,3 +92,18 @@ func (suite *APIContainerStartSuite) TestInvalidParam(c *check.C) { // TODO: missing case helpwantedForMissingCase(c, "container api start bad request") } + +// TestStartAlreadyRunningContainer tests starting a running container +func (suite *APIContainerStartSuite) TestStartAlreadyRunningContainer(c *check.C) { + cname := "TestStartAlreadyRunningContainer" + + CreateBusyboxContainerOk(c, cname) + defer DelContainerForceMultyTime(c, cname) + + StartContainerOk(c, cname) + + resp, err := request.Post("/containers/" + cname + "/start") + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 304) + +} diff --git a/test/cli_stop_test.go b/test/cli_stop_test.go index 0d9b9551b..809ca8123 100644 --- a/test/cli_stop_test.go +++ b/test/cli_stop_test.go @@ -159,3 +159,12 @@ func (suite *PouchStopSuite) TestAutoStopPidValue(c *check.C) { } c.Assert(result[0].State.Pid, check.Equals, int64(0)) } + +// TestStartContainerTwice tries to start a container twice +func (suite *PouchStartSuite) TestStartContainerTwice(c *check.C) { + name := "TestStartContainerTwice" + + command.PouchRun("create", "--name", name, busyboxImage, "top").Assert(c, icmd.Success) + command.PouchRun("start", name).Assert(c, icmd.Success) + command.PouchRun("start", name).Assert(c, icmd.Success) +}