mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
backend: add StopOptions to ContainerRestart and ContainerStop
While we're modifying the interface, also add a context to both. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
952902efbc
commit
90de570cfa
9 changed files with 43 additions and 29 deletions
|
@ -37,10 +37,10 @@ type stateBackend interface {
|
||||||
ContainerPause(name string) error
|
ContainerPause(name string) error
|
||||||
ContainerRename(oldName, newName string) error
|
ContainerRename(oldName, newName string) error
|
||||||
ContainerResize(name string, height, width int) error
|
ContainerResize(name string, height, width int) error
|
||||||
ContainerRestart(name string, seconds *int) error
|
ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
|
||||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||||
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
||||||
ContainerStop(name string, seconds *int) error
|
ContainerStop(ctx context.Context, name string, options container.StopOptions) error
|
||||||
ContainerUnpause(name string) error
|
ContainerUnpause(name string) error
|
||||||
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
|
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
|
||||||
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
||||||
|
|
|
@ -221,16 +221,16 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var seconds *int
|
var options container.StopOptions
|
||||||
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
|
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
|
||||||
valSeconds, err := strconv.Atoi(tmpSeconds)
|
valSeconds, err := strconv.Atoi(tmpSeconds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
seconds = &valSeconds
|
options.Timeout = &valSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.backend.ContainerStop(vars["name"], seconds); err != nil {
|
if err := s.backend.ContainerStop(ctx, vars["name"], options); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -278,16 +278,16 @@ func (s *containerRouter) postContainersRestart(ctx context.Context, w http.Resp
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var seconds *int
|
var options container.StopOptions
|
||||||
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
|
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
|
||||||
valSeconds, err := strconv.Atoi(tmpSeconds)
|
valSeconds, err := strconv.Atoi(tmpSeconds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
seconds = &valSeconds
|
options.Timeout = &valSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.backend.ContainerRestart(vars["name"], seconds); err != nil {
|
if err := s.backend.ContainerRestart(ctx, vars["name"], options); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,19 @@ import (
|
||||||
// Docker interprets it as 3 nanoseconds.
|
// Docker interprets it as 3 nanoseconds.
|
||||||
const MinimumDuration = 1 * time.Millisecond
|
const MinimumDuration = 1 * time.Millisecond
|
||||||
|
|
||||||
|
// StopOptions holds the options to stop or restart a container.
|
||||||
|
type StopOptions struct {
|
||||||
|
// Timeout (optional) is the timeout (in seconds) to wait for the container
|
||||||
|
// to stop gracefully before forcibly terminating it with SIGKILL.
|
||||||
|
//
|
||||||
|
// - Use nil to use the default timeout (10 seconds).
|
||||||
|
// - Use '-1' to wait indefinitely.
|
||||||
|
// - Use '0' to not wait for the container to exit gracefully, and
|
||||||
|
// immediately proceeds to forcibly terminating the container.
|
||||||
|
// - Other positive values are used as timeout (in seconds).
|
||||||
|
Timeout *int `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
||||||
type HealthConfig struct {
|
type HealthConfig struct {
|
||||||
// Test is the test to perform to check that the container is healthy.
|
// Test is the test to perform to check that the container is healthy.
|
||||||
|
|
|
@ -35,8 +35,8 @@ type Backend interface {
|
||||||
ReleaseIngress() (<-chan struct{}, error)
|
ReleaseIngress() (<-chan struct{}, error)
|
||||||
CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||||
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
||||||
ContainerStop(name string, seconds *int) error
|
ContainerStop(ctx context.Context, name string, config container.StopOptions) error
|
||||||
ContainerLogs(context.Context, string, *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||||
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||||
ActivateContainerServiceBinding(containerName string) error
|
ActivateContainerServiceBinding(containerName string) error
|
||||||
DeactivateContainerServiceBinding(containerName string) error
|
DeactivateContainerServiceBinding(containerName string) error
|
||||||
|
|
|
@ -407,14 +407,13 @@ func (c *containerAdapter) wait(ctx context.Context) (<-chan containerpkg.StateS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *containerAdapter) shutdown(ctx context.Context) error {
|
func (c *containerAdapter) shutdown(ctx context.Context) error {
|
||||||
|
var options = containertypes.StopOptions{}
|
||||||
// Default stop grace period to nil (daemon will use the stopTimeout of the container)
|
// Default stop grace period to nil (daemon will use the stopTimeout of the container)
|
||||||
var stopgrace *int
|
if spec := c.container.spec(); spec.StopGracePeriod != nil {
|
||||||
spec := c.container.spec()
|
timeout := int(spec.StopGracePeriod.Seconds)
|
||||||
if spec.StopGracePeriod != nil {
|
options.Timeout = &timeout
|
||||||
stopgraceValue := int(spec.StopGracePeriod.Seconds)
|
|
||||||
stopgrace = &stopgraceValue
|
|
||||||
}
|
}
|
||||||
return c.backend.ContainerStop(c.container.name(), stopgrace)
|
return c.backend.ContainerStop(ctx, c.container.name(), options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *containerAdapter) terminate(ctx context.Context) error {
|
func (c *containerAdapter) terminate(ctx context.Context) error {
|
||||||
|
|
|
@ -1117,7 +1117,7 @@ func (daemon *Daemon) waitForStartupDone() {
|
||||||
|
|
||||||
func (daemon *Daemon) shutdownContainer(c *container.Container) error {
|
func (daemon *Daemon) shutdownContainer(c *container.Container) error {
|
||||||
// If container failed to exit in stopTimeout seconds of SIGTERM, then using the force
|
// If container failed to exit in stopTimeout seconds of SIGTERM, then using the force
|
||||||
if err := daemon.containerStop(c, nil); err != nil {
|
if err := daemon.containerStop(context.TODO(), c, containertypes.StopOptions{}); err != nil {
|
||||||
return fmt.Errorf("Failed to stop container %s with error: %v", c.ID, err)
|
return fmt.Errorf("Failed to stop container %s with error: %v", c.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package daemon // import "github.com/docker/docker/daemon"
|
package daemon // import "github.com/docker/docker/daemon"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -8,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
containertypes "github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/docker/docker/pkg/containerfs"
|
"github.com/docker/docker/pkg/containerfs"
|
||||||
|
@ -109,7 +111,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, config ty
|
||||||
// If you arrived here and know the answer, you earned yourself a picture
|
// If you arrived here and know the answer, you earned yourself a picture
|
||||||
// of a cute animal of your own choosing.
|
// of a cute animal of your own choosing.
|
||||||
var stopTimeout = 3
|
var stopTimeout = 3
|
||||||
if err := daemon.containerStop(container, &stopTimeout); err != nil {
|
if err := daemon.containerStop(context.TODO(), container, containertypes.StopOptions{Timeout: &stopTimeout}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package daemon // import "github.com/docker/docker/daemon"
|
package daemon // import "github.com/docker/docker/daemon"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
containertypes "github.com/docker/docker/api/types/container"
|
containertypes "github.com/docker/docker/api/types/container"
|
||||||
|
@ -14,12 +15,12 @@ import (
|
||||||
// timeout, ContainerRestart will wait forever until a graceful
|
// timeout, ContainerRestart will wait forever until a graceful
|
||||||
// stop. Returns an error if the container cannot be found, or if
|
// stop. Returns an error if the container cannot be found, or if
|
||||||
// there is an underlying error at any stage of the restart.
|
// there is an underlying error at any stage of the restart.
|
||||||
func (daemon *Daemon) ContainerRestart(name string, seconds *int) error {
|
func (daemon *Daemon) ContainerRestart(ctx context.Context, name string, options containertypes.StopOptions) error {
|
||||||
ctr, err := daemon.GetContainer(name)
|
ctr, err := daemon.GetContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = daemon.containerRestart(ctr, seconds)
|
err = daemon.containerRestart(ctx, ctr, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Cannot restart container %s: %v", name, err)
|
return fmt.Errorf("Cannot restart container %s: %v", name, err)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +32,7 @@ func (daemon *Daemon) ContainerRestart(name string, seconds *int) error {
|
||||||
// container. When stopping, wait for the given duration in seconds to
|
// container. When stopping, wait for the given duration in seconds to
|
||||||
// gracefully stop, before forcefully terminating the container. If
|
// gracefully stop, before forcefully terminating the container. If
|
||||||
// given a negative duration, wait forever for a graceful stop.
|
// given a negative duration, wait forever for a graceful stop.
|
||||||
func (daemon *Daemon) containerRestart(container *container.Container, seconds *int) error {
|
func (daemon *Daemon) containerRestart(ctx context.Context, container *container.Container, options containertypes.StopOptions) error {
|
||||||
// Determine isolation. If not specified in the hostconfig, use daemon default.
|
// Determine isolation. If not specified in the hostconfig, use daemon default.
|
||||||
actualIsolation := container.HostConfig.Isolation
|
actualIsolation := container.HostConfig.Isolation
|
||||||
if containertypes.Isolation.IsDefault(actualIsolation) {
|
if containertypes.Isolation.IsDefault(actualIsolation) {
|
||||||
|
@ -56,7 +57,7 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds *
|
||||||
autoRemove := container.HostConfig.AutoRemove
|
autoRemove := container.HostConfig.AutoRemove
|
||||||
|
|
||||||
container.HostConfig.AutoRemove = false
|
container.HostConfig.AutoRemove = false
|
||||||
err := daemon.containerStop(container, seconds)
|
err := daemon.containerStop(ctx, container, options)
|
||||||
// restore AutoRemove irrespective of whether the stop worked or not
|
// restore AutoRemove irrespective of whether the stop worked or not
|
||||||
container.HostConfig.AutoRemove = autoRemove
|
container.HostConfig.AutoRemove = autoRemove
|
||||||
// containerStop will write HostConfig to disk, we shall restore AutoRemove
|
// containerStop will write HostConfig to disk, we shall restore AutoRemove
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
containertypes "github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -18,7 +19,7 @@ import (
|
||||||
// If the timeout is nil, the container's StopTimeout value is used, if set,
|
// If the timeout is nil, the container's StopTimeout value is used, if set,
|
||||||
// otherwise the engine default. A negative timeout value can be specified,
|
// otherwise the engine default. A negative timeout value can be specified,
|
||||||
// meaning no timeout, i.e. no forceful termination is performed.
|
// meaning no timeout, i.e. no forceful termination is performed.
|
||||||
func (daemon *Daemon) ContainerStop(name string, timeout *int) error {
|
func (daemon *Daemon) ContainerStop(ctx context.Context, name string, options containertypes.StopOptions) error {
|
||||||
ctr, err := daemon.GetContainer(name)
|
ctr, err := daemon.GetContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -26,7 +27,7 @@ func (daemon *Daemon) ContainerStop(name string, timeout *int) error {
|
||||||
if !ctr.IsRunning() {
|
if !ctr.IsRunning() {
|
||||||
return containerNotModifiedError{}
|
return containerNotModifiedError{}
|
||||||
}
|
}
|
||||||
err = daemon.containerStop(ctr, timeout)
|
err = daemon.containerStop(ctx, ctr, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errdefs.System(errors.Wrapf(err, "cannot stop container: %s", name))
|
return errdefs.System(errors.Wrapf(err, "cannot stop container: %s", name))
|
||||||
}
|
}
|
||||||
|
@ -34,9 +35,7 @@ func (daemon *Daemon) ContainerStop(name string, timeout *int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// containerStop sends a stop signal, waits, sends a kill signal.
|
// containerStop sends a stop signal, waits, sends a kill signal.
|
||||||
func (daemon *Daemon) containerStop(ctr *container.Container, seconds *int) (retErr error) {
|
func (daemon *Daemon) containerStop(ctx context.Context, ctr *container.Container, options containertypes.StopOptions) (retErr error) {
|
||||||
// TODO propagate a context down to this function
|
|
||||||
ctx := context.TODO()
|
|
||||||
if !ctr.IsRunning() {
|
if !ctr.IsRunning() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -45,8 +44,8 @@ func (daemon *Daemon) containerStop(ctr *container.Container, seconds *int) (ret
|
||||||
stopSignal = ctr.StopSignal()
|
stopSignal = ctr.StopSignal()
|
||||||
stopTimeout = ctr.StopTimeout()
|
stopTimeout = ctr.StopTimeout()
|
||||||
)
|
)
|
||||||
if seconds != nil {
|
if options.Timeout != nil {
|
||||||
stopTimeout = *seconds
|
stopTimeout = *options.Timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
var wait time.Duration
|
var wait time.Duration
|
||||||
|
|
Loading…
Reference in a new issue