Skip to content

Commit 90de570

Browse files
committed
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>
1 parent 952902e commit 90de570

9 files changed

Lines changed: 43 additions & 29 deletions

File tree

api/server/router/container/backend.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ type stateBackend interface {
3737
ContainerPause(name string) error
3838
ContainerRename(oldName, newName string) error
3939
ContainerResize(name string, height, width int) error
40-
ContainerRestart(name string, seconds *int) error
40+
ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
4141
ContainerRm(name string, config *types.ContainerRmConfig) error
4242
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
43-
ContainerStop(name string, seconds *int) error
43+
ContainerStop(ctx context.Context, name string, options container.StopOptions) error
4444
ContainerUnpause(name string) error
4545
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
4646
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)

api/server/router/container/container_routes.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,16 +221,16 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
221221
return err
222222
}
223223

224-
var seconds *int
224+
var options container.StopOptions
225225
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
226226
valSeconds, err := strconv.Atoi(tmpSeconds)
227227
if err != nil {
228228
return err
229229
}
230-
seconds = &valSeconds
230+
options.Timeout = &valSeconds
231231
}
232232

233-
if err := s.backend.ContainerStop(vars["name"], seconds); err != nil {
233+
if err := s.backend.ContainerStop(ctx, vars["name"], options); err != nil {
234234
return err
235235
}
236236
w.WriteHeader(http.StatusNoContent)
@@ -278,16 +278,16 @@ func (s *containerRouter) postContainersRestart(ctx context.Context, w http.Resp
278278
return err
279279
}
280280

281-
var seconds *int
281+
var options container.StopOptions
282282
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
283283
valSeconds, err := strconv.Atoi(tmpSeconds)
284284
if err != nil {
285285
return err
286286
}
287-
seconds = &valSeconds
287+
options.Timeout = &valSeconds
288288
}
289289

