Browse code

Update RestartPolicy of container

Add `--restart` flag for `update` command, so we can change restart
policy for a container no matter it's running or stopped.

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>

Zhang Wei authored on 2016/01/05 00:58:20
Showing 17 changed files
... ...
@@ -6,6 +6,7 @@ import (
6 6
 
7 7
 	Cli "github.com/docker/docker/cli"
8 8
 	flag "github.com/docker/docker/pkg/mflag"
9
+	"github.com/docker/docker/runconfig/opts"
9 10
 	"github.com/docker/engine-api/types/container"
10 11
 	"github.com/docker/go-units"
11 12
 )
... ...
@@ -25,6 +26,7 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
25 25
 	flMemoryReservation := cmd.String([]string{"-memory-reservation"}, "", "Memory soft limit")
26 26
 	flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap")
27 27
 	flKernelMemory := cmd.String([]string{"-kernel-memory"}, "", "Kernel memory limit")
28
+	flRestartPolicy := cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits")
28 29
 
29 30
 	cmd.Require(flag.Min, 1)
30 31
 	cmd.ParseFlags(args, true)
... ...
@@ -69,6 +71,14 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
69 69
 		}
70 70
 	}
71 71
 
72
+	var restartPolicy container.RestartPolicy
73
+	if *flRestartPolicy != "" {
74
+		restartPolicy, err = opts.ParseRestartPolicy(*flRestartPolicy)
75
+		if err != nil {
76
+			return err
77
+		}
78
+	}
79
+
72 80
 	resources := container.Resources{
73 81
 		BlkioWeight:       *flBlkioWeight,
74 82
 		CpusetCpus:        *flCpusetCpus,
... ...
@@ -83,7 +93,8 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
83 83
 	}
84 84
 
85 85
 	updateConfig := container.UpdateConfig{
86
-		Resources: resources,
86
+		Resources:     resources,
87
+		RestartPolicy: restartPolicy,
87 88
 	}
88 89
 
89 90
 	names := cmd.Args()
... ...
@@ -322,7 +322,8 @@ func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.Respon
322 322
 	}
323 323
 
324 324
 	hostConfig := &container.HostConfig{
325
-		Resources: updateConfig.Resources,
325
+		Resources:     updateConfig.Resources,
326
+		RestartPolicy: updateConfig.RestartPolicy,
326 327
 	}
327 328
 
328 329
 	name := vars["name"]
... ...
@@ -64,7 +64,7 @@ var dockerCommands = []Command{
64 64
 	{"tag", "Tag an image into a repository"},
65 65
 	{"top", "Display the running processes of a container"},
66 66
 	{"unpause", "Unpause all processes within a container"},
67
-	{"update", "Update resources of one or more containers"},
67
+	{"update", "Update configuration of one or more containers"},
68 68
 	{"version", "Show the Docker version information"},
69 69
 	{"volume", "Manage Docker volumes"},
70 70
 	{"wait", "Block until a container stops, then print its exit code"},
... ...
@@ -594,3 +594,20 @@ func (container *Container) InitDNSHostConfig() {
594 594
 		container.HostConfig.DNSOptions = make([]string, 0)
595 595
 	}
596 596
 }
597
+
598
+// UpdateMonitor updates monitor configure for running container
599
+func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
600
+	monitor := container.monitor
601
+	// No need to update monitor if container hasn't got one
602
+	// monitor will be generated correctly according to container
603
+	if monitor == nil {
604
+		return
605
+	}
606
+
607
+	monitor.mux.Lock()
608
+	// to check whether restart policy has changed.
609
+	if restartPolicy.Name != "" && !monitor.restartPolicy.IsSame(&restartPolicy) {
610
+		monitor.restartPolicy = restartPolicy
611
+	}
612
+	monitor.mux.Unlock()
613
+}
... ...
@@ -564,10 +564,11 @@ func updateCommand(c *execdriver.Command, resources containertypes.Resources) {
564 564
 	c.Resources.KernelMemory = resources.KernelMemory
565 565
 }
566 566
 
567
-// UpdateContainer updates resources of a container.
567
+// UpdateContainer updates configuration of a container.
568 568
 func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
569 569
 	container.Lock()
570 570
 
571
+	// update resources of container
571 572
 	resources := hostConfig.Resources
572 573
 	cResources := &container.HostConfig.Resources
