Browse Source

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 9 years ago
parent
commit
ff3ea4c90f

+ 12 - 1
api/client/update.go

@@ -6,6 +6,7 @@ import (
 
 
 	Cli "github.com/docker/docker/cli"
 	Cli "github.com/docker/docker/cli"
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/runconfig/opts"
 	"github.com/docker/engine-api/types/container"
 	"github.com/docker/engine-api/types/container"
 	"github.com/docker/go-units"
 	"github.com/docker/go-units"
 )
 )
@@ -25,6 +26,7 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
 	flMemoryReservation := cmd.String([]string{"-memory-reservation"}, "", "Memory soft limit")
 	flMemoryReservation := cmd.String([]string{"-memory-reservation"}, "", "Memory soft limit")
 	flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap")
 	flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap")
 	flKernelMemory := cmd.String([]string{"-kernel-memory"}, "", "Kernel memory limit")
 	flKernelMemory := cmd.String([]string{"-kernel-memory"}, "", "Kernel memory limit")
+	flRestartPolicy := cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits")
 
 
 	cmd.Require(flag.Min, 1)
 	cmd.Require(flag.Min, 1)
 	cmd.ParseFlags(args, true)
 	cmd.ParseFlags(args, true)
@@ -69,6 +71,14 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
 		}
 		}
 	}
 	}
 
 
+	var restartPolicy container.RestartPolicy
+	if *flRestartPolicy != "" {
+		restartPolicy, err = opts.ParseRestartPolicy(*flRestartPolicy)
+		if err != nil {
+			return err
+		}
+	}
+
 	resources := container.Resources{
 	resources := container.Resources{
 		BlkioWeight:       *flBlkioWeight,
 		BlkioWeight:       *flBlkioWeight,
 		CpusetCpus:        *flCpusetCpus,
 		CpusetCpus:        *flCpusetCpus,
@@ -83,7 +93,8 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
 	}
 	}
 
 
 	updateConfig := container.UpdateConfig{
 	updateConfig := container.UpdateConfig{
-		Resources: resources,
+		Resources:     resources,
+		RestartPolicy: restartPolicy,
 	}
 	}
 
 
 	names := cmd.Args()
 	names := cmd.Args()

+ 2 - 1
api/server/router/container/container_routes.go

@@ -322,7 +322,8 @@ func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.Respon
 	}
 	}
 
 
 	hostConfig := &container.HostConfig{
 	hostConfig := &container.HostConfig{
-		Resources: updateConfig.Resources,
+		Resources:     updateConfig.Resources,
+		RestartPolicy: updateConfig.RestartPolicy,
 	}
 	}
 
 
 	name := vars["name"]
 	name := vars["name"]

+ 1 - 1
cli/common.go

@@ -64,7 +64,7 @@ var dockerCommands = []Command{
 	{"tag", "Tag an image into a repository"},
 	{"tag", "Tag an image into a repository"},
 	{"top", "Display the running processes of a container"},
 	{"top", "Display the running processes of a container"},
 	{"unpause", "Unpause all processes within a container"},
 	{"unpause", "Unpause all processes within a container"},
-	{"update", "Update resources of one or more containers"},
+	{"update", "Update configuration of one or more containers"},
 	{"version", "Show the Docker version information"},
 	{"version", "Show the Docker version information"},
 	{"volume", "Manage Docker volumes"},
 	{"volume", "Manage Docker volumes"},
 	{"wait", "Block until a container stops, then print its exit code"},
 	{"wait", "Block until a container stops, then print its exit code"},

+ 17 - 0
container/container.go

@@ -594,3 +594,20 @@ func (container *Container) InitDNSHostConfig() {
 		container.HostConfig.DNSOptions = make([]string, 0)
 		container.HostConfig.DNSOptions = make([]string, 0)
 	}
 	}
 }
 }
+
+// UpdateMonitor updates monitor configure for running container
+func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
+	monitor := container.monitor
+	// No need to update monitor if container hasn't got one
+	// monitor will be generated correctly according to container
+	if monitor == nil {
+		return
+	}
+
+	monitor.mux.Lock()
+	// to check whether restart policy has changed.
+	if restartPolicy.Name != "" && !monitor.restartPolicy.IsSame(&restartPolicy) {
+		monitor.restartPolicy = restartPolicy
+	}
+	monitor.mux.Unlock()
+}

