diff --git a/components/engine/api/types/swarm/task.go b/components/engine/api/types/swarm/task.go index ff11b07e74..079ec3690f 100644 --- a/components/engine/api/types/swarm/task.go +++ b/components/engine/api/types/swarm/task.go @@ -162,19 +162,19 @@ const ( // TaskStatus represents the status of a task. type TaskStatus struct { - Timestamp time.Time `json:",omitempty"` - State TaskState `json:",omitempty"` - Message string `json:",omitempty"` - Err string `json:",omitempty"` - ContainerStatus ContainerStatus `json:",omitempty"` - PortStatus PortStatus `json:",omitempty"` + Timestamp time.Time `json:",omitempty"` + State TaskState `json:",omitempty"` + Message string `json:",omitempty"` + Err string `json:",omitempty"` + ContainerStatus *ContainerStatus `json:",omitempty"` + PortStatus PortStatus `json:",omitempty"` } // ContainerStatus represents the status of a container. type ContainerStatus struct { - ContainerID string `json:",omitempty"` - PID int `json:",omitempty"` - ExitCode int `json:",omitempty"` + ContainerID string + PID int + ExitCode int } // PortStatus represents the port status of a task's host ports whose diff --git a/components/engine/daemon/cluster/convert/task.go b/components/engine/daemon/cluster/convert/task.go index bedf2dba9e..be3bacf11c 100644 --- a/components/engine/daemon/cluster/convert/task.go +++ b/components/engine/daemon/cluster/convert/task.go @@ -42,9 +42,11 @@ func TaskFromGRPC(t swarmapi.Task) (types.Task, error) { task.Status.Timestamp, _ = gogotypes.TimestampFromProto(t.Status.Timestamp) if containerStatus != nil { - task.Status.ContainerStatus.ContainerID = containerStatus.ContainerID - task.Status.ContainerStatus.PID = int(containerStatus.PID) - task.Status.ContainerStatus.ExitCode = int(containerStatus.ExitCode) + task.Status.ContainerStatus = &types.ContainerStatus{ + ContainerID: containerStatus.ContainerID, + PID: int(containerStatus.PID), + ExitCode: int(containerStatus.ExitCode), + } } // NetworksAttachments diff --git a/components/engine/daemon/delete.go b/components/engine/daemon/delete.go index f16d38beb3..c6f8efec45 100644 --- a/components/engine/daemon/delete.go +++ b/components/engine/daemon/delete.go @@ -128,6 +128,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo container.SetRemovalError(e) return e } + container.RWLayer = nil } if err := system.EnsureRemoveAll(container.Root); err != nil { diff --git a/components/engine/integration-cli/docker_api_update_unix_test.go b/components/engine/integration-cli/docker_api_update_unix_test.go deleted file mode 100644 index e2e1b092be..0000000000 --- a/components/engine/integration-cli/docker_api_update_unix_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// +build !windows - -package main - -import ( - "strings" - - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/client" - "github.com/docker/docker/integration-cli/checker" - "github.com/go-check/check" - "golang.org/x/net/context" -) - -func (s *DockerSuite) TestAPIUpdateContainer(c *check.C) { - testRequires(c, DaemonIsLinux) - testRequires(c, memoryLimitSupport) - testRequires(c, swapMemorySupport) - - name := "apiUpdateContainer" - updateConfig := container.UpdateConfig{ - Resources: container.Resources{ - Memory: 314572800, - MemorySwap: 524288000, - }, - } - dockerCmd(c, "run", "-d", "--name", name, "-m", "200M", "busybox", "top") - cli, err := client.NewEnvClient() - c.Assert(err, check.IsNil) - defer cli.Close() - - _, err = cli.ContainerUpdate(context.Background(), name, updateConfig) - - c.Assert(err, check.IsNil) - - c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "314572800") - file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" - out, _ := dockerCmd(c, "exec", name, "cat", file) - c.Assert(strings.TrimSpace(out), checker.Equals, "314572800") - - c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "524288000") - file = "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes" - out, _ = dockerCmd(c, "exec", name, "cat", file) - c.Assert(strings.TrimSpace(out), checker.Equals, "524288000") -} diff --git a/components/engine/integration-cli/docker_cli_service_create_test.go b/components/engine/integration-cli/docker_cli_service_create_test.go index ac7eff713c..d690b7e45f 100644 --- a/components/engine/integration-cli/docker_cli_service_create_test.go +++ b/components/engine/integration-cli/docker_cli_service_create_test.go @@ -29,10 +29,10 @@ func (s *DockerSwarmSuite) TestServiceCreateMountVolume(c *check.C) { task := tasks[0] waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { - if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + if task.NodeID == "" || task.Status.ContainerStatus == nil { task = d.GetTask(c, task.ID) } - return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + return task.NodeID != "" && task.Status.ContainerStatus != nil, nil }, checker.Equals, true) // check container mount config @@ -143,10 +143,10 @@ func (s *DockerSwarmSuite) TestServiceCreateWithSecretSourceTargetPaths(c *check task := tasks[0] waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { - if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + if task.NodeID == "" || task.Status.ContainerStatus == nil { task = d.GetTask(c, task.ID) } - return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + return task.NodeID != "" && task.Status.ContainerStatus != nil, nil }, checker.Equals, true) for testName, testTarget := range testPaths { @@ -193,10 +193,10 @@ func (s *DockerSwarmSuite) TestServiceCreateWithSecretReferencedTwice(c *check.C task := tasks[0] waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { - if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + if task.NodeID == "" || task.Status.ContainerStatus == nil { task = d.GetTask(c, task.ID) } - return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + return task.NodeID != "" && task.Status.ContainerStatus != nil, nil }, checker.Equals, true) for _, target := range []string{"target1", "target2"} { @@ -290,10 +290,10 @@ func (s *DockerSwarmSuite) TestServiceCreateWithConfigSourceTargetPaths(c *check task := tasks[0] waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { - if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + if task.NodeID == "" || task.Status.ContainerStatus == nil { task = d.GetTask(c, task.ID) } - return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + return task.NodeID != "" && task.Status.ContainerStatus != nil, nil }, checker.Equals, true) for testName, testTarget := range testPaths { @@ -340,10 +340,10 @@ func (s *DockerSwarmSuite) TestServiceCreateWithConfigReferencedTwice(c *check.C task := tasks[0] waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { - if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + if task.NodeID == "" || task.Status.ContainerStatus == nil { task = d.GetTask(c, task.ID) } - return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + return task.NodeID != "" && task.Status.ContainerStatus != nil, nil }, checker.Equals, true) for _, target := range []string{"target1", "target2"} { @@ -372,10 +372,10 @@ func (s *DockerSwarmSuite) TestServiceCreateMountTmpfs(c *check.C) { task := tasks[0] waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { - if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + if task.NodeID == "" || task.Status.ContainerStatus == nil { task = d.GetTask(c, task.ID) } - return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + return task.NodeID != "" && task.Status.ContainerStatus != nil, nil }, checker.Equals, true) // check container mount config @@ -428,10 +428,10 @@ func (s *DockerSwarmSuite) TestServiceCreateWithNetworkAlias(c *check.C) { task := tasks[0] waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { - if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + if task.NodeID == "" || task.Status.ContainerStatus == nil { task = d.GetTask(c, task.ID) } - return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + return task.NodeID != "" && task.Status.ContainerStatus != nil, nil }, checker.Equals, true) // check container alias config diff --git a/components/engine/integration/container/update_linux_test.go b/components/engine/integration/container/update_linux_test.go index bb9906ac7d..53ed10692c 100644 --- a/components/engine/integration/container/update_linux_test.go +++ b/components/engine/integration/container/update_linux_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "io/ioutil" "strconv" "strings" "testing" @@ -11,10 +12,67 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/docker/client" "github.com/docker/docker/integration/util/request" "github.com/docker/docker/pkg/stdcopy" + "github.com/gotestyourself/gotestyourself/poll" + "github.com/gotestyourself/gotestyourself/skip" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) +func TestUpdateMemory(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + skip.If(t, !testEnv.DaemonInfo.MemoryLimit) + skip.If(t, !testEnv.DaemonInfo.SwapLimit) + + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + c, err := client.ContainerCreate(ctx, + &container.Config{ + Cmd: []string{"top"}, + Image: "busybox", + }, + &container.HostConfig{ + Resources: container.Resources{ + Memory: 200 * 1024 * 1024, + }, + }, + nil, + "", + ) + require.NoError(t, err) + + err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}) + require.NoError(t, err) + + poll.WaitOn(t, containerIsInState(ctx, client, c.ID, "running"), poll.WithDelay(100*time.Millisecond)) + + _, err = client.ContainerUpdate(ctx, c.ID, container.UpdateConfig{ + Resources: container.Resources{ + Memory: 314572800, + MemorySwap: 524288000, + }, + }) + require.NoError(t, err) + + inspect, err := client.ContainerInspect(ctx, c.ID) + require.NoError(t, err) + assert.Equal(t, inspect.HostConfig.Memory, int64(314572800)) + assert.Equal(t, inspect.HostConfig.MemorySwap, int64(524288000)) + + body, err := getContainerSysFSValue(ctx, client, c.ID, "/sys/fs/cgroup/memory/memory.limit_in_bytes") + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(body), "314572800") + + body, err = getContainerSysFSValue(ctx, client, c.ID, "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes") + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(body), "524288000") +} + func TestUpdateCPUQUota(t *testing.T) { t.Parallel() @@ -106,3 +164,33 @@ func TestUpdateCPUQUota(t *testing.T) { } } + +func getContainerSysFSValue(ctx context.Context, client client.APIClient, cID string, path string) (string, error) { + var b bytes.Buffer + + ex, err := client.ContainerExecCreate(ctx, cID, + types.ExecConfig{ + AttachStdout: true, + Cmd: strslice.StrSlice([]string{"cat", path}), + }, + ) + if err != nil { + return "", err + } + + resp, err := client.ContainerExecAttach(ctx, ex.ID, + types.ExecStartCheck{ + Detach: false, + Tty: false, + }, + ) + if err != nil { + return "", err + } + + defer resp.Close() + + b.Reset() + _, err = stdcopy.StdCopy(&b, ioutil.Discard, resp.Reader) + return b.String(), err +} diff --git a/components/engine/vendor.conf b/components/engine/vendor.conf index dc06f6a6fb..38ebca2602 100644 --- a/components/engine/vendor.conf +++ b/components/engine/vendor.conf @@ -16,7 +16,7 @@ github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 golang.org/x/sys 95c6576299259db960f6c5b9b69ea52422860fce github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 -github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d +github.com/docker/go-connections 98e7d807e5d804e4e42a98d74d1dd695321224ef golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987 github.com/pmezard/go-difflib v1.0.0 diff --git a/components/engine/vendor/github.com/docker/go-connections/tlsconfig/config.go b/components/engine/vendor/github.com/docker/go-connections/tlsconfig/config.go index 1b31bbb8b1..f11f166a44 100644 --- a/components/engine/vendor/github.com/docker/go-connections/tlsconfig/config.go +++ b/components/engine/vendor/github.com/docker/go-connections/tlsconfig/config.go @@ -65,22 +65,34 @@ var allTLSVersions = map[uint16]struct{}{ } // ServerDefault returns a secure-enough TLS configuration for the server TLS configuration. -func ServerDefault() *tls.Config { - return &tls.Config{ - // Avoid fallback to SSL protocols < TLS1.0 +func ServerDefault(ops ...func(*tls.Config)) *tls.Config { + tlsconfig := &tls.Config{ + // Avoid fallback by default to SSL protocols < TLS1.0 MinVersion: tls.VersionTLS10, PreferServerCipherSuites: true, CipherSuites: DefaultServerAcceptedCiphers, } + + for _, op := range ops { + op(tlsconfig) + } + + return tlsconfig } // ClientDefault returns a secure-enough TLS configuration for the client TLS configuration. -func ClientDefault() *tls.Config { - return &tls.Config{ +func ClientDefault(ops ...func(*tls.Config)) *tls.Config { + tlsconfig := &tls.Config{ // Prefer TLS1.2 as the client minimum MinVersion: tls.VersionTLS12, CipherSuites: clientCipherSuites, } + + for _, op := range ops { + op(tlsconfig) + } + + return tlsconfig } // certPool returns an X.509 certificate pool from `caFile`, the certificate file.