573 574
 	if resources.BlkioWeight != 0 {
... ...
@@ -600,6 +601,11 @@ func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfi
600 600
 	if resources.KernelMemory != 0 {
601 601
 		cResources.KernelMemory = resources.KernelMemory
602 602
 	}
603
+
604
+	// update HostConfig of container
605
+	if hostConfig.RestartPolicy.Name != "" {
606
+		container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
607
+	}
603 608
 	container.Unlock()
604 609
 
605 610
 	// If container is not running, update hostConfig struct is enough,
... ...
@@ -3,6 +3,7 @@
3 3
 package container
4 4
 
5 5
 import (
6
+	"fmt"
6 7
 	"os"
7 8
 	"path/filepath"
8 9
 
... ...
@@ -45,8 +46,22 @@ func (container *Container) TmpfsMounts() []execdriver.Mount {
45 45
 	return nil
46 46
 }
47 47
 
48
-// UpdateContainer updates resources of a container
48
+// UpdateContainer updates configuration of a container
49 49
 func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error {
50
+	container.Lock()
51
+	defer container.Unlock()
52
+	resources := hostConfig.Resources
53
+	if resources.BlkioWeight != 0 || resources.CPUShares != 0 ||
54
+		resources.CPUPeriod != 0 || resources.CPUQuota != 0 ||
55
+		resources.CpusetCpus != "" || resources.CpusetMems != "" ||
56
+		resources.Memory != 0 || resources.MemorySwap != 0 ||
57
+		resources.MemoryReservation != 0 || resources.KernelMemory != 0 {
58
+		return fmt.Errorf("Resource updating isn't supported on Windows")
59
+	}
60
+	// update HostConfig of container
61
+	if hostConfig.RestartPolicy.Name != "" {
62
+		container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
63
+	}
50 64
 	return nil
51 65
 }
52 66
 
... ...
@@ -79,11 +79,11 @@ type containerMonitor struct {
79 79
 
80 80
 // StartMonitor initializes a containerMonitor for this container with the provided supervisor and restart policy
81 81
 // and starts the container's process.
82
-func (container *Container) StartMonitor(s supervisor, policy container.RestartPolicy) error {
82
+func (container *Container) StartMonitor(s supervisor) error {
83 83
 	container.monitor = &containerMonitor{
84 84
 		supervisor:    s,
85 85
 		container:     container,
86
-		restartPolicy: policy,
86
+		restartPolicy: container.HostConfig.RestartPolicy,
87 87
 		timeIncrement: defaultTimeIncrement,
88 88
 		stopChan:      make(chan struct{}),
89 89
 		startSignal:   make(chan struct{}),
... ...
@@ -119,11 +119,11 @@ func wait(waitChan <-chan struct{}, timeout time.Duration) error {
119 119
 	}
120 120
 }
121 121
 
122
-// waitRunning waits until state is running. If state is already
122
+// WaitRunning waits until state is running. If state is already
123 123
 // running it returns immediately. If you want wait forever you must
124 124
 // supply negative timeout. Returns pid, that was passed to
125 125
 // SetRunning.
126
-func (s *State) waitRunning(timeout time.Duration) (int, error) {
126
+func (s *State) WaitRunning(timeout time.Duration) (int, error) {
127 127
 	s.Lock()
128 128
 	if s.Running {
129 129
 		pid := s.Pid
... ...
@@ -14,7 +14,7 @@ func TestStateRunStop(t *testing.T) {
14 14
 		started := make(chan struct{})
15 15
 		var pid int64
16 16
 		go func() {
17
-			runPid, _ := s.waitRunning(-1 * time.Second)
17
+			runPid, _ := s.WaitRunning(-1 * time.Second)
18 18
 			atomic.StoreInt64(&pid, int64(runPid))
19 19
 			close(started)
20 20
 		}()
... ...
@@ -41,8 +41,8 @@ func TestStateRunStop(t *testing.T) {
41 41
 		if runPid != i+100 {
42 42
 			t.Fatalf("Pid %v, expected %v", runPid, i+100)
43 43
 		}
44
-		if pid, err := s.waitRunning(-1 * time.Second); err != nil || pid != i+100 {
45
-			t.Fatalf("waitRunning returned pid: %v, err: %v, expected pid: %v, err: %v", pid, err, i+100, nil)
44
+		if pid, err := s.WaitRunning(-1 * time.Second); err != nil || pid != i+100 {
45
+			t.Fatalf("WaitRunning returned pid: %v, err: %v, expected pid: %v, err: %v", pid, err, i+100, nil)
46 46
 		}
47 47
 
48 48
 		stopped := make(chan struct{})
... ...
@@ -82,7 +82,7 @@ func TestStateTimeoutWait(t *testing.T) {
82 82
 	s := NewState()
83 83
 	started := make(chan struct{})
84 84
 	go func() {
85
-		s.waitRunning(100 * time.Millisecond)
85
+		s.WaitRunning(100 * time.Millisecond)
86 86
 		close(started)
87 87
 	}()
88 88
 	select {
... ...
@@ -98,7 +98,7 @@ func TestStateTimeoutWait(t *testing.T) {
98 98
 
99 99
 	stopped := make(chan struct{})
100 100
 	go func() {
101
-		s.waitRunning(100 * time.Millisecond)
101
+		s.WaitRunning(100 * time.Millisecond)
102 102
 		close(stopped)
103 103
 	}()
104 104
 	select {
... ...
@@ -3,12 +3,12 @@
3 3
 package windows
4 4
 
5 5
 import (
6
-	"fmt"
7
-
8 6
 	"github.com/docker/docker/daemon/execdriver"
9 7
 )
10 8
 
11 9
 // Update updates resource configs for a container.
12 10
 func (d *Driver) Update(c *execdriver.Command) error {
13
-	return fmt.Errorf("Windows: Update not implemented")
11
+	// Updating resource isn't supported on Windows
12
+	// but we should return nil for enabling updating container
13
+	return nil
14 14
 }
... ...
@@ -154,7 +154,7 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
154 154
 }
155 155
 
156 156
 func (daemon *Daemon) waitForStart(container *container.Container) error {
157
-	return container.StartMonitor(daemon, container.HostConfig.RestartPolicy)
157
+	return container.StartMonitor(daemon)
158 158
 }
159 159
 
160 160
 // Cleanup releases any network resources allocated to the container along with any rules
... ...
@@ -2,12 +2,13 @@ package daemon
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"time"
5 6
 
6 7
 	derr "github.com/docker/docker/errors"
7 8
 	"github.com/docker/engine-api/types/container"
8 9
 )
9 10
 
10
-// ContainerUpdate updates resources of the container
11
+// ContainerUpdate updates configuration of the container
11 12
 func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig) ([]string, error) {
12 13
 	var warnings []string
13 14
 
... ...
@@ -58,11 +59,19 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
58 58
 		return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
59 59
 	}
60 60
 
61
+	// if Restart Policy changed, we need to update container monitor
62
+	container.UpdateMonitor(hostConfig.RestartPolicy)
63
+
64
+	// if container is restarting, wait 5 seconds until it's running
65
+	if container.IsRestarting() {
66
+		container.WaitRunning(5 * time.Second)
67
+	}
68
+
61 69
 	// If container is not running, update hostConfig struct is enough,
62 70
 	// resources will be updated when the container is started again.
63 71
 	// If container is running (including paused), we need to update configs
64 72
 	// to the real world.
65
-	if container.IsRunning() {
73
+	if container.IsRunning() && !container.IsRestarting() {
66 74
 		if err := daemon.execDriver.Update(container.Command); err != nil {
67 75
 			return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
68 76
 		}
... ...
@@ -117,7 +117,7 @@ This section lists each version from latest to oldest.  Each listing includes a
117 117
 
118 118
 * `GET /containers/json` returns the state of the container, one of `created`, `restarting`, `running`, `paused`, `exited` or `dead`.
119 119
 * `GET /networks/(name)` now returns an `Internal` field showing whether the network is internal or not.
120
-
120
+* `POST /containers/(name)/update` now supports updating container's restart policy.
121 121
 
122 122
 ### v1.22 API changes
123 123
 
... ...
@@ -1031,7 +1031,7 @@ Status Codes:
1031 1031
 
1032 1032
 `POST /containers/(id)/update`
1033 1033
 
1034
-Update resource configs of one or more containers.
1034
+Update configuration of one or more containers.
1035 1035
 
1036 1036
 **Example request**:
1037 1037
 
... ...
@@ -1049,6 +1049,10 @@ Update resource configs of one or more containers.
1049 1049
          "MemorySwap": 514288000,
1050 1050
          "MemoryReservation": 209715200,
1051 1051
          "KernelMemory": 52428800,
1052
+         "RestartPolicy": {
1053
+           "MaximumRetryCount": 4,
1054
+           "Name": "on-failure"
1055
+         },
1052 1056
        }
1053 1057
 
1054 1058
 **Example response**:
... ...
@@ -12,7 +12,7 @@ parent = "smn_cli"
12 12
 
13 13
     Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
14 14
 
15
-    Updates container resource limits
15
+    Update configuration of one or more containers
16 16
 
17 17
       --help=false               Print usage
18 18
       --blkio-weight=0           Block IO (relative weight), between 10 and 1000
... ...
@@ -25,11 +25,12 @@ parent = "smn_cli"
25 25
       --memory-reservation=""    Memory soft limit
26 26
       --memory-swap=""           A positive integer equal to memory plus swap. Specify -1 to enable unlimited swap
27 27
       --kernel-memory=""         Kernel memory limit: container must be stopped
28
+      --restart                  Restart policy to apply when a container exits
28 29
 
29
-The `docker update` command dynamically updates container resources.  Use this
30
-command to prevent containers from consuming too many resources from their
31
-Docker host.  With a single command, you can place limits on a single
32
-container or on many. To specify more than one container, provide
30
+The `docker update` command dynamically updates container configuration.
31
+You can use this command to prevent containers from consuming too many resources
32
+from their Docker host.  With a single command, you can place limits on
33
+a single container or on many. To specify more than one container, provide
33 34
 space-separated list of container names or IDs.
34 35
 
35 36
 With the exception of the `--kernel-memory` value, you can specify these
... ...
@@ -38,6 +39,10 @@ options on a running or a stopped container. You can only update
38 38
 stopped container, the next time you restart it, the container uses those
39 39
 values.
40 40
 
41
+Another configuration you can change with this command is restart policy,
42
+new restart policy will take effect instantly after you run `docker update`
43
+on a container.
44
+
41 45
 ## EXAMPLES
42 46
 
43 47
 The following sections illustrate ways to use this command.
... ...
@@ -59,3 +64,10 @@ To update multiple resource configurations for multiple containers:
59 59
 ```bash
60 60
 $ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
61 61
 ```
62
+
63
+### Update a container's restart policy
64
+
65
+To update restart policy for one or more containers:
66
+```bash
67
+$ docker update --restart=on-failure:3 abebf7571666 hopeful_morse
68
+```
62 69
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+package main
1
+
2
+import (
3
+	"strings"
4
+	"time"
5
+
6
+	"github.com/docker/docker/pkg/integration/checker"
7
+	"github.com/go-check/check"
8
+)
9
+
10
+func (s *DockerSuite) TestUpdateRestartPolicy(c *check.C) {
11
+	out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "sh", "-c", "sleep 1 && false")
12
+	timeout := 60 * time.Second
13
+	if daemonPlatform == "windows" {
14
+		timeout = 100 * time.Second
15
+	}
16
+
17
+	id := strings.TrimSpace(string(out))
18
+
19
+	// update restart policy to on-failure:5
20
+	dockerCmd(c, "update", "--restart=on-failure:5", id)
21
+
22
+	err := waitExited(id, timeout)
23
+	c.Assert(err, checker.IsNil)
24
+
25
+	count := inspectField(c, id, "RestartCount")
26
+	c.Assert(count, checker.Equals, "5")
27
+
28
+	maximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
29
+	c.Assert(maximumRetryCount, checker.Equals, "5")
30
+}
... ...
@@ -2,7 +2,7 @@
2 2
 % Docker Community
3 3
 % JUNE 2014
4 4
 # NAME
5
-docker-update - Update resource configs of one or more containers
5
+docker-update - Update configuration of one or more containers
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker update**
... ...
@@ -17,15 +17,16 @@ docker-update - Update resource configs of one or more containers
17 17
 [**-m**|**--memory**[=*MEMORY*]]
18 18
 [**--memory-reservation**[=*MEMORY-RESERVATION*]]
19 19
 [**--memory-swap**[=*MEMORY-SWAP*]]
20
+[**--restart**[=*""*]]
20 21
 CONTAINER [CONTAINER...]
21 22
 
22 23
 # DESCRIPTION
23 24
 
24
-The `docker update` command dynamically updates container resources.  Use this
25
-command to prevent containers from consuming too many resources from their
26
-Docker host.  With a single command, you can place limits on a single
27
-container or on many. To specify more than one container, provide
28
-space-separated list of container names or IDs.
25
+The `docker update` command dynamically updates container configuration.
26
+you can Use this command to prevent containers from consuming too many 
27
+resources from their Docker host.  With a single command, you can place 
28
+limits on a single container or on many. To specify more than one container,
29
+provide space-separated list of container names or IDs.
29 30
 
30 31
 With the exception of the `--kernel-memory` value, you can specify these
31 32
 options on a running or a stopped container. You can only update
... ...
@@ -33,6 +34,10 @@ options on a running or a stopped container. You can only update
33 33
 stopped container, the next time you restart it, the container uses those
34 34
 values.
35 35
 
36
+Another configuration you can change with this command is restart policy,
37
+new restart policy will take effect instantly after you run `docker update`
38
+on a container.
39
+
36 40
 # OPTIONS
37 41
 **--blkio-weight**=0
38 42
    Block IO weight (relative weight) accepts a weight value between 10 and 1000.
... ...
@@ -70,6 +75,9 @@ be updated to a stopped container, and affect after it's started.
70 70
 **--memory-swap**=""
71 71
    Total memory limit (memory + swap)
72 72
 
73
+**--restart**=""
74
+   Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
75
+
73 76
 # EXAMPLES
74 77
 
75 78
 The following sections illustrate ways to use this command.
... ...
@@ -91,3 +99,10 @@ To update multiple resource configurations for multiple containers:
91 91
 ```bash
92 92
 $ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
93 93
 ```
94
+
95
+### Update a container's restart policy
96
+
97
+To update restart policy for one or more containers:
98
+```bash
99
+$ docker update --restart=on-failure:3 abebf7571666 hopeful_morse
100
+```