Merge pull request #46720 from akerouanton/container-create-init-structs

api: ContainerCreate: clean up BC conditions
This commit is contained in:
Sebastiaan van Stijn 2023-10-25 22:47:29 +02:00 committed by GitHub
commit 460e1b3600
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 42 deletions

View file

@ -19,10 +19,12 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
containerpkg "github.com/docker/docker/container"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/runconfig"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/net/websocket"
@ -492,21 +494,39 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
}
return err
}
if config == nil {
return errdefs.InvalidParameter(runconfig.ErrEmptyConfig)
}
if hostConfig == nil {
hostConfig = &container.HostConfig{}
}
if hostConfig.NetworkMode == "" {
hostConfig.NetworkMode = "default"
}
if networkingConfig == nil {
networkingConfig = &network.NetworkingConfig{}
}
if networkingConfig.EndpointsConfig == nil {
networkingConfig.EndpointsConfig = make(map[string]*network.EndpointSettings)
}
version := httputils.VersionFromContext(ctx)
adjustCPUShares := versions.LessThan(version, "1.19")
// When using API 1.24 and under, the client is responsible for removing the container
if hostConfig != nil && versions.LessThan(version, "1.25") {
if versions.LessThan(version, "1.25") {
hostConfig.AutoRemove = false
}
if hostConfig != nil && versions.LessThan(version, "1.40") {
if versions.LessThan(version, "1.40") {
// Ignore BindOptions.NonRecursive because it was added in API 1.40.
for _, m := range hostConfig.Mounts {
if bo := m.BindOptions; bo != nil {
bo.NonRecursive = false
}
}
// Ignore KernelMemoryTCP because it was added in API 1.40.
hostConfig.KernelMemoryTCP = 0
@ -515,14 +535,26 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
hostConfig.IpcMode = container.IPCModeShareable
}
}
if hostConfig != nil && versions.LessThan(version, "1.41") && !s.cgroup2 {
if versions.LessThan(version, "1.41") {
// Older clients expect the default to be "host" on cgroup v1 hosts
if hostConfig.CgroupnsMode.IsEmpty() {
if !s.cgroup2 && hostConfig.CgroupnsMode.IsEmpty() {
hostConfig.CgroupnsMode = container.CgroupnsModeHost
}
}
if hostConfig != nil && versions.LessThan(version, "1.42") {
var platform *ocispec.Platform
if versions.GreaterThanOrEqualTo(version, "1.41") {
if v := r.Form.Get("platform"); v != "" {
p, err := platforms.Parse(v)
if err != nil {
return errdefs.InvalidParameter(err)
}
platform = &p
}
}
if versions.LessThan(version, "1.42") {
for _, m := range hostConfig.Mounts {
// Ignore BindOptions.CreateMountpoint because it was added in API 1.42.
if bo := m.BindOptions; bo != nil {
@ -542,16 +574,14 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
bo.CreateMountpoint = false
}
}
}
if config != nil && versions.LessThan(version, "1.44") {
if config.Healthcheck != nil {
// StartInterval was added in API 1.44
config.Healthcheck.StartInterval = 0
if runtime.GOOS == "linux" {
// ConsoleSize is not respected by Linux daemon before API 1.42
hostConfig.ConsoleSize = [2]uint{0, 0}
}
}
if hostConfig != nil && versions.GreaterThanOrEqualTo(version, "1.42") {
if versions.GreaterThanOrEqualTo(version, "1.42") {
// Ignore KernelMemory removed in API 1.42.
hostConfig.KernelMemory = 0
for _, m := range hostConfig.Mounts {
@ -567,36 +597,17 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
}
}
if hostConfig != nil && runtime.GOOS == "linux" && versions.LessThan(version, "1.42") {
// ConsoleSize is not respected by Linux daemon before API 1.42
hostConfig.ConsoleSize = [2]uint{0, 0}
}
if hostConfig != nil && versions.LessThan(version, "1.43") {
if versions.LessThan(version, "1.43") {
// Ignore Annotations because it was added in API v1.43.
hostConfig.Annotations = nil
}
var platform *ocispec.Platform
if versions.GreaterThanOrEqualTo(version, "1.41") {
if v := r.Form.Get("platform"); v != "" {
p, err := platforms.Parse(v)
if err != nil {
return errdefs.InvalidParameter(err)
}
platform = &p
if versions.LessThan(version, "1.44") {
if config.Healthcheck != nil {
// StartInterval was added in API 1.44
config.Healthcheck.StartInterval = 0
}
}
if hostConfig != nil && hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
// Don't set a limit if either no limit was specified, or "unlimited" was
// explicitly set.
// Both `0` and `-1` are accepted as "unlimited", and historically any
// negative value was accepted, so treat those as "unlimited" as well.
hostConfig.PidsLimit = nil
}
if hostConfig != nil && versions.LessThan(version, "1.44") {
for _, m := range hostConfig.Mounts {
if m.BindOptions != nil {
// Ignore ReadOnlyNonRecursive because it was added in API 1.44.
@ -606,11 +617,9 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
}
}
}
}
if versions.LessThan(version, "1.44") {
// Creating a container connected to several networks is not supported until v1.44.
if networkingConfig != nil && len(networkingConfig.EndpointsConfig) > 1 {
if len(networkingConfig.EndpointsConfig) > 1 {
l := make([]string, 0, len(networkingConfig.EndpointsConfig))
for k := range networkingConfig.EndpointsConfig {
l = append(l, k)
@ -619,6 +628,14 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
}
}
if hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
// Don't set a limit if either no limit was specified, or "unlimited" was
// explicitly set.
// Both `0` and `-1` are accepted as "unlimited", and historically any
// negative value was accepted, so treat those as "unlimited" as well.
hostConfig.PidsLimit = nil
}
ccr, err := s.backend.ContainerCreate(ctx, types.ContainerCreateConfig{
Name: name,
Config: config,

View file

@ -2,7 +2,6 @@ package daemon // import "github.com/docker/docker/daemon"
import (
"context"
"errors"
"fmt"
"runtime"
"strings"
@ -61,7 +60,7 @@ func (daemon *Daemon) ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context
func (daemon *Daemon) containerCreate(ctx context.Context, daemonCfg *configStore, opts createOpts) (containertypes.CreateResponse, error) {
start := time.Now()
if opts.params.Config == nil {
return containertypes.CreateResponse{}, errdefs.InvalidParameter(errors.New("Config cannot be empty in order to create a container"))
return containertypes.CreateResponse{}, errdefs.InvalidParameter(runconfig.ErrEmptyConfig)
}
// Normalize some defaults. Doing this "ad-hoc" here for now, as there's

View file

@ -12,6 +12,7 @@ import (
"github.com/docker/docker/api"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/testutil"
"github.com/docker/docker/testutil/request"
"gotest.tools/v3/assert"
@ -82,7 +83,7 @@ func (s *DockerAPISuite) TestAPIErrorJSON(c *testing.T) {
assert.Assert(c, strings.Contains(httpResp.Header.Get("Content-Type"), "application/json"))
b, err := request.ReadBody(body)
assert.NilError(c, err)
assert.Equal(c, getErrorMessage(c, b), "Config cannot be empty in order to create a container")
assert.Equal(c, getErrorMessage(c, b), runconfig.ErrEmptyConfig.Error())
}
func (s *DockerAPISuite) TestAPIErrorPlainText(c *testing.T) {
@ -99,7 +100,7 @@ func (s *DockerAPISuite) TestAPIErrorPlainText(c *testing.T) {
assert.Assert(c, strings.Contains(httpResp.Header.Get("Content-Type"), "text/plain"))
b, err := request.ReadBody(body)
assert.NilError(c, err)
assert.Equal(c, strings.TrimSpace(string(b)), "Config cannot be empty in order to create a container")
assert.Equal(c, strings.TrimSpace(string(b)), runconfig.ErrEmptyConfig.Error())
}
func (s *DockerAPISuite) TestAPIErrorNotFoundJSON(c *testing.T) {

View file

@ -31,6 +31,8 @@ const (
ErrUnsupportedNetworkAndAlias validationError = "network-scoped alias is supported only for containers in user defined networks"
// ErrConflictUTSHostname conflict between the hostname and the UTS mode
ErrConflictUTSHostname validationError = "conflicting options: hostname and the UTS mode"
// ErrEmptyConfig when container config is nil
ErrEmptyConfig validationError = "config cannot be empty in order to create a container"
)
type validationError string