mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
client: ContainerStop(), ContainerRestart(): support stop-signal
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
9060126639
commit
e8fa708ae5
12 changed files with 68 additions and 40 deletions
|
@ -3,18 +3,22 @@ package client // import "github.com/docker/docker/client"
|
|||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"time"
|
||||
"strconv"
|
||||
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
||||
// ContainerRestart stops and starts a container again.
|
||||
// It makes the daemon wait for the container to be up again for
|
||||
// a specific amount of time, given the timeout.
|
||||
func (cli *Client) ContainerRestart(ctx context.Context, containerID string, timeout *time.Duration) error {
|
||||
func (cli *Client) ContainerRestart(ctx context.Context, containerID string, options container.StopOptions) error {
|
||||
query := url.Values{}
|
||||
if timeout != nil {
|
||||
query.Set("t", timetypes.DurationToSecondsString(*timeout))
|
||||
if options.Timeout != nil {
|
||||
query.Set("t", strconv.Itoa(*options.Timeout))
|
||||
}
|
||||
if options.Signal != "" && versions.GreaterThanOrEqualTo(cli.version, "1.42") {
|
||||
query.Set("signal", options.Signal)
|
||||
}
|
||||
resp, err := cli.post(ctx, "/containers/"+containerID+"/restart", query, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
|
@ -17,20 +17,23 @@ func TestContainerRestartError(t *testing.T) {
|
|||
client := &Client{
|
||||
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
||||
}
|
||||
timeout := 0 * time.Second
|
||||
err := client.ContainerRestart(context.Background(), "nothing", &timeout)
|
||||
err := client.ContainerRestart(context.Background(), "nothing", container.StopOptions{})
|
||||
if !errdefs.IsSystem(err) {
|
||||
t.Fatalf("expected a Server Error, got %[1]T: %[1]v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerRestart(t *testing.T) {
|
||||
expectedURL := "/containers/container_id/restart"
|
||||
const expectedURL = "/v1.42/containers/container_id/restart"
|
||||
client := &Client{
|
||||
client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
if !strings.HasPrefix(req.URL.Path, expectedURL) {
|
||||
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
|
||||
}
|
||||
s := req.URL.Query().Get("signal")
|
||||
if s != "SIGKILL" {
|
||||
return nil, fmt.Errorf("signal not set in URL query. Expected 'SIGKILL', got '%s'", s)
|
||||
}
|
||||
t := req.URL.Query().Get("t")
|
||||
if t != "100" {
|
||||
return nil, fmt.Errorf("t (timeout) not set in URL query properly. Expected '100', got %s", t)
|
||||
|
@ -40,9 +43,13 @@ func TestContainerRestart(t *testing.T) {
|
|||
Body: io.NopCloser(bytes.NewReader([]byte(""))),
|
||||
}, nil
|
||||
}),
|
||||
version: "1.42",
|
||||
}
|
||||
timeout := 100 * time.Second
|
||||
err := client.ContainerRestart(context.Background(), "container_id", &timeout)
|
||||
timeout := 100
|
||||
err := client.ContainerRestart(context.Background(), "container_id", container.StopOptions{
|
||||
Signal: "SIGKILL",
|
||||
Timeout: &timeout,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -3,9 +3,10 @@ package client // import "github.com/docker/docker/client"
|
|||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"time"
|
||||
"strconv"
|
||||
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
||||
// ContainerStop stops a container. In case the container fails to stop
|
||||
|
@ -15,10 +16,13 @@ import (
|
|||
// 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,
|
||||
// meaning no timeout, i.e. no forceful termination is performed.
|
||||
func (cli *Client) ContainerStop(ctx context.Context, containerID string, timeout *time.Duration) error {
|
||||
func (cli *Client) ContainerStop(ctx context.Context, containerID string, options container.StopOptions) error {
|
||||
query := url.Values{}
|
||||
if timeout != nil {
|
||||
query.Set("t", timetypes.DurationToSecondsString(*timeout))
|
||||
if options.Timeout != nil {
|
||||
query.Set("t", strconv.Itoa(*options.Timeout))
|
||||
}
|
||||
if options.Signal != "" && versions.GreaterThanOrEqualTo(cli.version, "1.42") {
|
||||
query.Set("signal", options.Signal)
|
||||
}
|
||||
resp, err := cli.post(ctx, "/containers/"+containerID+"/stop", query, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
|
@ -17,20 +17,23 @@ func TestContainerStopError(t *testing.T) {
|
|||
client := &Client{
|
||||
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
||||
}
|
||||
timeout := 0 * time.Second
|
||||
err := client.ContainerStop(context.Background(), "nothing", &timeout)
|
||||
err := client.ContainerStop(context.Background(), "nothing", container.StopOptions{})
|
||||
if !errdefs.IsSystem(err) {
|
||||
t.Fatalf("expected a Server Error, got %[1]T: %[1]v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerStop(t *testing.T) {
|
||||
expectedURL := "/containers/container_id/stop"
|
||||
const expectedURL = "/v1.42/containers/container_id/stop"
|
||||
client := &Client{
|
||||
client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
if !strings.HasPrefix(req.URL.Path, expectedURL) {
|
||||
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
|
||||
}
|
||||
s := req.URL.Query().Get("signal")
|
||||
if s != "SIGKILL" {
|
||||
return nil, fmt.Errorf("signal not set in URL query. Expected 'SIGKILL', got '%s'", s)
|
||||
}
|
||||
t := req.URL.Query().Get("t")
|
||||
if t != "100" {
|
||||
return nil, fmt.Errorf("t (timeout) not set in URL query properly. Expected '100', got %s", t)
|
||||
|
@ -40,9 +43,13 @@ func TestContainerStop(t *testing.T) {
|
|||
Body: io.NopCloser(bytes.NewReader([]byte(""))),
|
||||
}, nil
|
||||
}),
|
||||
version: "1.42",
|
||||
}
|
||||
timeout := 100 * time.Second
|
||||
err := client.ContainerStop(context.Background(), "container_id", &timeout)
|
||||
timeout := 100
|
||||
err := client.ContainerStop(context.Background(), "container_id", container.StopOptions{
|
||||
Signal: "SIGKILL",
|
||||
Timeout: &timeout,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
@ -65,12 +64,12 @@ type ContainerAPIClient interface {
|
|||
ContainerRemove(ctx context.Context, container string, options types.ContainerRemoveOptions) error
|
||||
ContainerRename(ctx context.Context, container, newContainerName string) error
|
||||
ContainerResize(ctx context.Context, container string, options types.ResizeOptions) error
|
||||
ContainerRestart(ctx context.Context, container string, timeout *time.Duration) error
|
||||
ContainerRestart(ctx context.Context, container string, options container.StopOptions) error
|
||||
ContainerStatPath(ctx context.Context, container, path string) (types.ContainerPathStat, error)
|
||||
ContainerStats(ctx context.Context, container string, stream bool) (types.ContainerStats, error)
|
||||
ContainerStatsOneShot(ctx context.Context, container string) (types.ContainerStats, error)
|
||||
ContainerStart(ctx context.Context, container string, options types.ContainerStartOptions) error
|
||||
ContainerStop(ctx context.Context, container string, timeout *time.Duration) error
|
||||
ContainerStop(ctx context.Context, container string, options container.StopOptions) error
|
||||
ContainerTop(ctx context.Context, container string, arguments []string) (container.ContainerTopOKBody, error)
|
||||
ContainerUnpause(ctx context.Context, container string) error
|
||||
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error)
|
||||
|
|
|
@ -913,8 +913,8 @@ func (s *DockerSuite) TestContainerAPIRestart(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
timeout := 1 * time.Second
|
||||
err = cli.ContainerRestart(context.Background(), name, &timeout)
|
||||
timeout := 1
|
||||
err = cli.ContainerRestart(context.Background(), name, container.StopOptions{Timeout: &timeout})
|
||||
assert.NilError(c, err)
|
||||
|
||||
assert.Assert(c, waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second) == nil)
|
||||
|
@ -930,7 +930,7 @@ func (s *DockerSuite) TestContainerAPIRestartNotimeoutParam(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
err = cli.ContainerRestart(context.Background(), name, nil)
|
||||
err = cli.ContainerRestart(context.Background(), name, container.StopOptions{})
|
||||
assert.NilError(c, err)
|
||||
|
||||
assert.Assert(c, waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second) == nil)
|
||||
|
@ -965,19 +965,23 @@ func (s *DockerSuite) TestContainerAPIStart(c *testing.T) {
|
|||
func (s *DockerSuite) TestContainerAPIStop(c *testing.T) {
|
||||
name := "test-api-stop"
|
||||
runSleepingContainer(c, "-i", "--name", name)
|
||||
timeout := 30 * time.Second
|
||||
timeout := 30
|
||||
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
err = cli.ContainerStop(context.Background(), name, &timeout)
|
||||
err = cli.ContainerStop(context.Background(), name, container.StopOptions{
|
||||
Timeout: &timeout,
|
||||
})
|
||||
assert.NilError(c, err)
|
||||
assert.Assert(c, waitInspect(name, "{{ .State.Running }}", "false", 60*time.Second) == nil)
|
||||
|
||||
// second call to start should give 304
|
||||
// maybe add ContainerStartWithRaw to test it
|
||||
err = cli.ContainerStop(context.Background(), name, &timeout)
|
||||
err = cli.ContainerStop(context.Background(), name, container.StopOptions{
|
||||
Timeout: &timeout,
|
||||
})
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
|
||||
|
@ -1255,7 +1259,7 @@ func (s *DockerSuite) TestContainerAPIPostContainerStop(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
err = cli.ContainerStop(context.Background(), containerID, nil)
|
||||
err = cli.ContainerStop(context.Background(), containerID, container.StopOptions{})
|
||||
assert.NilError(c, err)
|
||||
assert.Assert(c, waitInspect(containerID, "{{ .State.Running }}", "false", 60*time.Second) == nil)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
containerderrdefs "github.com/containerd/containerd/errdefs"
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
|
@ -80,7 +81,7 @@ func TestPauseStopPausedContainer(t *testing.T) {
|
|||
err := client.ContainerPause(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ContainerStop(ctx, cID, nil)
|
||||
err = client.ContainerStop(ctx, cID, containertypes.StopOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
|
|
|
@ -143,7 +143,7 @@ func TestRenameAnonymousContainer(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
// Stop/Start the container to get registered
|
||||
// FIXME(vdemeester) this is a really weird behavior as it fails otherwise
|
||||
err = client.ContainerStop(ctx, container1Name, nil)
|
||||
err = client.ContainerStop(ctx, container1Name, containertypes.StopOptions{})
|
||||
assert.NilError(t, err)
|
||||
err = client.ContainerStart(ctx, container1Name, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/icmd"
|
||||
|
@ -56,8 +57,7 @@ func TestStopContainerWithTimeout(t *testing.T) {
|
|||
t.Parallel()
|
||||
id := container.Run(ctx, t, client, testCmd)
|
||||
|
||||
timeout := time.Duration(d.timeout) * time.Second
|
||||
err := client.ContainerStop(ctx, id, &timeout)
|
||||
err := client.ContainerStop(ctx, id, containertypes.StopOptions{Timeout: &d.timeout})
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, id),
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/poll"
|
||||
|
@ -29,7 +30,7 @@ func TestStopContainerWithRestartPolicyAlways(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, name := range names {
|
||||
err := client.ContainerStop(ctx, name, nil)
|
||||
err := client.ContainerStop(ctx, name, containertypes.StopOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/poll"
|
||||
|
@ -53,8 +54,7 @@ func TestStopContainerWithTimeout(t *testing.T) {
|
|||
t.Parallel()
|
||||
id := container.Run(ctx, t, client, testCmd)
|
||||
|
||||
timeout := time.Duration(d.timeout) * time.Second
|
||||
err := client.ContainerStop(ctx, id, &timeout)
|
||||
err := client.ContainerStop(ctx, id, containertypes.StopOptions{Timeout: &d.timeout})
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, id),
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/testutil/request"
|
||||
"gotest.tools/v3/assert"
|
||||
|
@ -86,7 +87,7 @@ func TestWaitBlocked(t *testing.T) {
|
|||
|
||||
waitResC, errC := cli.ContainerWait(ctx, containerID, "")
|
||||
|
||||
err := cli.ContainerStop(ctx, containerID, nil)
|
||||
err := cli.ContainerStop(ctx, containerID, containertypes.StopOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
select {
|
||||
|
|
Loading…
Add table
Reference in a new issue