Browse code

Keep backwards compatibility in kill api.

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>

David Calavera authored on 2015/07/29 03:36:38
Showing 4 changed files
... ...
@@ -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
+}