290-
if err := s.backend.ContainerRestart(vars["name"], seconds); err != nil {
290+
if err := s.backend.ContainerRestart(ctx, vars["name"], options); err != nil {
291291
return err
292292
}
293293

api/types/container/config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ import (
1313
// Docker interprets it as 3 nanoseconds.
1414
const MinimumDuration = 1 * time.Millisecond
1515

16+
// StopOptions holds the options to stop or restart a container.
17+
type StopOptions struct {
18+
// Timeout (optional) is the timeout (in seconds) to wait for the container
19+
// to stop gracefully before forcibly terminating it with SIGKILL.
20+
//
21+
// - Use nil to use the default timeout (10 seconds).
22+
// - Use '-1' to wait indefinitely.
23+
// - Use '0' to not wait for the container to exit gracefully, and
24+
// immediately proceeds to forcibly terminating the container.
25+
// - Other positive values are used as timeout (in seconds).
26+
Timeout *int `json:",omitempty"`
27+
}
28+
1629
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
1730
type HealthConfig struct {
1831
// Test is the test to perform to check that the container is healthy.

daemon/cluster/executor/backend.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ type Backend interface {
3535
ReleaseIngress() (<-chan struct{}, error)
3636
CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
3737
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
38-
ContainerStop(name string, seconds *int) error
39-
ContainerLogs(context.Context, string, *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
38+
ContainerStop(ctx context.Context, name string, config container.StopOptions) error
39+
ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
4040
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
4141
ActivateContainerServiceBinding(containerName string) error
4242
DeactivateContainerServiceBinding(containerName string) error

daemon/cluster/executor/container/adapter.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -407,14 +407,13 @@ func (c *containerAdapter) wait(ctx context.Context) (<-chan containerpkg.StateS
407407
}
408408

409409
func (c *containerAdapter) shutdown(ctx context.Context) error {
410+
var options = containertypes.StopOptions{}
410411
// Default stop grace period to nil (daemon will use the stopTimeout of the container)
411-
var stopgrace *int
412-
spec := c.container.spec()
413-
if spec.StopGracePeriod != nil {
414-
stopgraceValue := int(spec.StopGracePeriod.Seconds)
415-
stopgrace = &stopgraceValue
412+
if spec := c.container.spec(); spec.StopGracePeriod != nil {
413+
timeout := int(spec.StopGracePeriod.Seconds)
414+
options.Timeout = &timeout
416415
}
417-
return c.backend.ContainerStop(c.container.name(), stopgrace)
416+
return c.backend.ContainerStop(ctx, c.container.name(), options)
418417
}
419418

420419
func (c *containerAdapter) terminate(ctx context.Context) error {

daemon/daemon.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ func (daemon *Daemon) waitForStartupDone() {
11171117

11181118
func (daemon *Daemon) shutdownContainer(c *container.Container) error {
11191119
// If container failed to exit in stopTimeout seconds of SIGTERM, then using the force
1120-
if err := daemon.containerStop(c, nil); err != nil {
1120+
if err := daemon.containerStop(context.TODO(), c, containertypes.StopOptions{}); err != nil {
11211121
return fmt.Errorf("Failed to stop container %s with error: %v", c.ID, err)
11221122
}
11231123

daemon/delete.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package daemon // import "github.com/docker/docker/daemon"
22

33
import (
4+
"context"
45
"fmt"
56
"os"
67
"path"
78
"strings"
89
"time"
910

1011
"github.com/docker/docker/api/types"
12+
containertypes "github.com/docker/docker/api/types/container"
1113
"github.com/docker/docker/container"
1214
"github.com/docker/docker/errdefs"
1315
"github.com/docker/docker/pkg/containerfs"
@@ -109,7 +111,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, config ty
109111
// If you arrived here and know the answer, you earned yourself a picture
110112
// of a cute animal of your own choosing.
111113
var stopTimeout = 3
112-
if err := daemon.containerStop(container, &stopTimeout); err != nil {
114+
if err := daemon.containerStop(context.TODO(), container, containertypes.StopOptions{Timeout: &stopTimeout}); err != nil {
113115
return err
114116
}
115117

daemon/restart.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package daemon // import "github.com/docker/docker/daemon"
22

33
import (
4+
"context"
45
"fmt"
56

67
containertypes "github.com/docker/docker/api/types/container"
@@ -14,12 +15,12 @@ import (
1415
// timeout, ContainerRestart will wait forever until a graceful
1516
// stop. Returns an error if the container cannot be found, or if
1617
// there is an underlying error at any stage of the restart.
17-
func (daemon *Daemon) ContainerRestart(name string, seconds *int) error {
18+
func (daemon *Daemon) ContainerRestart(ctx context.Context, name string, options containertypes.StopOptions) error {
1819
ctr, err := daemon.GetContainer(name)
1920
if err != nil {
2021
return err
2122
}
22-
err = daemon.containerRestart(ctr, seconds)
23+
err = daemon.containerRestart(ctx, ctr, options)
2324
if err != nil {
2425
return fmt.Errorf("Cannot restart container %s: %v", name, err)
2526
}
@@ -31,7 +32,7 @@ func (daemon *Daemon) ContainerRestart(name string, seconds *int) error {
3132
// container. When stopping, wait for the given duration in seconds to
3233
// gracefully stop, before forcefully terminating the container. If
3334
// given a negative duration, wait forever for a graceful stop.
34-
func (daemon *Daemon) containerRestart(container *container.Container, seconds *int) error {
35+
func (daemon *Daemon) containerRestart(ctx context.Context, container *container.Container, options containertypes.StopOptions) error {
3536
// Determine isolation. If not specified in the hostconfig, use daemon default.
3637
actualIsolation := container.HostConfig.Isolation
3738
if containertypes.Isolation.IsDefault(actualIsolation) {
@@ -56,7 +57,7 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds *
5657
autoRemove := container.HostConfig.AutoRemove
5758

5859
container.HostConfig.AutoRemove = false
59-
err := daemon.containerStop(container, seconds)
60+
err := daemon.containerStop(ctx, container, options)
6061
// restore AutoRemove irrespective of whether the stop worked or not
6162
container.HostConfig.AutoRemove = autoRemove
6263
// containerStop will write HostConfig to disk, we shall restore AutoRemove

daemon/stop.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"time"
66

7+
containertypes "github.com/docker/docker/api/types/container"
78
"github.com/docker/docker/container"
89
"github.com/docker/docker/errdefs"
910
"github.com/pkg/errors"
@@ -18,25 +19,23 @@ import (
1819
// If the timeout is nil, the container's StopTimeout value is used, if set,
1920
// otherwise the engine default. A negative timeout value can be specified,
2021
// meaning no timeout, i.e. no forceful termination is performed.
21-
func (daemon *Daemon) ContainerStop(name string, timeout *int) error {
22+
func (daemon *Daemon) ContainerStop(ctx context.Context, name string, options containertypes.StopOptions) error {
2223
ctr, err := daemon.GetContainer(name)
2324
if err != nil {
2425
return err
2526
}
2627
if !ctr.IsRunning() {
2728
return containerNotModifiedError{}
2829
}
29-
err = daemon.containerStop(ctr, timeout)
30+
err = daemon.containerStop(ctx, ctr, options)
3031
if err != nil {
3132
return errdefs.System(errors.Wrapf(err, "cannot stop container: %s", name))
3233
}
3334
return nil
3435
}
3536

3637
// containerStop sends a stop signal, waits, sends a kill signal.
37-
func (daemon *Daemon) containerStop(ctr *container.Container, seconds *int) (retErr error) {
38-
// TODO propagate a context down to this function
39-
ctx := context.TODO()
38+
func (daemon *Daemon) containerStop(ctx context.Context, ctr *container.Container, options containertypes.StopOptions) (retErr error) {
4039
if !ctr.IsRunning() {
4140
return nil
4241
}
@@ -45,8 +44,8 @@ func (daemon *Daemon) containerStop(ctr *container.Container, seconds *int) (ret
4544
stopSignal = ctr.StopSignal()
4645
stopTimeout = ctr.StopTimeout()
4746
)
48-
if seconds != nil {
49-
stopTimeout = *seconds
47+
if options.Timeout != nil {
48+
stopTimeout = *options.Timeout
5049
}
5150

5251
var wait time.Duration

0 commit comments

Comments
 (0)