Sfoglia il codice sorgente

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 anni fa
parent
commit
ff3ea4c90f

+ 12 - 1
api/client/update.go

@@ -6,6 +6,7 @@ import (
 
 	Cli "github.com/docker/docker/cli"
 	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/runconfig/opts"
 	"github.com/docker/engine-api/types/container"
 	"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")
 	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")
+	flRestartPolicy := cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits")
 
 	cmd.Require(flag.Min, 1)
 	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{
 		BlkioWeight:       *flBlkioWeight,
 		CpusetCpus:        *flCpusetCpus,
@@ -83,7 +93,8 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
 	}
 
 	updateConfig := container.UpdateConfig{
-		Resources: resources,
+		Resources:     resources,
+		RestartPolicy: restartPolicy,
 	}
 
 	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{
-		Resources: updateConfig.Resources,
+		Resources:     updateConfig.Resources,
+		RestartPolicy: updateConfig.RestartPolicy,
 	}
 
 	name := vars["name"]

+ 1 - 1
cli/common.go

@@ -64,7 +64,7 @@ var dockerCommands = []Command{
 	{"tag", "Tag an image into a repository"},
 	{"top", "Display the running processes of 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"},
 	{"volume", "Manage Docker volumes"},
 	{"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)
 	}
 }
+
+// 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
 }
 
-// UpdateContainer updates resources of a container.
+// UpdateContainer updates configuration of a container.
 func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
 	container.Lock()
 
+	// update resources of container
 	resources := hostConfig.Resources
 	cResources := &container.HostConfig.Resources
 	if resources.BlkioWeight != 0 {
@@ -600,6 +601,11 @@ func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfi
 	if resources.KernelMemory != 0 {
 		cResources.KernelMemory = resources.KernelMemory
 	}
+
+	// update HostConfig of container
+	if hostConfig.RestartPolicy.Name != "" {
+		container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
+	}
 	container.Unlock()
 
 	// If container is not running, update hostConfig struct is enough,

+ 16 - 1
container/container_windows.go

@@ -3,6 +3,7 @@
 package container
 
 import (
+	"fmt"
 	"os"
 	"path/filepath"
 
@@ -45,8 +46,22 @@ func (container *Container) TmpfsMounts() []execdriver.Mount {
 	return nil
 }
 
-// UpdateContainer updates resources of a container
+// UpdateContainer updates configuration of a container
 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
 }
 

+ 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
 // 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{
 		supervisor:    s,
 		container:     container,
-		restartPolicy: policy,
+		restartPolicy: container.HostConfig.RestartPolicy,
 		timeIncrement: defaultTimeIncrement,
 		stopChan:      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
 // supply negative timeout. Returns pid, that was passed to
 // SetRunning.
-func (s *State) waitRunning(timeout time.Duration) (int, error) {
+func (s *State) WaitRunning(timeout time.Duration) (int, error) {
 	s.Lock()
 	if s.Running {
 		pid := s.Pid

+ 5 - 5
container/state_test.go

@@ -14,7 +14,7 @@ func TestStateRunStop(t *testing.T) {
 		started := make(chan struct{})
 		var pid int64
 		go func() {
-			runPid, _ := s.waitRunning(-1 * time.Second)
+			runPid, _ := s.WaitRunning(-1 * time.Second)
 			atomic.StoreInt64(&pid, int64(runPid))
 			close(started)
 		}()
@@ -41,8 +41,8 @@ func TestStateRunStop(t *testing.T) {
 		if 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{})
@@ -82,7 +82,7 @@ func TestStateTimeoutWait(t *testing.T) {
 	s := NewState()
 	started := make(chan struct{})
 	go func() {
-		s.waitRunning(100 * time.Millisecond)
+		s.WaitRunning(100 * time.Millisecond)
 		close(started)
 	}()
 	select {
@@ -98,7 +98,7 @@ func TestStateTimeoutWait(t *testing.T) {
 
 	stopped := make(chan struct{})
 	go func() {
-		s.waitRunning(100 * time.Millisecond)
+		s.WaitRunning(100 * time.Millisecond)
 		close(stopped)
 	}()
 	select {

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

@@ -3,12 +3,12 @@
 package windows
 
 import (
-	"fmt"
-
 	"github.com/docker/docker/daemon/execdriver"
 )
 
 // Update updates resource configs for a container.
 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 {
-	return container.StartMonitor(daemon, container.HostConfig.RestartPolicy)
+	return container.StartMonitor(daemon)
 }
 
 // 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 (
 	"fmt"
+	"time"
 
 	derr "github.com/docker/docker/errors"
 	"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) {
 	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())
 	}
 
+	// 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,
 	// resources will be updated when the container is started again.
 	// If container is running (including paused), we need to update configs
 	// to the real world.
-	if container.IsRunning() {
+	if container.IsRunning() && !container.IsRestarting() {
 		if err := daemon.execDriver.Update(container.Command); err != nil {
 			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 /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
 

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

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

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

@@ -12,7 +12,7 @@ parent = "smn_cli"
 
     Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
 
-    Updates container resource limits
+    Update configuration of one or more containers
 
       --help=false               Print usage
       --blkio-weight=0           Block IO (relative weight), between 10 and 1000
@@ -25,11 +25,12 @@ parent = "smn_cli"
       --memory-reservation=""    Memory soft limit
       --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
+      --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.
 
 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
 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
 
 The following sections illustrate ways to use this command.
@@ -59,3 +64,10 @@ To update multiple resource configurations for multiple containers:
 ```bash
 $ 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
 % JUNE 2014
 # NAME
-docker-update - Update resource configs of one or more containers
+docker-update - Update configuration of one or more containers
 
 # SYNOPSIS
 **docker update**
@@ -17,15 +17,16 @@ docker-update - Update resource configs of one or more containers
 [**-m**|**--memory**[=*MEMORY*]]
 [**--memory-reservation**[=*MEMORY-RESERVATION*]]
 [**--memory-swap**[=*MEMORY-SWAP*]]
+[**--restart**[=*""*]]
 CONTAINER [CONTAINER...]
 
 # 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
 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
 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
 **--blkio-weight**=0
    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**=""
    Total memory limit (memory + swap)
 
+**--restart**=""
+   Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
+
 # EXAMPLES
 
 The following sections illustrate ways to use this command.
@@ -91,3 +99,10 @@ To update multiple resource configurations for multiple containers:
 ```bash
 $ 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
+```