+ 7 - 1
container/container_unix.go

@@ -564,10 +564,11 @@ func updateCommand(c *execdriver.Command, resources containertypes.Resources) {
 	c.Resources.KernelMemory = resources.KernelMemory
 	c.Resources.KernelMemory = resources.KernelMemory
 }
 }
 
 
-// UpdateContainer updates resources of a container.
+// UpdateContainer updates configuration of a container.
 func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
 func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
 	container.Lock()
 	container.Lock()
 
 
+	// update resources of container
 	resources := hostConfig.Resources
 	resources := hostConfig.Resources
 	cResources := &container.HostConfig.Resources
 	cResources := &container.HostConfig.Resources
 	if resources.BlkioWeight != 0 {
 	if resources.BlkioWeight != 0 {
@@ -600,6 +601,11 @@ func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfi
 	if resources.KernelMemory != 0 {
 	if resources.KernelMemory != 0 {
 		cResources.KernelMemory = resources.KernelMemory
 		cResources.KernelMemory = resources.KernelMemory
 	}
 	}
+
+	// update HostConfig of container
+	if hostConfig.RestartPolicy.Name != "" {
+		container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
+	}
 	container.Unlock()
 	container.Unlock()
 
 
 	// If container is not running, update hostConfig struct is enough,
 	// If container is not running, update hostConfig struct is enough,

+ 16 - 1
container/container_windows.go

@@ -3,6 +3,7 @@
 package container
 package container
 
 
 import (
 import (
+	"fmt"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 
 
@@ -45,8 +46,22 @@ func (container *Container) TmpfsMounts() []execdriver.Mount {
 	return nil
 	return nil
 }
 }
 
 
-// UpdateContainer updates resources of a container
+// UpdateContainer updates configuration of a container
 func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error {
 func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error {
+	container.Lock()
+	defer container.Unlock()
+	resources := hostConfig.Resources
+	if resources.BlkioWeight != 0 || resources.CPUShares != 0 ||
+		resources.CPUPeriod != 0 || resources.CPUQuota != 0 ||
+		resources.CpusetCpus != "" || resources.CpusetMems != "" ||
+		resources.Memory != 0 || resources.MemorySwap != 0 ||
+		resources.MemoryReservation != 0 || resources.KernelMemory != 0 {
+		return fmt.Errorf("Resource updating isn't supported on Windows")
+	}
+	// update HostConfig of container
+	if hostConfig.RestartPolicy.Name != "" {
+		container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
+	}
 	return nil
 	return nil
 }
 }
 
 

+ 2 - 2
container/monitor.go

@@ -79,11 +79,11 @@ type containerMonitor struct {
 
 
 // StartMonitor initializes a containerMonitor for this container with the provided supervisor and restart policy
 // StartMonitor initializes a containerMonitor for this container with the provided supervisor and restart policy
 // and starts the container's process.
 // and starts the container's process.
-func (container *Container) StartMonitor(s supervisor, policy container.RestartPolicy) error {
+func (container *Container) StartMonitor(s supervisor) error {
 	container.monitor = &containerMonitor{
 	container.monitor = &containerMonitor{
 		supervisor:    s,
 		supervisor:    s,
 		container:     container,
 		container:     container,
-		restartPolicy: policy,
+		restartPolicy: container.HostConfig.RestartPolicy,
 		timeIncrement: defaultTimeIncrement,
 		timeIncrement: defaultTimeIncrement,
 		stopChan:      make(chan struct{}),
 		stopChan:      make(chan struct{}),
 		startSignal:   make(chan struct{}),
 		startSignal:   make(chan struct{}),

+ 2 - 2
container/state.go

@@ -119,11 +119,11 @@ func wait(waitChan <-chan struct{}, timeout time.Duration) error {
 	}
 	}
 }
 }
 
 
-// waitRunning waits until state is running. If state is already
+// WaitRunning waits until state is running. If state is already
 // running it returns immediately. If you want wait forever you must
 // running it returns immediately. If you want wait forever you must
 // supply negative timeout. Returns pid, that was passed to
 // supply negative timeout. Returns pid, that was passed to
 // SetRunning.
 // SetRunning.
-func (s *State) waitRunning(timeout time.Duration) (int, error) {
+func (s *State) WaitRunning(timeout time.Duration) (int, error) {
 	s.Lock()
 	s.Lock()
 	if s.Running {
 	if s.Running {
 		pid := s.Pid
 		pid := s.Pid

+ 5 - 5
container/state_test.go

@@ -14,7 +14,7 @@ func TestStateRunStop(t *testing.T) {
 		started := make(chan struct{})
 		started := make(chan struct{})
 		var pid int64
 		var pid int64
 		go func() {
 		go func() {
-			runPid, _ := s.waitRunning(-1 * time.Second)
+			runPid, _ := s.WaitRunning(-1 * time.Second)
 			atomic.StoreInt64(&pid, int64(runPid))
 			atomic.StoreInt64(&pid, int64(runPid))
 			close(started)
 			close(started)
 		}()
 		}()
@@ -41,8 +41,8 @@ func TestStateRunStop(t *testing.T) {
 		if runPid != i+100 {
 		if runPid != i+100 {
 			t.Fatalf("Pid %v, expected %v", runPid, i+100)
 			t.Fatalf("Pid %v, expected %v", runPid, i+100)
 		}
 		}
-		if pid, err := s.waitRunning(-1 * time.Second); err != nil || pid != i+100 {
-			t.Fatalf("waitRunning returned pid: %v, err: %v, expected pid: %v, err: %v", pid, err, i+100, nil)
+		if pid, err := s.WaitRunning(-1 * time.Second); err != nil || pid != i+100 {
+			t.Fatalf("WaitRunning returned pid: %v, err: %v, expected pid: %v, err: %v", pid, err, i+100, nil)
 		}
 		}
 
 
 		stopped := make(chan struct{})
 		stopped := make(chan struct{})
@@ -82,7 +82,7 @@ func TestStateTimeoutWait(t *testing.T) {
 	s := NewState()
 	s := NewState()
 	started := make(chan struct{})
 	started := make(chan struct{})
 	go func() {
 	go func() {
-		s.waitRunning(100 * time.Millisecond)
+		s.WaitRunning(100 * time.Millisecond)
 		close(started)
 		close(started)
 	}()
 	}()
 	select {
 	select {
@@ -98,7 +98,7 @@ func TestStateTimeoutWait(t *testing.T) {
 
 
 	stopped := make(chan struct{})
 	stopped := make(chan struct{})
 	go func() {
 	go func() {
-		s.waitRunning(100 * time.Millisecond)
+		s.WaitRunning(100 * time.Millisecond)
 		close(stopped)
 		close(stopped)
 	}()
 	}()
 	select {
 	select {

+ 3 - 3
daemon/execdriver/windows/update.go

@@ -3,12 +3,12 @@
 package windows
 package windows
 
 
 import (
 import (
-	"fmt"
-
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 )
 )
 
 
 // Update updates resource configs for a container.
 // Update updates resource configs for a container.
 func (d *Driver) Update(c *execdriver.Command) error {
 func (d *Driver) Update(c *execdriver.Command) error {
-	return fmt.Errorf("Windows: Update not implemented")
+	// Updating resource isn't supported on Windows
+	// but we should return nil for enabling updating container
+	return nil
 }
 }

+ 1 - 1
daemon/start.go

@@ -154,7 +154,7 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
 }
 }
 
 
 func (daemon *Daemon) waitForStart(container *container.Container) error {
 func (daemon *Daemon) waitForStart(container *container.Container) error {
-	return container.StartMonitor(daemon, container.HostConfig.RestartPolicy)
+	return container.StartMonitor(daemon)
 }
 }
 
 
 // Cleanup releases any network resources allocated to the container along with any rules
 // Cleanup releases any network resources allocated to the container along with any rules

+ 11 - 2
daemon/update.go

@@ -2,12 +2,13 @@ package daemon
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"time"
 
 
 	derr "github.com/docker/docker/errors"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/engine-api/types/container"
 	"github.com/docker/engine-api/types/container"
 )
 )
 
 
-// ContainerUpdate updates resources of the container
+// ContainerUpdate updates configuration of the container
 func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig) ([]string, error) {
 func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig) ([]string, error) {
 	var warnings []string
 	var warnings []string
 
 
@@ -58,11 +59,19 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
 		return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
 		return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
 	}
 	}
 
 
+	// if Restart Policy changed, we need to update container monitor
+	container.UpdateMonitor(hostConfig.RestartPolicy)
+
+	// if container is restarting, wait 5 seconds until it's running
+	if container.IsRestarting() {
+		container.WaitRunning(5 * time.Second)
+	}
+
 	// If container is not running, update hostConfig struct is enough,
 	// If container is not running, update hostConfig struct is enough,
 	// resources will be updated when the container is started again.
 	// resources will be updated when the container is started again.
 	// If container is running (including paused), we need to update configs
 	// If container is running (including paused), we need to update configs
 	// to the real world.
 	// to the real world.
-	if container.IsRunning() {
+	if container.IsRunning() && !container.IsRestarting() {
 		if err := daemon.execDriver.Update(container.Command); err != nil {
 		if err := daemon.execDriver.Update(container.Command); err != nil {
 			return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
 			return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
 		}
 		}

+ 1 - 1
docs/reference/api/docker_remote_api.md

@@ -117,7 +117,7 @@ This section lists each version from latest to oldest.  Each listing includes a
 
 
 * `GET /containers/json` returns the state of the container, one of `created`, `restarting`, `running`, `paused`, `exited` or `dead`.
 * `GET /containers/json` returns the state of the container, one of `created`, `restarting`, `running`, `paused`, `exited` or `dead`.
 * `GET /networks/(name)` now returns an `Internal` field showing whether the network is internal or not.
 * `GET /networks/(name)` now returns an `Internal` field showing whether the network is internal or not.
-
+* `POST /containers/(name)/update` now supports updating container's restart policy.
 
 
 ### v1.22 API changes
 ### v1.22 API changes
 
 

+ 5 - 1
docs/reference/api/docker_remote_api_v1.23.md

@@ -1031,7 +1031,7 @@ Status Codes:
 
 
 `POST /containers/(id)/update`
 `POST /containers/(id)/update`
 
 
-Update resource configs of one or more containers.
+Update configuration of one or more containers.
 
 
 **Example request**:
 **Example request**:
 
 
@@ -1049,6 +1049,10 @@ Update resource configs of one or more containers.
          "MemorySwap": 514288000,
          "MemorySwap": 514288000,
          "MemoryReservation": 209715200,
          "MemoryReservation": 209715200,
          "KernelMemory": 52428800,
          "KernelMemory": 52428800,
+         "RestartPolicy": {
+           "MaximumRetryCount": 4,
+           "Name": "on-failure"
+         },
        }
        }
 
 
 **Example response**:
 **Example response**:

+ 17 - 5
docs/reference/commandline/update.md

@@ -12,7 +12,7 @@ parent = "smn_cli"
 
 
     Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
     Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
 
 
-    Updates container resource limits
+    Update configuration of one or more containers
 
 
       --help=false               Print usage
       --help=false               Print usage
       --blkio-weight=0           Block IO (relative weight), between 10 and 1000
       --blkio-weight=0           Block IO (relative weight), between 10 and 1000
@@ -25,11 +25,12 @@ parent = "smn_cli"
       --memory-reservation=""    Memory soft limit
       --memory-reservation=""    Memory soft limit
       --memory-swap=""           A positive integer equal to memory plus swap. Specify -1 to enable unlimited swap
       --memory-swap=""           A positive integer equal to memory plus swap. Specify -1 to enable unlimited swap
       --kernel-memory=""         Kernel memory limit: container must be stopped
       --kernel-memory=""         Kernel memory limit: container must be stopped
+      --restart                  Restart policy to apply when a container exits
 
 
-The `docker update` command dynamically updates container resources.  Use this
-command to prevent containers from consuming too many resources from their
-Docker host.  With a single command, you can place limits on a single
-container or on many. To specify more than one container, provide
+The `docker update` command dynamically updates container configuration.
+You can use this command to prevent containers from consuming too many resources
+from their Docker host.  With a single command, you can place limits on
+a single container or on many. To specify more than one container, provide
 space-separated list of container names or IDs.
 space-separated list of container names or IDs.
 
 
 With the exception of the `--kernel-memory` value, you can specify these
 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
 stopped container, the next time you restart it, the container uses those
 stopped container, the next time you restart it, the container uses those
 values.
 values.
 
 
+Another configuration you can change with this command is restart policy,
+new restart policy will take effect instantly after you run `docker update`
+on a container.
+
 ## EXAMPLES
 ## EXAMPLES
 
 
 The following sections illustrate ways to use this command.
 The following sections illustrate ways to use this command.
@@ -59,3 +64,10 @@ To update multiple resource configurations for multiple containers:
 ```bash
 ```bash
 $ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
 $ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
 ```
 ```
+
+### Update a container's restart policy
+
+To update restart policy for one or more containers:
+```bash
+$ docker update --restart=on-failure:3 abebf7571666 hopeful_morse
+```

+ 31 - 0
integration-cli/docker_cli_update_test.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"strings"
+	"time"
+
+	"github.com/docker/docker/pkg/integration/checker"
+	"github.com/go-check/check"
+)
+
+func (s *DockerSuite) TestUpdateRestartPolicy(c *check.C) {
+	out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "sh", "-c", "sleep 1 && false")
+	timeout := 60 * time.Second
+	if daemonPlatform == "windows" {
+		timeout = 100 * time.Second
+	}
+
+	id := strings.TrimSpace(string(out))
+
+	// update restart policy to on-failure:5
+	dockerCmd(c, "update", "--restart=on-failure:5", id)
+
+	err := waitExited(id, timeout)
+	c.Assert(err, checker.IsNil)
+
+	count := inspectField(c, id, "RestartCount")
+	c.Assert(count, checker.Equals, "5")
+
+	maximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
+	c.Assert(maximumRetryCount, checker.Equals, "5")
+}

+ 21 - 6
man/docker-update.1.md

@@ -2,7 +2,7 @@
 % Docker Community
 % Docker Community
 % JUNE 2014
 % JUNE 2014
 # NAME
 # NAME
-docker-update - Update resource configs of one or more containers
+docker-update - Update configuration of one or more containers
 
 
 # SYNOPSIS
 # SYNOPSIS
 **docker update**
 **docker update**
@@ -17,15 +17,16 @@ docker-update - Update resource configs of one or more containers
 [**-m**|**--memory**[=*MEMORY*]]
 [**-m**|**--memory**[=*MEMORY*]]
 [**--memory-reservation**[=*MEMORY-RESERVATION*]]
 [**--memory-reservation**[=*MEMORY-RESERVATION*]]
 [**--memory-swap**[=*MEMORY-SWAP*]]
 [**--memory-swap**[=*MEMORY-SWAP*]]
+[**--restart**[=*""*]]
 CONTAINER [CONTAINER...]
 CONTAINER [CONTAINER...]
 
 
 # DESCRIPTION
 # DESCRIPTION
 
 
-The `docker update` command dynamically updates container resources.  Use this
-command to prevent containers from consuming too many resources from their
-Docker host.  With a single command, you can place limits on a single
-container or on many. To specify more than one container, provide
-space-separated list of container names or IDs.
+The `docker update` command dynamically updates container configuration.
+you can Use this command to prevent containers from consuming too many 
+resources from their Docker host.  With a single command, you can place 
+limits on a single container or on many. To specify more than one container,
+provide space-separated list of container names or IDs.
 
 
 With the exception of the `--kernel-memory` value, you can specify these
 With the exception of the `--kernel-memory` value, you can specify these
 options on a running or a stopped container. You can only update
 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
 stopped container, the next time you restart it, the container uses those
 stopped container, the next time you restart it, the container uses those
 values.
 values.
 
 
+Another configuration you can change with this command is restart policy,
+new restart policy will take effect instantly after you run `docker update`
+on a container.
+
 # OPTIONS
 # OPTIONS
 **--blkio-weight**=0
 **--blkio-weight**=0
    Block IO weight (relative weight) accepts a weight value between 10 and 1000.
    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.
 **--memory-swap**=""
 **--memory-swap**=""
    Total memory limit (memory + swap)
    Total memory limit (memory + swap)
 
 
+**--restart**=""
+   Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
+
 # EXAMPLES
 # EXAMPLES
 
 
 The following sections illustrate ways to use this command.
 The following sections illustrate ways to use this command.
@@ -91,3 +99,10 @@ To update multiple resource configurations for multiple containers:
 ```bash
 ```bash
 $ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
 $ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
 ```
 ```
+
+### Update a container's restart policy
+
+To update restart policy for one or more containers:
+```bash
+$ docker update --restart=on-failure:3 abebf7571666 hopeful_morse
+```