Merge pull request #43206 from thaJeztah/having_such_a_good_time_im_having_a_ball
API: add "signal" parameter to container stop and restart endpoints
This commit is contained in:
commit
1a0c15abbb
28 changed files with 428 additions and 359 deletions
|
@ -37,10 +37,10 @@ type stateBackend interface {
|
|||
ContainerPause(name string) error
|
||||
ContainerRename(oldName, newName string) 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
|
||||
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
|
||||
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
|
||||
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
||||
|
|
|
@ -221,20 +221,31 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
|
|||
return err
|
||||
}
|
||||
|
||||
var seconds *int
|
||||
var (
|
||||
options container.StopOptions
|
||||
version = httputils.VersionFromContext(ctx)
|
||||
)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
if sig := r.Form.Get("signal"); sig != "" {
|
||||
if _, err := signal.ParseSignal(sig); err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
options.Signal = sig
|
||||
}
|
||||
}
|
||||
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
|
||||
valSeconds, err := strconv.Atoi(tmpSeconds)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -278,21 +289,31 @@ func (s *containerRouter) postContainersRestart(ctx context.Context, w http.Resp
|
|||
return err
|
||||
}
|
||||
|
||||
var seconds *int
|
||||
var (
|
||||
options container.StopOptions
|
||||
version = httputils.VersionFromContext(ctx)
|
||||
)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
if sig := r.Form.Get("signal"); sig != "" {
|
||||
if _, err := signal.ParseSignal(sig); err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
options.Signal = sig
|
||||
}
|
||||
}
|
||||
if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
|
||||
valSeconds, err := strconv.Atoi(tmpSeconds)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6869,6 +6869,11 @@ paths:
|
|||
required: true
|
||||
description: "ID or name of the container"
|
||||
type: "string"
|
||||
- name: "signal"
|
||||
in: "query"
|
||||
description: |
|
||||
Signal to send to the container as an integer or string (e.g. `SIGINT`).
|
||||
type: "string"
|
||||
- name: "t"
|
||||
in: "query"
|
||||
description: "Number of seconds to wait before killing the container"
|
||||
|
@ -6898,6 +6903,11 @@ paths:
|
|||
required: true
|
||||
description: "ID or name of the container"
|
||||
type: "string"
|
||||
- name: "signal"
|
||||
in: "query"
|
||||
description: |
|
||||
Signal to send to the container as an integer or string (e.g. `SIGINT`).
|
||||
type: "string"
|
||||
- name: "t"
|
||||
in: "query"
|
||||
description: "Number of seconds to wait before killing the container"
|
||||
|
@ -6939,7 +6949,8 @@ paths:
|
|||
type: "string"
|
||||
- name: "signal"
|
||||
in: "query"
|
||||
description: "Signal to send to the container as an integer or string (e.g. `SIGINT`)"
|
||||
description: |
|
||||
Signal to send to the container as an integer or string (e.g. `SIGINT`).
|
||||
type: "string"
|
||||
default: "SIGKILL"
|
||||
tags: ["Container"]
|
||||
|
|
|
@ -13,6 +13,24 @@ import (
|
|||
// Docker interprets it as 3 nanoseconds.
|
||||
const MinimumDuration = 1 * time.Millisecond
|
||||
|
||||
// StopOptions holds the options to stop or restart a container.
|
||||
type StopOptions struct {
|
||||
// Signal (optional) is the signal to send to the container to (gracefully)
|
||||
// stop it before forcibly terminating the container with SIGKILL after the
|
||||
// timeout expires. If not value is set, the default (SIGTERM) is used.
|
||||
Signal string `json:",omitempty"`
|
||||
|
||||
// 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.
|
||||
type HealthConfig struct {
|
||||
// Test is the test to perform to check that the container is healthy.
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package time // import "github.com/docker/docker/api/types/time"
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DurationToSecondsString converts the specified duration to the number
|
||||
// seconds it represents, formatted as a string.
|
||||
func DurationToSecondsString(duration time.Duration) string {
|
||||
return strconv.FormatFloat(duration.Seconds(), 'f', 0, 64)
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package time // import "github.com/docker/docker/api/types/time"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDurationToSecondsString(t *testing.T) {
|
||||
cases := []struct {
|
||||
in time.Duration
|
||||
expected string
|
||||
}{
|
||||
{0 * time.Second, "0"},
|
||||
{1 * time.Second, "1"},
|
||||
{1 * time.Minute, "60"},
|
||||
{24 * time.Hour, "86400"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
s := DurationToSecondsString(c.in)
|
||||
if s != c.expected {
|
||||
t.Errorf("wrong value for input `%v`: expected `%s`, got `%s`", c.in, c.expected, s)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,17 +5,16 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"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/image"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
|
@ -48,8 +47,8 @@ type CommonAPIClient interface {
|
|||
type ContainerAPIClient interface {
|
||||
ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error)
|
||||
ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error)
|
||||
ContainerCreate(ctx context.Context, config *containertypes.Config, hostConfig *containertypes.HostConfig, networkingConfig *networktypes.NetworkingConfig, platform *specs.Platform, containerName string) (containertypes.ContainerCreateCreatedBody, error)
|
||||
ContainerDiff(ctx context.Context, container string) ([]containertypes.ContainerChangeResponseItem, error)
|
||||
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *specs.Platform, containerName string) (container.ContainerCreateCreatedBody, error)
|
||||
ContainerDiff(ctx context.Context, container string) ([]container.ContainerChangeResponseItem, error)
|
||||
ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error)
|
||||
ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error)
|
||||
ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error)
|
||||
|
@ -65,16 +64,16 @@ 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
|
||||
ContainerTop(ctx context.Context, container string, arguments []string) (containertypes.ContainerTopOKBody, 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 containertypes.UpdateConfig) (containertypes.ContainerUpdateOKBody, error)
|
||||
ContainerWait(ctx context.Context, container string, condition containertypes.WaitCondition) (<-chan containertypes.ContainerWaitOKBody, <-chan error)
|
||||
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error)
|
||||
ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.ContainerWaitOKBody, <-chan error)
|
||||
CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
||||
CopyToContainer(ctx context.Context, container, path string, content io.Reader, options types.CopyToContainerOptions) error
|
||||
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error)
|
||||
|
@ -107,7 +106,7 @@ type ImageAPIClient interface {
|
|||
|
||||
// NetworkAPIClient defines API client methods for the networks
|
||||
type NetworkAPIClient interface {
|
||||
NetworkConnect(ctx context.Context, network, container string, config *networktypes.EndpointSettings) error
|
||||
NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error
|
||||
NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error)
|
||||
NetworkDisconnect(ctx context.Context, network, container string, force bool) error
|
||||
NetworkInspect(ctx context.Context, network string, options types.NetworkInspectOptions) (types.NetworkResource, error)
|
||||
|
@ -174,10 +173,10 @@ type SystemAPIClient interface {
|
|||
|
||||
// VolumeAPIClient defines API client methods for the volumes
|
||||
type VolumeAPIClient interface {
|
||||
VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error)
|
||||
VolumeCreate(ctx context.Context, options volume.VolumeCreateBody) (types.Volume, error)
|
||||
VolumeInspect(ctx context.Context, volumeID string) (types.Volume, error)
|
||||
VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error)
|
||||
VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumeListOKBody, error)
|
||||
VolumeList(ctx context.Context, filter filters.Args) (volume.VolumeListOKBody, error)
|
||||
VolumeRemove(ctx context.Context, volumeID string, force bool) error
|
||||
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error)
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ type Backend interface {
|
|||
ReleaseIngress() (<-chan struct{}, error)
|
||||
CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
||||
ContainerStop(name string, seconds *int) error
|
||||
ContainerLogs(context.Context, string, *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||
ContainerStop(ctx context.Context, name string, config container.StopOptions) 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
|
||||
ActivateContainerServiceBinding(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 {
|
||||
var options = containertypes.StopOptions{}
|
||||
// Default stop grace period to nil (daemon will use the stopTimeout of the container)
|
||||
var stopgrace *int
|
||||
spec := c.container.spec()
|
||||
if spec.StopGracePeriod != nil {
|
||||
stopgraceValue := int(spec.StopGracePeriod.Seconds)
|
||||
stopgrace = &stopgraceValue
|
||||
if spec := c.container.spec(); spec.StopGracePeriod != nil {
|
||||
timeout := int(spec.StopGracePeriod.Seconds)
|
||||
options.Timeout = &timeout
|
||||
}
|
||||
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 {
|
||||
|
|
|
@ -12,19 +12,19 @@ import (
|
|||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
func (d *Daemon) configureLocalContentStore() (content.Store, leases.Manager, error) {
|
||||
if err := os.MkdirAll(filepath.Join(d.root, "content"), 0700); err != nil {
|
||||
func (daemon *Daemon) configureLocalContentStore() (content.Store, leases.Manager, error) {
|
||||
if err := os.MkdirAll(filepath.Join(daemon.root, "content"), 0700); err != nil {
|
||||
return nil, nil, errors.Wrap(err, "error creating dir for content store")
|
||||
}
|
||||
db, err := bbolt.Open(filepath.Join(d.root, "content", "metadata.db"), 0600, nil)
|
||||
db, err := bbolt.Open(filepath.Join(daemon.root, "content", "metadata.db"), 0600, nil)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "error opening bolt db for content metadata store")
|
||||
}
|
||||
cs, err := local.NewStore(filepath.Join(d.root, "content", "data"))
|
||||
cs, err := local.NewStore(filepath.Join(daemon.root, "content", "data"))
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "error setting up content store")
|
||||
}
|
||||
md := metadata.NewDB(db, cs, nil)
|
||||
d.mdDB = db
|
||||
daemon.mdDB = db
|
||||
return md.ContentStore(), metadata.NewLeaseManager(md), nil
|
||||
}
|
||||
|
|
|
@ -153,8 +153,12 @@ func (daemon *Daemon) create(opts createOpts) (retC *container.Container, retErr
|
|||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
if err := daemon.cleanupContainer(ctr, true, true); err != nil {
|
||||
logrus.Errorf("failed to cleanup container on create error: %v", err)
|
||||
err = daemon.cleanupContainer(ctr, types.ContainerRmConfig{
|
||||
ForceRemove: true,
|
||||
RemoveVolume: true,
|
||||
})
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("failed to cleanup container on create error")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -1116,10 +1116,8 @@ func (daemon *Daemon) waitForStartupDone() {
|
|||
}
|
||||
|
||||
func (daemon *Daemon) shutdownContainer(c *container.Container) error {
|
||||
stopTimeout := c.StopTimeout()
|
||||
|
||||
// If container failed to exit in stopTimeout seconds of SIGTERM, then using the force
|
||||
if err := daemon.containerStop(c, stopTimeout); 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
|
@ -22,28 +24,28 @@ import (
|
|||
// network links are removed.
|
||||
func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) error {
|
||||
start := time.Now()
|
||||
container, err := daemon.GetContainer(name)
|
||||
ctr, err := daemon.GetContainer(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Container state RemovalInProgress should be used to avoid races.
|
||||
if inProgress := container.SetRemovalInProgress(); inProgress {
|
||||
if inProgress := ctr.SetRemovalInProgress(); inProgress {
|
||||
err := fmt.Errorf("removal of container %s is already in progress", name)
|
||||
return errdefs.Conflict(err)
|
||||
}
|
||||
defer container.ResetRemovalInProgress()
|
||||
defer ctr.ResetRemovalInProgress()
|
||||
|
||||
// check if container wasn't deregistered by previous rm since Get
|
||||
if c := daemon.containers.Get(container.ID); c == nil {
|
||||
if c := daemon.containers.Get(ctr.ID); c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if config.RemoveLink {
|
||||
return daemon.rmLink(container, name)
|
||||
return daemon.rmLink(ctr, name)
|
||||
}
|
||||
|
||||
err = daemon.cleanupContainer(container, config.ForceRemove, config.RemoveVolume)
|
||||
err = daemon.cleanupContainer(ctr, *config)
|
||||
containerActions.WithValues("delete").UpdateSince(start)
|
||||
|
||||
return err
|
||||
|
@ -77,9 +79,9 @@ func (daemon *Daemon) rmLink(container *container.Container, name string) error
|
|||
|
||||
// cleanupContainer unregisters a container from the daemon, stops stats
|
||||
// collection and cleanly removes contents and metadata from the filesystem.
|
||||
func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemove, removeVolume bool) error {
|
||||
func (daemon *Daemon) cleanupContainer(container *container.Container, config types.ContainerRmConfig) error {
|
||||
if container.IsRunning() {
|
||||
if !forceRemove {
|
||||
if !config.ForceRemove {
|
||||
state := container.StateString()
|
||||
procedure := "Stop the container before attempting removal or force remove"
|
||||
if state == "paused" {
|
||||
|
@ -97,7 +99,19 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
|||
// if stats are currently getting collected.
|
||||
daemon.statsCollector.StopCollection(container)
|
||||
|
||||
if err := daemon.containerStop(container, 3); err != nil {
|
||||
// stopTimeout is the number of seconds to wait for the container to stop
|
||||
// gracefully before forcibly killing it.
|
||||
//
|
||||
// Why 3 seconds? The timeout specified here was originally added in commit
|
||||
// 1615bb08c7c3fc6c4b22db0a633edda516f97cf0, which added a custom timeout to
|
||||
// some commands, but lacking an option for a timeout on "docker rm", was
|
||||
// hardcoded to 10 seconds. Commit 28fd289b448164b77affd8103c0d96fd8110daf9
|
||||
// later on updated this to 3 seconds (but no background on that change).
|
||||
//
|
||||
// If you arrived here and know the answer, you earned yourself a picture
|
||||
// of a cute animal of your own choosing.
|
||||
var stopTimeout = 3
|
||||
if err := daemon.containerStop(context.TODO(), container, containertypes.StopOptions{Timeout: &stopTimeout}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -135,7 +149,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
|||
daemon.idIndex.Delete(container.ID)
|
||||
daemon.containers.Delete(container.ID)
|
||||
daemon.containersReplica.Delete(container)
|
||||
if err := daemon.removeMountPoints(container, removeVolume); err != nil {
|
||||
if err := daemon.removeMountPoints(container, config.RemoveVolume); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
for _, name := range linkNames {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
|
@ -14,16 +15,13 @@ import (
|
|||
// timeout, ContainerRestart will wait forever until a graceful
|
||||
// stop. Returns an error if the container cannot be found, or if
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if seconds == nil {
|
||||
stopTimeout := ctr.StopTimeout()
|
||||
seconds = &stopTimeout
|
||||
}
|
||||
if err := daemon.containerRestart(ctr, *seconds); err != nil {
|
||||
err = daemon.containerRestart(ctx, ctr, options)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot restart container %s: %v", name, err)
|
||||
}
|
||||
return nil
|
||||
|
@ -34,8 +32,7 @@ func (daemon *Daemon) ContainerRestart(name string, seconds *int) error {
|
|||
// container. When stopping, wait for the given duration in seconds to
|
||||
// gracefully stop, before forcefully terminating the container. If
|
||||
// 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.
|
||||
actualIsolation := container.HostConfig.Isolation
|
||||
if containertypes.Isolation.IsDefault(actualIsolation) {
|
||||
|
@ -60,7 +57,7 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds i
|
|||
autoRemove := container.HostConfig.AutoRemove
|
||||
|
||||
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
|
||||
container.HostConfig.AutoRemove = autoRemove
|
||||
// containerStop will write HostConfig to disk, we shall restore AutoRemove
|
||||
|
|
|
@ -7,10 +7,10 @@ import (
|
|||
"testing"
|
||||
|
||||
coci "github.com/containerd/containerd/oci"
|
||||
config "github.com/docker/docker/api/types/container"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
dconfig "github.com/docker/docker/daemon/config"
|
||||
doci "github.com/docker/docker/oci"
|
||||
"github.com/docker/docker/oci"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/profiles/seccomp"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
@ -36,12 +36,12 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: dconfig.SeccompProfileUnconfined,
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: false,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
outSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: oci.DefaultLinuxSpec(),
|
||||
},
|
||||
{
|
||||
comment: "privileged container w/ custom profile runs unconfined",
|
||||
|
@ -50,12 +50,12 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "{ \"defaultAction\": \"SCMP_ACT_LOG\" }",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: true,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
outSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: oci.DefaultLinuxSpec(),
|
||||
},
|
||||
{
|
||||
comment: "privileged container w/ default runs unconfined",
|
||||
|
@ -64,12 +64,12 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: true,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
outSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: oci.DefaultLinuxSpec(),
|
||||
},
|
||||
{
|
||||
comment: "privileged container w/ daemon profile runs unconfined",
|
||||
|
@ -79,12 +79,12 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: true,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
outSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: oci.DefaultLinuxSpec(),
|
||||
},
|
||||
{
|
||||
comment: "custom profile when seccomp is disabled returns error",
|
||||
|
@ -93,12 +93,12 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "{ \"defaultAction\": \"SCMP_ACT_ERRNO\" }",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: false,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
outSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: oci.DefaultLinuxSpec(),
|
||||
err: "seccomp is not enabled in your kernel, cannot run a custom seccomp profile",
|
||||
},
|
||||
{
|
||||
|
@ -108,13 +108,13 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: false,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: func() coci.Spec {
|
||||
s := doci.DefaultLinuxSpec()
|
||||
s := oci.DefaultLinuxSpec()
|
||||
profile, _ := seccomp.GetDefaultProfile(&s)
|
||||
s.Linux.Seccomp = profile
|
||||
return s
|
||||
|
@ -127,13 +127,13 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "{ \"defaultAction\": \"SCMP_ACT_ERRNO\" }",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: false,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: func() coci.Spec {
|
||||
s := doci.DefaultLinuxSpec()
|
||||
s := oci.DefaultLinuxSpec()
|
||||
profile := &specs.LinuxSeccomp{
|
||||
DefaultAction: specs.LinuxSeccompAction("SCMP_ACT_ERRNO"),
|
||||
}
|
||||
|
@ -149,13 +149,13 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: false,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: func() coci.Spec {
|
||||
s := doci.DefaultLinuxSpec()
|
||||
s := oci.DefaultLinuxSpec()
|
||||
profile := &specs.LinuxSeccomp{
|
||||
DefaultAction: specs.LinuxSeccompAction("SCMP_ACT_ERRNO"),
|
||||
}
|
||||
|
@ -171,13 +171,13 @@ func TestWithSeccomp(t *testing.T) {
|
|||
},
|
||||
c: &container.Container{
|
||||
SeccompProfile: "{ \"defaultAction\": \"SCMP_ACT_LOG\" }",
|
||||
HostConfig: &config.HostConfig{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
Privileged: false,
|
||||
},
|
||||
},
|
||||
inSpec: doci.DefaultLinuxSpec(),
|
||||
inSpec: oci.DefaultLinuxSpec(),
|
||||
outSpec: func() coci.Spec {
|
||||
s := doci.DefaultLinuxSpec()
|
||||
s := oci.DefaultLinuxSpec()
|
||||
profile := &specs.LinuxSeccomp{
|
||||
DefaultAction: specs.LinuxSeccompAction("SCMP_ACT_LOG"),
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/moby/sys/signal"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -18,84 +20,96 @@ 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 (daemon *Daemon) ContainerStop(name string, timeout *int) error {
|
||||
container, err := daemon.GetContainer(name)
|
||||
func (daemon *Daemon) ContainerStop(ctx context.Context, name string, options containertypes.StopOptions) error {
|
||||
ctr, err := daemon.GetContainer(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !container.IsRunning() {
|
||||
return containerNotModifiedError{running: false}
|
||||
if !ctr.IsRunning() {
|
||||
return containerNotModifiedError{}
|
||||
}
|
||||
if timeout == nil {
|
||||
stopTimeout := container.StopTimeout()
|
||||
timeout = &stopTimeout
|
||||
}
|
||||
if err := daemon.containerStop(container, *timeout); err != nil {
|
||||
err = daemon.containerStop(ctx, ctr, options)
|
||||
if err != nil {
|
||||
return errdefs.System(errors.Wrapf(err, "cannot stop container: %s", name))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// containerStop sends a stop signal, waits, sends a kill signal.
|
||||
func (daemon *Daemon) containerStop(container *containerpkg.Container, seconds int) error {
|
||||
// TODO propagate a context down to this function
|
||||
ctx := context.TODO()
|
||||
if !container.IsRunning() {
|
||||
func (daemon *Daemon) containerStop(ctx context.Context, ctr *container.Container, options containertypes.StopOptions) (retErr error) {
|
||||
if !ctr.IsRunning() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
stopSignal = ctr.StopSignal()
|
||||
stopTimeout = ctr.StopTimeout()
|
||||
)
|
||||
if options.Signal != "" {
|
||||
sig, err := signal.ParseSignal(options.Signal)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
stopSignal = int(sig)
|
||||
}
|
||||
if options.Timeout != nil {
|
||||
stopTimeout = *options.Timeout
|
||||
}
|
||||
|
||||
var wait time.Duration
|
||||
if seconds >= 0 {
|
||||
wait = time.Duration(seconds) * time.Second
|
||||
if stopTimeout >= 0 {
|
||||
wait = time.Duration(stopTimeout) * time.Second
|
||||
}
|
||||
success := func() error {
|
||||
daemon.LogContainerEvent(container, "stop")
|
||||
return nil
|
||||
}
|
||||
stopSignal := container.StopSignal()
|
||||
defer func() {
|
||||
if retErr == nil {
|
||||
daemon.LogContainerEvent(ctr, "stop")
|
||||
}
|
||||
}()
|
||||
|
||||
// 1. Send a stop signal
|
||||
err := daemon.killPossiblyDeadProcess(container, stopSignal)
|
||||
err := daemon.killPossiblyDeadProcess(ctr, stopSignal)
|
||||
if err != nil {
|
||||
wait = 2 * time.Second
|
||||
}
|
||||
|
||||
var subCtx context.Context
|
||||
var cancel context.CancelFunc
|
||||
if seconds >= 0 {
|
||||
if stopTimeout >= 0 {
|
||||
subCtx, cancel = context.WithTimeout(ctx, wait)
|
||||
} else {
|
||||
subCtx, cancel = context.WithCancel(ctx)
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
if status := <-container.Wait(subCtx, containerpkg.WaitConditionNotRunning); status.Err() == nil {
|
||||
if status := <-ctr.Wait(subCtx, container.WaitConditionNotRunning); status.Err() == nil {
|
||||
// container did exit, so ignore any previous errors and return
|
||||
return success()
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// the container has still not exited, and the kill function errored, so log the error here:
|
||||
logrus.WithError(err).WithField("container", container.ID).Errorf("Error sending stop (signal %d) to container", stopSignal)
|
||||
logrus.WithError(err).WithField("container", ctr.ID).Errorf("Error sending stop (signal %d) to container", stopSignal)
|
||||
}
|
||||
if seconds < 0 {
|
||||
if stopTimeout < 0 {
|
||||
// if the client requested that we never kill / wait forever, but container.Wait was still
|
||||
// interrupted (parent context cancelled, for example), we should propagate the signal failure
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.WithField("container", container.ID).Infof("Container failed to exit within %s of signal %d - using the force", wait, stopSignal)
|
||||
// Stop either failed or container didnt exit, so fallback to kill.
|
||||
if err := daemon.Kill(container); err != nil {
|
||||
logrus.WithField("container", ctr.ID).Infof("Container failed to exit within %s of signal %d - using the force", wait, stopSignal)
|
||||
|
||||
// Stop either failed or container didn't exit, so fallback to kill.
|
||||
if err := daemon.Kill(ctr); err != nil {
|
||||
// got a kill error, but give container 2 more seconds to exit just in case
|
||||
subCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
||||
defer cancel()
|
||||
if status := <-container.Wait(subCtx, containerpkg.WaitConditionNotRunning); status.Err() == nil {
|
||||
// container did exit, so ignore error and return
|
||||
return success()
|
||||
status := <-ctr.Wait(subCtx, container.WaitConditionNotRunning)
|
||||
if status.Err() != nil {
|
||||
logrus.WithError(err).WithField("container", ctr.ID).Errorf("error killing container: %v", status.Err())
|
||||
return err
|
||||
}
|
||||
logrus.WithError(err).WithField("container", container.ID).Error("Error killing the container")
|
||||
return err
|
||||
// container did exit, so ignore previous errors and continue
|
||||
}
|
||||
|
||||
return success()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ keywords: "API, Docker, rcli, REST, documentation"
|
|||
was introduced in API 1.31 as part of an experimental feature, and no longer
|
||||
used since API 1.40.
|
||||
Use field `BuildCache` instead to track storage used by the builder component.
|
||||
* `POST /containers/{id}/stop` and `POST /containers/{id}/restart` now accept a
|
||||
`signal` query parameter, which allows overriding the container's default stop-
|
||||
signal.
|
||||
* `GET /images/json` now accepts query parameter `shared-size`. When set `true`,
|
||||
images returned will include `SharedSize`, which provides the size on disk shared
|
||||
with other images present on the system.
|
||||
|
|
|
@ -17,9 +17,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/client"
|
||||
dconfig "github.com/docker/docker/daemon/config"
|
||||
|
@ -476,7 +476,7 @@ func (s *DockerSuite) TestContainerAPICommitWithLabelInConfig(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Labels: map[string]string{"key1": "value1", "key2": "value2"}}
|
||||
|
||||
options := types.ContainerCommitOptions{
|
||||
|
@ -504,12 +504,12 @@ func (s *DockerSuite) TestContainerAPIBadPort(c *testing.T) {
|
|||
// TODO Windows to Windows CI - Port this test
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"/bin/sh", "-c", "echo test"},
|
||||
}
|
||||
|
||||
hostConfig := containertypes.HostConfig{
|
||||
hostConfig := container.HostConfig{
|
||||
PortBindings: nat.PortMap{
|
||||
"8080/tcp": []nat.PortBinding{
|
||||
{
|
||||
|
@ -523,12 +523,12 @@ func (s *DockerSuite) TestContainerAPIBadPort(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
||||
assert.ErrorContains(c, err, `invalid port specification: "aa80"`)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestContainerAPICreate(c *testing.T) {
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"/bin/sh", "-c", "touch /test && ls /test"},
|
||||
}
|
||||
|
@ -537,7 +537,7 @@ func (s *DockerSuite) TestContainerAPICreate(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
|
||||
out, _ := dockerCmd(c, "start", "-a", container.ID)
|
||||
|
@ -550,7 +550,7 @@ func (s *DockerSuite) TestContainerAPICreateEmptyConfig(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &containertypes.Config{}, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||
_, err = cli.ContainerCreate(context.Background(), &container.Config{}, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
||||
|
||||
expected := "No command specified"
|
||||
assert.ErrorContains(c, err, expected)
|
||||
|
@ -558,12 +558,12 @@ func (s *DockerSuite) TestContainerAPICreateEmptyConfig(c *testing.T) {
|
|||
|
||||
func (s *DockerSuite) TestContainerAPICreateMultipleNetworksConfig(c *testing.T) {
|
||||
// Container creation must fail if client specified configurations for more than one network
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
|
||||
networkingConfig := networktypes.NetworkingConfig{
|
||||
EndpointsConfig: map[string]*networktypes.EndpointSettings{
|
||||
networkingConfig := network.NetworkingConfig{
|
||||
EndpointsConfig: map[string]*network.EndpointSettings{
|
||||
"net1": {},
|
||||
"net2": {},
|
||||
"net3": {},
|
||||
|
@ -574,7 +574,7 @@ func (s *DockerSuite) TestContainerAPICreateMultipleNetworksConfig(c *testing.T)
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networkingConfig, nil, "")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &networkingConfig, nil, "")
|
||||
msg := err.Error()
|
||||
// network name order in error message is not deterministic
|
||||
assert.Assert(c, strings.Contains(msg, "Container cannot be connected to network endpoints"))
|
||||
|
@ -596,12 +596,12 @@ func (s *DockerSuite) TestContainerAPICreateOtherNetworkModes(c *testing.T) {
|
|||
UtilCreateNetworkMode(c, "container:web1")
|
||||
}
|
||||
|
||||
func UtilCreateNetworkMode(c *testing.T, networkMode containertypes.NetworkMode) {
|
||||
config := containertypes.Config{
|
||||
func UtilCreateNetworkMode(c *testing.T, networkMode container.NetworkMode) {
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
|
||||
hostConfig := containertypes.HostConfig{
|
||||
hostConfig := container.HostConfig{
|
||||
NetworkMode: networkMode,
|
||||
}
|
||||
|
||||
|
@ -609,7 +609,7 @@ func UtilCreateNetworkMode(c *testing.T, networkMode containertypes.NetworkMode)
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
|
||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
|
@ -621,12 +621,12 @@ func UtilCreateNetworkMode(c *testing.T, networkMode containertypes.NetworkMode)
|
|||
func (s *DockerSuite) TestContainerAPICreateWithCpuSharesCpuset(c *testing.T) {
|
||||
// TODO Windows to Windows CI. The CpuShares part could be ported.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
|
||||
hostConfig := containertypes.HostConfig{
|
||||
Resources: containertypes.Resources{
|
||||
hostConfig := container.HostConfig{
|
||||
Resources: container.Resources{
|
||||
CPUShares: 512,
|
||||
CpusetCpus: "0",
|
||||
},
|
||||
|
@ -636,7 +636,7 @@ func (s *DockerSuite) TestContainerAPICreateWithCpuSharesCpuset(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
|
||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
|
@ -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)
|
||||
|
@ -938,7 +938,7 @@ func (s *DockerSuite) TestContainerAPIRestartNotimeoutParam(c *testing.T) {
|
|||
|
||||
func (s *DockerSuite) TestContainerAPIStart(c *testing.T) {
|
||||
name := "testing-start"
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: append([]string{"/bin/sh", "-c"}, sleepCommandForDaemonPlatform()...),
|
||||
OpenStdin: true,
|
||||
|
@ -948,7 +948,7 @@ func (s *DockerSuite) TestContainerAPIStart(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, name)
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, name)
|
||||
assert.NilError(c, err)
|
||||
|
||||
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
||||
|
@ -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,14 +1259,14 @@ 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)
|
||||
}
|
||||
|
||||
// #14170
|
||||
func (s *DockerSuite) TestPostContainerAPICreateWithStringOrSliceEntrypoint(c *testing.T) {
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Entrypoint: []string{"echo"},
|
||||
Cmd: []string{"hello", "world"},
|
||||
|
@ -1272,7 +1276,7 @@ func (s *DockerSuite) TestPostContainerAPICreateWithStringOrSliceEntrypoint(c *t
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "echotest")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "echotest")
|
||||
assert.NilError(c, err)
|
||||
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
||||
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
||||
|
@ -1290,7 +1294,7 @@ func (s *DockerSuite) TestPostContainerAPICreateWithStringOrSliceEntrypoint(c *t
|
|||
|
||||
// #14170
|
||||
func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *testing.T) {
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"echo", "hello", "world"},
|
||||
}
|
||||
|
@ -1299,7 +1303,7 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *testing.T)
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "echotest")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "echotest")
|
||||
assert.NilError(c, err)
|
||||
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
||||
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
||||
|
@ -1330,10 +1334,10 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *tes
|
|||
assert.NilError(c, err)
|
||||
assert.Equal(c, res.StatusCode, http.StatusCreated)
|
||||
|
||||
config2 := containertypes.Config{
|
||||
config2 := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
hostConfig := containertypes.HostConfig{
|
||||
hostConfig := container.HostConfig{
|
||||
CapAdd: []string{"net_admin", "SYS_ADMIN"},
|
||||
CapDrop: []string{"SETGID", "CAP_SETPCAP"},
|
||||
}
|
||||
|
@ -1342,21 +1346,21 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *tes
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config2, &hostConfig, &networktypes.NetworkingConfig{}, nil, "capaddtest1")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config2, &hostConfig, &network.NetworkingConfig{}, nil, "capaddtest1")
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
|
||||
// #14915
|
||||
func (s *DockerSuite) TestContainerAPICreateNoHostConfig118(c *testing.T) {
|
||||
testRequires(c, DaemonIsLinux) // Windows only support 1.25 or later
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("v1.18"))
|
||||
assert.NilError(c, err)
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
|
||||
|
@ -1397,27 +1401,27 @@ func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *testing.T
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
hostConfig1 := containertypes.HostConfig{
|
||||
Resources: containertypes.Resources{
|
||||
hostConfig1 := container.HostConfig{
|
||||
Resources: container.Resources{
|
||||
CpusetCpus: "1-42,,",
|
||||
},
|
||||
}
|
||||
name := "wrong-cpuset-cpus"
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig1, &networktypes.NetworkingConfig{}, nil, name)
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig1, &network.NetworkingConfig{}, nil, name)
|
||||
expected := "Invalid value 1-42,, for cpuset cpus"
|
||||
assert.ErrorContains(c, err, expected)
|
||||
|
||||
hostConfig2 := containertypes.HostConfig{
|
||||
Resources: containertypes.Resources{
|
||||
hostConfig2 := container.HostConfig{
|
||||
Resources: container.Resources{
|
||||
CpusetMems: "42-3,1--",
|
||||
},
|
||||
}
|
||||
name = "wrong-cpuset-mems"
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig2, &networktypes.NetworkingConfig{}, nil, name)
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig2, &network.NetworkingConfig{}, nil, name)
|
||||
expected = "Invalid value 42-3,1-- for cpuset mems"
|
||||
assert.ErrorContains(c, err, expected)
|
||||
}
|
||||
|
@ -1425,10 +1429,10 @@ func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *testing.T
|
|||
func (s *DockerSuite) TestPostContainersCreateShmSizeNegative(c *testing.T) {
|
||||
// ShmSize is not supported on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
hostConfig := containertypes.HostConfig{
|
||||
hostConfig := container.HostConfig{
|
||||
ShmSize: -1,
|
||||
}
|
||||
|
||||
|
@ -1436,7 +1440,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeNegative(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
||||
assert.ErrorContains(c, err, "SHM size can not be less than 0")
|
||||
}
|
||||
|
||||
|
@ -1444,7 +1448,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *testin
|
|||
// ShmSize is not supported on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"mount"},
|
||||
}
|
||||
|
@ -1453,7 +1457,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *testin
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
|
||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
|
@ -1471,7 +1475,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *testin
|
|||
func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *testing.T) {
|
||||
// ShmSize is not supported on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"mount"},
|
||||
}
|
||||
|
@ -1480,7 +1484,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
|
||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
|
@ -1498,12 +1502,12 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *testing.T) {
|
|||
func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *testing.T) {
|
||||
// ShmSize is not supported on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"mount"},
|
||||
}
|
||||
|
||||
hostConfig := containertypes.HostConfig{
|
||||
hostConfig := container.HostConfig{
|
||||
ShmSize: 1073741824,
|
||||
}
|
||||
|
||||
|
@ -1511,7 +1515,7 @@ func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
|
||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
|
@ -1529,7 +1533,7 @@ func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *testing.T) {
|
|||
func (s *DockerSuite) TestPostContainersCreateMemorySwappinessHostConfigOmitted(c *testing.T) {
|
||||
// Swappiness is not supported on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
|
||||
|
@ -1537,7 +1541,7 @@ func (s *DockerSuite) TestPostContainersCreateMemorySwappinessHostConfigOmitted(
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||
container, err := cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
||||
assert.NilError(c, err)
|
||||
|
||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
|
@ -1555,11 +1559,11 @@ func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *tes
|
|||
// OomScoreAdj is not supported on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
|
||||
hostConfig := containertypes.HostConfig{
|
||||
hostConfig := container.HostConfig{
|
||||
OomScoreAdj: 1001,
|
||||
}
|
||||
|
||||
|
@ -1568,17 +1572,17 @@ func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *tes
|
|||
defer cli.Close()
|
||||
|
||||
name := "oomscoreadj-over"
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, name)
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, name)
|
||||
|
||||
expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]"
|
||||
assert.ErrorContains(c, err, expected)
|
||||
|
||||
hostConfig = containertypes.HostConfig{
|
||||
hostConfig = container.HostConfig{
|
||||
OomScoreAdj: -1001,
|
||||
}
|
||||
|
||||
name = "oomscoreadj-low"
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, name)
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, name)
|
||||
|
||||
expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]"
|
||||
assert.ErrorContains(c, err, expected)
|
||||
|
@ -1600,7 +1604,7 @@ func (s *DockerSuite) TestContainerAPIStatsWithNetworkDisabled(c *testing.T) {
|
|||
|
||||
name := "testing-network-disabled"
|
||||
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"top"},
|
||||
NetworkDisabled: true,
|
||||
|
@ -1610,7 +1614,7 @@ func (s *DockerSuite) TestContainerAPIStatsWithNetworkDisabled(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, name)
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, name)
|
||||
assert.NilError(c, err)
|
||||
|
||||
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
||||
|
@ -1645,8 +1649,8 @@ func (s *DockerSuite) TestContainerAPIStatsWithNetworkDisabled(c *testing.T) {
|
|||
|
||||
func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
||||
type testCase struct {
|
||||
config containertypes.Config
|
||||
hostConfig containertypes.HostConfig
|
||||
config container.Config
|
||||
hostConfig container.HostConfig
|
||||
msg string
|
||||
}
|
||||
|
||||
|
@ -1656,11 +1660,11 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
|
||||
cases := []testCase{
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "notreal",
|
||||
Target: destPath,
|
||||
},
|
||||
|
@ -1670,30 +1674,30 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
msg: "mount type unknown",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "bind"}}},
|
||||
msg: "Target must not be empty",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "bind",
|
||||
Target: destPath}}},
|
||||
msg: "Source must not be empty",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "bind",
|
||||
Source: notExistPath,
|
||||
Target: destPath}}},
|
||||
|
@ -1702,36 +1706,36 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
// msg: "source path does not exist: " + notExistPath,
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "volume"}}},
|
||||
msg: "Target must not be empty",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "volume",
|
||||
Source: "hello",
|
||||
Target: destPath}}},
|
||||
msg: "",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "volume",
|
||||
Source: "hello2",
|
||||
Target: destPath,
|
||||
VolumeOptions: &mounttypes.VolumeOptions{
|
||||
DriverConfig: &mounttypes.Driver{
|
||||
VolumeOptions: &mount.VolumeOptions{
|
||||
DriverConfig: &mount.Driver{
|
||||
Name: "local"}}}}},
|
||||
msg: "",
|
||||
},
|
||||
|
@ -1743,26 +1747,26 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
defer os.RemoveAll(tmpDir)
|
||||
cases = append(cases, []testCase{
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "bind",
|
||||
Source: tmpDir,
|
||||
Target: destPath}}},
|
||||
msg: "",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "bind",
|
||||
Source: tmpDir,
|
||||
Target: destPath,
|
||||
VolumeOptions: &mounttypes.VolumeOptions{}}}},
|
||||
VolumeOptions: &mount.VolumeOptions{}}}},
|
||||
msg: "VolumeOptions must not be specified",
|
||||
},
|
||||
}...)
|
||||
|
@ -1771,17 +1775,17 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
if DaemonIsWindows() {
|
||||
cases = append(cases, []testCase{
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "volume",
|
||||
Source: "not-supported-on-windows",
|
||||
Target: destPath,
|
||||
VolumeOptions: &mounttypes.VolumeOptions{
|
||||
DriverConfig: &mounttypes.Driver{
|
||||
VolumeOptions: &mount.VolumeOptions{
|
||||
DriverConfig: &mount.Driver{
|
||||
Name: "local",
|
||||
Options: map[string]string{"type": "tmpfs"},
|
||||
},
|
||||
|
@ -1797,17 +1801,17 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
if DaemonIsLinux() {
|
||||
cases = append(cases, []testCase{
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "volume",
|
||||
Source: "missing-device-opt",
|
||||
Target: destPath,
|
||||
VolumeOptions: &mounttypes.VolumeOptions{
|
||||
DriverConfig: &mounttypes.Driver{
|
||||
VolumeOptions: &mount.VolumeOptions{
|
||||
DriverConfig: &mount.Driver{
|
||||
Name: "local",
|
||||
Options: map[string]string{"foobar": "foobaz"},
|
||||
},
|
||||
|
@ -1818,17 +1822,17 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
msg: `invalid option: "foobar"`,
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "volume",
|
||||
Source: "missing-device-opt",
|
||||
Target: destPath,
|
||||
VolumeOptions: &mounttypes.VolumeOptions{
|
||||
DriverConfig: &mounttypes.Driver{
|
||||
VolumeOptions: &mount.VolumeOptions{
|
||||
DriverConfig: &mount.Driver{
|
||||
Name: "local",
|
||||
Options: map[string]string{"type": "tmpfs"},
|
||||
},
|
||||
|
@ -1839,17 +1843,17 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
msg: `missing required option: "device"`,
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "volume",
|
||||
Source: "missing-type-opt",
|
||||
Target: destPath,
|
||||
VolumeOptions: &mounttypes.VolumeOptions{
|
||||
DriverConfig: &mounttypes.Driver{
|
||||
VolumeOptions: &mount.VolumeOptions{
|
||||
DriverConfig: &mount.Driver{
|
||||
Name: "local",
|
||||
Options: map[string]string{"device": "tmpfs"},
|
||||
},
|
||||
|
@ -1860,17 +1864,17 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
msg: `missing required option: "type"`,
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "volume",
|
||||
Source: "hello4",
|
||||
Target: destPath,
|
||||
VolumeOptions: &mounttypes.VolumeOptions{
|
||||
DriverConfig: &mounttypes.Driver{
|
||||
VolumeOptions: &mount.VolumeOptions{
|
||||
DriverConfig: &mount.Driver{
|
||||
Name: "local",
|
||||
Options: map[string]string{"o": "size=1", "type": "tmpfs", "device": "tmpfs"},
|
||||
},
|
||||
|
@ -1881,35 +1885,35 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
msg: "",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "tmpfs",
|
||||
Target: destPath}}},
|
||||
msg: "",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "tmpfs",
|
||||
Target: destPath,
|
||||
TmpfsOptions: &mounttypes.TmpfsOptions{
|
||||
TmpfsOptions: &mount.TmpfsOptions{
|
||||
SizeBytes: 4096 * 1024,
|
||||
Mode: 0700,
|
||||
}}}},
|
||||
msg: "",
|
||||
},
|
||||
{
|
||||
config: containertypes.Config{
|
||||
config: container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
hostConfig: containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{{
|
||||
hostConfig: container.HostConfig{
|
||||
Mounts: []mount.Mount{{
|
||||
Type: "tmpfs",
|
||||
Source: "/shouldnotbespecified",
|
||||
Target: destPath}}},
|
||||
|
@ -1926,7 +1930,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
|||
for i, x := range cases {
|
||||
x := x
|
||||
c.Run(fmt.Sprintf("case %d", i), func(c *testing.T) {
|
||||
_, err = apiClient.ContainerCreate(context.Background(), &x.config, &x.hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||
_, err = apiClient.ContainerCreate(context.Background(), &x.config, &x.hostConfig, &network.NetworkingConfig{}, nil, "")
|
||||
if len(x.msg) > 0 {
|
||||
assert.ErrorContains(c, err, x.msg, "%v", cases[i].config)
|
||||
} else {
|
||||
|
@ -1946,12 +1950,12 @@ func (s *DockerSuite) TestContainerAPICreateMountsBindRead(c *testing.T) {
|
|||
defer os.RemoveAll(tmpDir)
|
||||
err = os.WriteFile(filepath.Join(tmpDir, "bar"), []byte("hello"), 0666)
|
||||
assert.NilError(c, err)
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"/bin/sh", "-c", "cat /foo/bar"},
|
||||
}
|
||||
hostConfig := containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{
|
||||
hostConfig := container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{Type: "bind", Source: tmpDir, Target: destPath},
|
||||
},
|
||||
}
|
||||
|
@ -1959,7 +1963,7 @@ func (s *DockerSuite) TestContainerAPICreateMountsBindRead(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "test")
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "test")
|
||||
assert.NilError(c, err)
|
||||
|
||||
out, _ := dockerCmd(c, "start", "-a", "test")
|
||||
|
@ -1986,7 +1990,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
|||
}
|
||||
|
||||
type testCase struct {
|
||||
spec mounttypes.Mount
|
||||
spec mount.Mount
|
||||
expected types.MountPoint
|
||||
}
|
||||
|
||||
|
@ -2004,23 +2008,23 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
|||
// use literal strings here for `Type` instead of the defined constants in the volume package to keep this honest
|
||||
// Validation of the actual `Mount` struct is done in another test is not needed here
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath},
|
||||
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath + slash},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath + slash},
|
||||
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath, Source: "test1"},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test1"},
|
||||
expected: types.MountPoint{Type: "volume", Name: "test1", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath, ReadOnly: true, Source: "test2"},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath, ReadOnly: true, Source: "test2"},
|
||||
expected: types.MountPoint{Type: "volume", Name: "test2", RW: false, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath, Source: "test3", VolumeOptions: &mounttypes.VolumeOptions{DriverConfig: &mounttypes.Driver{Name: volume.DefaultDriverName}}},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test3", VolumeOptions: &mount.VolumeOptions{DriverConfig: &mount.Driver{Name: volume.DefaultDriverName}}},
|
||||
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", Name: "test3", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
}
|
||||
|
@ -2032,7 +2036,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
|||
defer os.RemoveAll(tmpDir1)
|
||||
cases = append(cases, []testCase{
|
||||
{
|
||||
spec: mounttypes.Mount{
|
||||
spec: mount.Mount{
|
||||
Type: "bind",
|
||||
Source: tmpDir1,
|
||||
Target: destPath,
|
||||
|
@ -2045,7 +2049,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "bind", Source: tmpDir1, Target: destPath, ReadOnly: true},
|
||||
spec: mount.Mount{Type: "bind", Source: tmpDir1, Target: destPath, ReadOnly: true},
|
||||
expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir1},
|
||||
},
|
||||
}...)
|
||||
|
@ -2060,15 +2064,15 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
|||
|
||||
cases = append(cases, []testCase{
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath},
|
||||
spec: mount.Mount{Type: "bind", Source: tmpDir3, Target: destPath},
|
||||
expected: types.MountPoint{Type: "bind", RW: true, Destination: destPath, Source: tmpDir3},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true},
|
||||
spec: mount.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true},
|
||||
expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true, BindOptions: &mounttypes.BindOptions{Propagation: "shared"}},
|
||||
spec: mount.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true, BindOptions: &mount.BindOptions{Propagation: "shared"}},
|
||||
expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3, Propagation: "shared"},
|
||||
},
|
||||
}...)
|
||||
|
@ -2078,19 +2082,19 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
|||
if testEnv.OSType != "windows" { // Windows does not support volume populate
|
||||
cases = append(cases, []testCase{
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath, VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
||||
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath + slash, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath + slash, VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
||||
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath, Source: "test4", VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test4", VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
||||
expected: types.MountPoint{Type: "volume", Name: "test4", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
{
|
||||
spec: mounttypes.Mount{Type: "volume", Target: destPath, Source: "test5", ReadOnly: true, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
|
||||
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test5", ReadOnly: true, VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
||||
expected: types.MountPoint{Type: "volume", Name: "test5", RW: false, Destination: destPath, Mode: selinuxSharedLabel},
|
||||
},
|
||||
}...)
|
||||
|
@ -2103,9 +2107,9 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
|||
c.Run(fmt.Sprintf("%d config: %v", i, x.spec), func(c *testing.T) {
|
||||
container, err := apiclient.ContainerCreate(
|
||||
ctx,
|
||||
&containertypes.Config{Image: testImg},
|
||||
&containertypes.HostConfig{Mounts: []mounttypes.Mount{x.spec}},
|
||||
&networktypes.NetworkingConfig{},
|
||||
&container.Config{Image: testImg},
|
||||
&container.HostConfig{Mounts: []mount.Mount{x.spec}},
|
||||
&network.NetworkingConfig{},
|
||||
nil,
|
||||
"")
|
||||
assert.NilError(c, err)
|
||||
|
@ -2179,22 +2183,22 @@ func containerExit(apiclient client.APIClient, name string) func(poll.LogT) poll
|
|||
func (s *DockerSuite) TestContainersAPICreateMountsTmpfs(c *testing.T) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
type testCase struct {
|
||||
cfg mounttypes.Mount
|
||||
cfg mount.Mount
|
||||
expectedOptions []string
|
||||
}
|
||||
target := "/foo"
|
||||
cases := []testCase{
|
||||
{
|
||||
cfg: mounttypes.Mount{
|
||||
cfg: mount.Mount{
|
||||
Type: "tmpfs",
|
||||
Target: target},
|
||||
expectedOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime"},
|
||||
},
|
||||
{
|
||||
cfg: mounttypes.Mount{
|
||||
cfg: mount.Mount{
|
||||
Type: "tmpfs",
|
||||
Target: target,
|
||||
TmpfsOptions: &mounttypes.TmpfsOptions{
|
||||
TmpfsOptions: &mount.TmpfsOptions{
|
||||
SizeBytes: 4096 * 1024, Mode: 0700}},
|
||||
expectedOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime", "size=4096k", "mode=700"},
|
||||
},
|
||||
|
@ -2204,17 +2208,17 @@ func (s *DockerSuite) TestContainersAPICreateMountsTmpfs(c *testing.T) {
|
|||
assert.NilError(c, err)
|
||||
defer cli.Close()
|
||||
|
||||
config := containertypes.Config{
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"/bin/sh", "-c", fmt.Sprintf("mount | grep 'tmpfs on %s'", target)},
|
||||
}
|
||||
for i, x := range cases {
|
||||
cName := fmt.Sprintf("test-tmpfs-%d", i)
|
||||
hostConfig := containertypes.HostConfig{
|
||||
Mounts: []mounttypes.Mount{x.cfg},
|
||||
hostConfig := container.HostConfig{
|
||||
Mounts: []mount.Mount{x.cfg},
|
||||
}
|
||||
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, cName)
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, cName)
|
||||
assert.NilError(c, err)
|
||||
out, _ := dockerCmd(c, "start", "-a", cName)
|
||||
for _, option := range x.expectedOptions {
|
||||
|
|
|
@ -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…
Reference in a new issue