Return an error when the container is stopped only in api versions
equal or greater than 1.20 (docker 1.8).
Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -298,7 +298,13 @@ func (s *Server) postContainersKill(version version.Version, w http.ResponseWrit |
| 298 | 298 |
} |
| 299 | 299 |
|
| 300 | 300 |
if err := s.daemon.ContainerKill(name, sig); err != nil {
|
| 301 |
- return err |
|
| 301 |
+ _, isStopped := err.(daemon.ErrContainerNotRunning) |
|
| 302 |
+ // Return error that's not caused because the container is stopped. |
|
| 303 |
+ // Return error if the container is not running and the api is >= 1.20 |
|
| 304 |
+ // to keep backwards compatibility. |
|
| 305 |
+ if version.GreaterThanOrEqualTo("1.20") || !isStopped {
|
|
| 306 |
+ return fmt.Errorf("Cannot kill container %s: %v", name, err)
|
|
| 307 |
+ } |
|
| 302 | 308 |
} |
| 303 | 309 |
|
| 304 | 310 |
w.WriteHeader(http.StatusNoContent) |
| ... | ... |
@@ -41,6 +41,14 @@ var ( |
| 41 | 41 |
ErrContainerRootfsReadonly = errors.New("container rootfs is marked read-only")
|
| 42 | 42 |
) |
| 43 | 43 |
|
| 44 |
+type ErrContainerNotRunning struct {
|
|
| 45 |
+ id string |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+func (e ErrContainerNotRunning) Error() string {
|
|
| 49 |
+ return fmt.Sprintf("Container %s is not running", e.id)
|
|
| 50 |
+} |
|
| 51 |
+ |
|
| 44 | 52 |
type StreamConfig struct {
|
| 45 | 53 |
stdout *broadcastwriter.BroadcastWriter |
| 46 | 54 |
stderr *broadcastwriter.BroadcastWriter |
| ... | ... |
@@ -361,7 +369,7 @@ func (container *Container) KillSig(sig int) error {
|
| 361 | 361 |
} |
| 362 | 362 |
|
| 363 | 363 |
if !container.Running {
|
| 364 |
- return fmt.Errorf("Container %s is not running", container.ID)
|
|
| 364 |
+ return ErrContainerNotRunning{container.ID}
|
|
| 365 | 365 |
} |
| 366 | 366 |
|
| 367 | 367 |
// signal to the monitor that it should not restart the container |
| ... | ... |
@@ -398,7 +406,7 @@ func (container *Container) Pause() error {
|
| 398 | 398 |
|
| 399 | 399 |
// We cannot Pause the container which is not running |
| 400 | 400 |
if !container.Running {
|
| 401 |
- return fmt.Errorf("Container %s is not running, cannot pause a non-running container", container.ID)
|
|
| 401 |
+ return ErrContainerNotRunning{container.ID}
|
|
| 402 | 402 |
} |
| 403 | 403 |
|
| 404 | 404 |
// We cannot Pause the container which is already paused |
| ... | ... |
@@ -420,7 +428,7 @@ func (container *Container) Unpause() error {
|
| 420 | 420 |
|
| 421 | 421 |
// We cannot unpause the container which is not running |
| 422 | 422 |
if !container.Running {
|
| 423 |
- return fmt.Errorf("Container %s is not running, cannot unpause a non-running container", container.ID)
|
|
| 423 |
+ return ErrContainerNotRunning{container.ID}
|
|
| 424 | 424 |
} |
| 425 | 425 |
|
| 426 | 426 |
// We cannot unpause the container which is not paused |
| ... | ... |
@@ -438,7 +446,7 @@ func (container *Container) Unpause() error {
|
| 438 | 438 |
|
| 439 | 439 |
func (container *Container) Kill() error {
|
| 440 | 440 |
if !container.IsRunning() {
|
| 441 |
- return fmt.Errorf("Container %s is not running", container.ID)
|
|
| 441 |
+ return ErrContainerNotRunning{container.ID}
|
|
| 442 | 442 |
} |
| 443 | 443 |
|
| 444 | 444 |
// 1. Send SIGKILL |
| ... | ... |
@@ -520,7 +528,7 @@ func (container *Container) Restart(seconds int) error {
|
| 520 | 520 |
|
| 521 | 521 |
func (container *Container) Resize(h, w int) error {
|
| 522 | 522 |
if !container.IsRunning() {
|
| 523 |
- return fmt.Errorf("Cannot resize container %s, container is not running", container.ID)
|
|
| 523 |
+ return ErrContainerNotRunning{container.ID}
|
|
| 524 | 524 |
} |
| 525 | 525 |
if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil {
|
| 526 | 526 |
return err |
| ... | ... |
@@ -1,9 +1,6 @@ |
| 1 | 1 |
package daemon |
| 2 | 2 |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- "syscall" |
|
| 6 |
-) |
|
| 3 |
+import "syscall" |
|
| 7 | 4 |
|
| 8 | 5 |
// ContainerKill send signal to the container |
| 9 | 6 |
// If no signal is given (sig 0), then Kill with SIGKILL and wait |
| ... | ... |
@@ -18,12 +15,12 @@ func (daemon *Daemon) ContainerKill(name string, sig uint64) error {
|
| 18 | 18 |
// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait()) |
| 19 | 19 |
if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
|
| 20 | 20 |
if err := container.Kill(); err != nil {
|
| 21 |
- return fmt.Errorf("Cannot kill container %s: %s", name, err)
|
|
| 21 |
+ return err |
|
| 22 | 22 |
} |
| 23 | 23 |
} else {
|
| 24 | 24 |
// Otherwise, just send the requested signal |
| 25 | 25 |
if err := container.KillSig(int(sig)); err != nil {
|
| 26 |
- return fmt.Errorf("Cannot kill container %s: %s", name, err)
|
|
| 26 |
+ return err |
|
| 27 | 27 |
} |
| 28 | 28 |
} |
| 29 | 29 |
return nil |
| ... | ... |
@@ -1,6 +1,8 @@ |
| 1 | 1 |
package main |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 5 |
+ "net/http" |
|
| 4 | 6 |
"strings" |
| 5 | 7 |
|
| 6 | 8 |
"github.com/go-check/check" |
| ... | ... |
@@ -87,3 +89,12 @@ func (s *DockerSuite) TestKillWithInvalidSignal(c *check.C) {
|
| 87 | 87 |
c.Fatal("Container should be in running state after an invalid signal")
|
| 88 | 88 |
} |
| 89 | 89 |
} |
| 90 |
+ |
|
| 91 |
+func (s *DockerSuite) TestKillofStoppedContainerAPIPre120(c *check.C) {
|
|
| 92 |
+ dockerCmd(c, "run", "--name", "docker-kill-test-api", "-d", "busybox", "top") |
|
| 93 |
+ dockerCmd(c, "stop", "docker-kill-test-api") |
|
| 94 |
+ |
|
| 95 |
+ status, _, err := sockRequest("POST", fmt.Sprintf("/v1.19/containers/%s/kill", "docker-kill-test-api"), nil)
|
|
| 96 |
+ c.Assert(err, check.IsNil) |
|
| 97 |
+ c.Assert(status, check.Equals, http.StatusNoContent) |
|
| 98 |
+} |