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>
This commit is contained in:
Zhang Wei 2016-01-04 23:58:20 +08:00
parent 6668326aa8
commit ff3ea4c90f
17 changed files with 154 additions and 33 deletions

View File

@ -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,
@ -84,6 +94,7 @@ 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()

View File

@ -323,6 +323,7 @@ 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"]

View File

@ -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"},

View File

@ -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()
}

View File

@ -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,

View File

@ -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
} }

View File

@ -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{}),

View File

@ -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

View File

@ -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 { 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) 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 {

View File

@ -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
} }

View File

@ -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

View File

@ -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())
} }

View File

@ -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

View File

@ -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**:

View File

@ -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 The `docker update` command dynamically updates container configuration.
command to prevent containers from consuming too many resources from their You can use this command to prevent containers from consuming too many resources
Docker host. With a single command, you can place limits on a single from their Docker host. With a single command, you can place limits on
container or on many. To specify more than one container, provide 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
```

View File

@ -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")
}

View File

@ -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 The `docker update` command dynamically updates container configuration.
command to prevent containers from consuming too many resources from their you can Use this command to prevent containers from consuming too many
Docker host. With a single command, you can place limits on a single resources from their Docker host. With a single command, you can place
container or on many. To specify more than one container, provide limits on a single container or on many. To specify more than one container,
space-separated list of container names or IDs. 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
```