diff --git a/api/client/build.go b/api/client/build.go index 38ade49ef7..0e12b4de41 100644 --- a/api/client/build.go +++ b/api/client/build.go @@ -16,6 +16,7 @@ import ( "github.com/docker/docker/api" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/builder/dockerignore" Cli "github.com/docker/docker/cli" "github.com/docker/docker/opts" @@ -207,6 +208,14 @@ func (cli *DockerCli) CmdBuild(args ...string) error { } } + var shmSize int64 + if *flShmSize != "" { + shmSize, err = units.RAMInBytes(*flShmSize) + if err != nil { + return err + } + } + var remoteContext string if isRemote { remoteContext = cmd.Arg(0) @@ -223,17 +232,17 @@ func (cli *DockerCli) CmdBuild(args ...string) error { Remove: *rm, ForceRemove: *forceRm, PullParent: *pull, - Isolation: *isolation, + IsolationLevel: container.IsolationLevel(*isolation), CPUSetCPUs: *flCPUSetCpus, CPUSetMems: *flCPUSetMems, CPUShares: *flCPUShares, CPUQuota: *flCPUQuota, CPUPeriod: *flCPUPeriod, CgroupParent: *flCgroupParent, - ShmSize: *flShmSize, Dockerfile: relDockerfile, + ShmSize: shmSize, Ulimits: flUlimits.GetList(), - BuildArgs: flBuildArg.GetAll(), + BuildArgs: runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()), AuthConfigs: cli.configFile.AuthConfigs, } diff --git a/api/client/lib/image_build.go b/api/client/lib/image_build.go index 0ed5da8dc1..da4d6efc68 100644 --- a/api/client/lib/image_build.go +++ b/api/client/lib/image_build.go @@ -11,7 +11,6 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" - "github.com/docker/go-units" ) var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`) @@ -73,8 +72,8 @@ func imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, erro query.Set("pull", "1") } - if !container.IsolationLevel.IsDefault(container.IsolationLevel(options.Isolation)) { - query.Set("isolation", options.Isolation) + if !container.IsolationLevel.IsDefault(options.IsolationLevel) { + query.Set("isolation", string(options.IsolationLevel)) } query.Set("cpusetcpus", options.CPUSetCPUs) @@ -85,15 +84,7 @@ func imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, erro query.Set("memory", strconv.FormatInt(options.Memory, 10)) query.Set("memswap", strconv.FormatInt(options.MemorySwap, 10)) query.Set("cgroupparent", options.CgroupParent) - - if options.ShmSize != "" { - parsedShmSize, err := units.RAMInBytes(options.ShmSize) - if err != nil { - return query, err - } - query.Set("shmsize", strconv.FormatInt(parsedShmSize, 10)) - } - + query.Set("shmsize", strconv.FormatInt(options.ShmSize, 10)) query.Set("dockerfile", options.Dockerfile) ulimitsJSON, err := json.Marshal(options.Ulimits) @@ -102,8 +93,7 @@ func imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, erro } query.Set("ulimits", string(ulimitsJSON)) - buildArgs := convertKVStringsToMap(options.BuildArgs) - buildArgsJSON, err := json.Marshal(buildArgs) + buildArgsJSON, err := json.Marshal(options.BuildArgs) if err != nil { return query, err } diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go index 4222004c07..0fec49586b 100644 --- a/api/server/router/build/build_routes.go +++ b/api/server/router/build/build_routes.go @@ -68,11 +68,72 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) { return repoAndTags, nil } +func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBuildOptions, error) { + version := httputils.VersionFromContext(ctx) + options := &types.ImageBuildOptions{} + if httputils.BoolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") { + options.Remove = true + } else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") { + options.Remove = true + } else { + options.Remove = httputils.BoolValue(r, "rm") + } + if httputils.BoolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") { + options.PullParent = true + } + + options.Dockerfile = r.FormValue("dockerfile") + options.SuppressOutput = httputils.BoolValue(r, "q") + options.NoCache = httputils.BoolValue(r, "nocache") + options.ForceRemove = httputils.BoolValue(r, "forcerm") + options.MemorySwap = httputils.Int64ValueOrZero(r, "memswap") + options.Memory = httputils.Int64ValueOrZero(r, "memory") + options.CPUShares = httputils.Int64ValueOrZero(r, "cpushares") + options.CPUPeriod = httputils.Int64ValueOrZero(r, "cpuperiod") + options.CPUQuota = httputils.Int64ValueOrZero(r, "cpuquota") + options.CPUSetCPUs = r.FormValue("cpusetcpus") + options.CPUSetMems = r.FormValue("cpusetmems") + options.CgroupParent = r.FormValue("cgroupparent") + + if r.Form.Get("shmsize") != "" { + shmSize, err := strconv.ParseInt(r.Form.Get("shmsize"), 10, 64) + if err != nil { + return nil, err + } + options.ShmSize = shmSize + } + + if i := container.IsolationLevel(r.FormValue("isolation")); i != "" { + if !container.IsolationLevel.IsValid(i) { + return nil, fmt.Errorf("Unsupported isolation: %q", i) + } + options.IsolationLevel = i + } + + var buildUlimits = []*units.Ulimit{} + ulimitsJSON := r.FormValue("ulimits") + if ulimitsJSON != "" { + if err := json.NewDecoder(strings.NewReader(ulimitsJSON)).Decode(&buildUlimits); err != nil { + return nil, err + } + options.Ulimits = buildUlimits + } + + var buildArgs = map[string]string{} + buildArgsJSON := r.FormValue("buildargs") + if buildArgsJSON != "" { + if err := json.NewDecoder(strings.NewReader(buildArgsJSON)).Decode(&buildArgs); err != nil { + return nil, err + } + options.BuildArgs = buildArgs + } + return options, nil +} + func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var ( authConfigs = map[string]types.AuthConfig{} authConfigsEncoded = r.Header.Get("X-Registry-Config") - buildConfig = &dockerfile.Config{} notVerboseBuffer = bytes.NewBuffer(nil) ) @@ -87,12 +148,11 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * w.Header().Set("Content-Type", "application/json") - version := httputils.VersionFromContext(ctx) output := ioutils.NewWriteFlusher(w) defer output.Close() sf := streamformatter.NewJSONStreamFormatter() errf := func(err error) error { - if !buildConfig.Verbose && notVerboseBuffer.Len() > 0 { + if httputils.BoolValue(r, "q") && notVerboseBuffer.Len() > 0 { output.Write(notVerboseBuffer.Bytes()) } // Do not write the error in the http output if it's still empty. @@ -107,15 +167,9 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * return nil } - if httputils.BoolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") { - buildConfig.Remove = true - } else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") { - buildConfig.Remove = true - } else { - buildConfig.Remove = httputils.BoolValue(r, "rm") - } - if httputils.BoolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") { - buildConfig.Pull = true + buildOptions, err := newImageBuildOptions(ctx, r) + if err != nil { + return errf(err) } repoAndTags, err := sanitizeRepoAndTags(r.Form["t"]) @@ -123,59 +177,13 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * return errf(err) } - buildConfig.DockerfileName = r.FormValue("dockerfile") - buildConfig.Verbose = !httputils.BoolValue(r, "q") - buildConfig.UseCache = !httputils.BoolValue(r, "nocache") - buildConfig.ForceRemove = httputils.BoolValue(r, "forcerm") - buildConfig.MemorySwap = httputils.Int64ValueOrZero(r, "memswap") - buildConfig.Memory = httputils.Int64ValueOrZero(r, "memory") - buildConfig.CPUShares = httputils.Int64ValueOrZero(r, "cpushares") - buildConfig.CPUPeriod = httputils.Int64ValueOrZero(r, "cpuperiod") - buildConfig.CPUQuota = httputils.Int64ValueOrZero(r, "cpuquota") - buildConfig.CPUSetCpus = r.FormValue("cpusetcpus") - buildConfig.CPUSetMems = r.FormValue("cpusetmems") - buildConfig.CgroupParent = r.FormValue("cgroupparent") - - if r.Form.Get("shmsize") != "" { - shmSize, err := strconv.ParseInt(r.Form.Get("shmsize"), 10, 64) - if err != nil { - return errf(err) - } - buildConfig.ShmSize = &shmSize - } - - if i := container.IsolationLevel(r.FormValue("isolation")); i != "" { - if !container.IsolationLevel.IsValid(i) { - return errf(fmt.Errorf("Unsupported isolation: %q", i)) - } - buildConfig.Isolation = i - } - - var buildUlimits = []*units.Ulimit{} - ulimitsJSON := r.FormValue("ulimits") - if ulimitsJSON != "" { - if err := json.NewDecoder(strings.NewReader(ulimitsJSON)).Decode(&buildUlimits); err != nil { - return errf(err) - } - buildConfig.Ulimits = buildUlimits - } - - var buildArgs = map[string]string{} - buildArgsJSON := r.FormValue("buildargs") - if buildArgsJSON != "" { - if err := json.NewDecoder(strings.NewReader(buildArgsJSON)).Decode(&buildArgs); err != nil { - return errf(err) - } - buildConfig.BuildArgs = buildArgs - } - remoteURL := r.FormValue("remote") // Currently, only used if context is from a remote url. // Look at code in DetectContextFromRemoteURL for more information. createProgressReader := func(in io.ReadCloser) io.ReadCloser { progressOutput := sf.NewProgressOutput(output, true) - if !buildConfig.Verbose { + if buildOptions.SuppressOutput { progressOutput = sf.NewProgressOutput(notVerboseBuffer, true) } return progress.NewProgressReader(in, progressOutput, r.ContentLength, "Downloading context", remoteURL) @@ -194,6 +202,9 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * logrus.Debugf("[BUILDER] failed to remove temporary context: %v", err) } }() + if len(dockerfileName) > 0 { + buildOptions.Dockerfile = dockerfileName + } uidMaps, gidMaps := br.backend.GetUIDGIDMaps() defaultArchiver := &archive.Archiver{ @@ -201,23 +212,28 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * UIDMaps: uidMaps, GIDMaps: gidMaps, } + docker := &daemonbuilder.Docker{ Daemon: br.backend, OutOld: output, AuthConfigs: authConfigs, Archiver: defaultArchiver, } - if !buildConfig.Verbose { + if buildOptions.SuppressOutput { docker.OutOld = notVerboseBuffer } - b, err := dockerfile.NewBuilder(buildConfig, docker, builder.DockerIgnoreContext{ModifiableContext: context}, nil) + b, err := dockerfile.NewBuilder( + buildOptions, // result of newBuildConfig + docker, + builder.DockerIgnoreContext{ModifiableContext: context}, + nil) if err != nil { return errf(err) } b.Stdout = &streamformatter.StdoutFormatter{Writer: output, StreamFormatter: sf} b.Stderr = &streamformatter.StderrFormatter{Writer: output, StreamFormatter: sf} - if !buildConfig.Verbose { + if buildOptions.SuppressOutput { b.Stdout = &streamformatter.StdoutFormatter{Writer: notVerboseBuffer, StreamFormatter: sf} b.Stderr = &streamformatter.StderrFormatter{Writer: notVerboseBuffer, StreamFormatter: sf} } @@ -235,10 +251,6 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * }() } - if len(dockerfileName) > 0 { - b.DockerfileName = dockerfileName - } - imgID, err := b.Build() if err != nil { return errf(err) @@ -252,7 +264,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * // Everything worked so if -q was provided the output from the daemon // should be just the image ID and we'll print that to stdout. - if !buildConfig.Verbose { + if buildOptions.SuppressOutput { stdout := &streamformatter.StdoutFormatter{Writer: output, StreamFormatter: sf} fmt.Fprintf(stdout, "%s\n", string(imgID)) } diff --git a/api/types/client.go b/api/types/client.go index 30f3b6fb8d..c936235173 100644 --- a/api/types/client.go +++ b/api/types/client.go @@ -127,7 +127,7 @@ type ImageBuildOptions struct { Remove bool ForceRemove bool PullParent bool - Isolation string + IsolationLevel container.IsolationLevel CPUSetCPUs string CPUSetMems string CPUShares int64 @@ -136,10 +136,10 @@ type ImageBuildOptions struct { Memory int64 MemorySwap int64 CgroupParent string - ShmSize string + ShmSize int64 Dockerfile string Ulimits []*units.Ulimit - BuildArgs []string + BuildArgs map[string]string AuthConfigs map[string]AuthConfig Context io.Reader } diff --git a/api/types/container/host_config.go b/api/types/container/host_config.go index 96f73e1170..623e5d108f 100644 --- a/api/types/container/host_config.go +++ b/api/types/container/host_config.go @@ -216,7 +216,7 @@ type HostConfig struct { SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container UTSMode UTSMode // UTS namespace to use for the container - ShmSize *int64 // Total shm memory usage + ShmSize int64 // Total shm memory usage // Applicable to Windows ConsoleSize [2]int // Initial console size diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index 102918da9a..8951793bff 100644 --- a/builder/dockerfile/builder.go +++ b/builder/dockerfile/builder.go @@ -10,11 +10,11 @@ import ( "sync" "github.com/Sirupsen/logrus" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/builder" "github.com/docker/docker/builder/dockerfile/parser" "github.com/docker/docker/pkg/stringid" - "github.com/docker/go-units" ) var validCommitCommands = map[string]bool{ @@ -41,38 +41,10 @@ var BuiltinAllowedBuildArgs = map[string]bool{ "no_proxy": true, } -// Config constitutes the configuration for a Dockerfile builder. -type Config struct { - // only used if Dockerfile has to be extracted from Context - DockerfileName string - - Verbose bool - UseCache bool - Remove bool - ForceRemove bool - Pull bool - BuildArgs map[string]string // build-time args received in build context for expansion/substitution and commands in 'run'. - Isolation container.IsolationLevel - - // resource constraints - // TODO: factor out to be reused with Run ? - - Memory int64 - MemorySwap int64 - ShmSize *int64 - CPUShares int64 - CPUPeriod int64 - CPUQuota int64 - CPUSetCpus string - CPUSetMems string - CgroupParent string - Ulimits []*units.Ulimit -} - // Builder is a Dockerfile builder // It implements the builder.Backend interface. type Builder struct { - *Config + options *types.ImageBuildOptions Stdout io.Writer Stderr io.Writer @@ -101,18 +73,18 @@ type Builder struct { // NewBuilder creates a new Dockerfile builder from an optional dockerfile and a Config. // If dockerfile is nil, the Dockerfile specified by Config.DockerfileName, // will be read from the Context passed to Build(). -func NewBuilder(config *Config, docker builder.Backend, context builder.Context, dockerfile io.ReadCloser) (b *Builder, err error) { +func NewBuilder(config *types.ImageBuildOptions, backend builder.Backend, context builder.Context, dockerfile io.ReadCloser) (b *Builder, err error) { if config == nil { - config = new(Config) + config = new(types.ImageBuildOptions) } if config.BuildArgs == nil { config.BuildArgs = make(map[string]string) } b = &Builder{ - Config: config, + options: config, Stdout: os.Stdout, Stderr: os.Stderr, - docker: docker, + docker: backend, context: context, runConfig: new(container.Config), tmpContainers: map[string]struct{}{}, @@ -162,14 +134,14 @@ func (b *Builder) Build() (string, error) { // Not cancelled yet, keep going... } if err := b.dispatch(i, n); err != nil { - if b.ForceRemove { + if b.options.ForceRemove { b.clearTmp() } return "", err } shortImgID = stringid.TruncateID(b.image) fmt.Fprintf(b.Stdout, " ---> %s\n", shortImgID) - if b.Remove { + if b.options.Remove { b.clearTmp() } } @@ -177,7 +149,7 @@ func (b *Builder) Build() (string, error) { // check if there are any leftover build-args that were passed but not // consumed during build. Return an error, if there are any. leftoverArgs := []string{} - for arg := range b.BuildArgs { + for arg := range b.options.BuildArgs { if !b.isBuildArgAllowed(arg) { leftoverArgs = append(leftoverArgs, arg) } diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go index 02d4413f1f..5f5f7f222e 100644 --- a/builder/dockerfile/dispatchers.go +++ b/builder/dockerfile/dispatchers.go @@ -209,7 +209,7 @@ func from(b *Builder, args []string, attributes map[string]bool, original string err error ) // TODO: don't use `name`, instead resolve it to a digest - if !b.Pull { + if !b.options.PullParent { image, err = b.docker.GetImage(name) // TODO: shouldn't we error out if error is different from "not found" ? } @@ -339,7 +339,7 @@ func run(b *Builder, args []string, attributes map[string]bool, original string) // lookup for same image built with same build time environment. cmdBuildEnv := []string{} configEnv := runconfigopts.ConvertKVStringsToMap(b.runConfig.Env) - for key, val := range b.BuildArgs { + for key, val := range b.options.BuildArgs { if !b.isBuildArgAllowed(key) { // skip build-args that are not in allowed list, meaning they have // not been defined by an "ARG" Dockerfile command yet. @@ -622,8 +622,8 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string) // If there is a default value associated with this arg then add it to the // b.buildArgs if one is not already passed to the builder. The args passed // to builder override the default value of 'arg'. - if _, ok := b.BuildArgs[name]; !ok && hasDefault { - b.BuildArgs[name] = value + if _, ok := b.options.BuildArgs[name]; !ok && hasDefault { + b.options.BuildArgs[name] = value } return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg)) diff --git a/builder/dockerfile/evaluator.go b/builder/dockerfile/evaluator.go index 2b3d2c8297..270e3a4ffe 100644 --- a/builder/dockerfile/evaluator.go +++ b/builder/dockerfile/evaluator.go @@ -148,7 +148,7 @@ func (b *Builder) dispatch(stepN int, ast *parser.Node) error { // a subsequent one. So, putting the buildArgs list after the Config.Env // list, in 'envs', is safe. envs := b.runConfig.Env - for key, val := range b.BuildArgs { + for key, val := range b.options.BuildArgs { if !b.isBuildArgAllowed(key) { // skip build-args that are not in allowed list, meaning they have // not been defined by an "ARG" Dockerfile command yet. diff --git a/builder/dockerfile/internals.go b/builder/dockerfile/internals.go index ce5f457a5e..70a9f44a59 100644 --- a/builder/dockerfile/internals.go +++ b/builder/dockerfile/internals.go @@ -450,7 +450,7 @@ func (b *Builder) processImageFrom(img builder.Image) error { // If there is any error, it returns `(false, err)`. func (b *Builder) probeCache() (bool, error) { c, ok := b.docker.(builder.ImageCache) - if !ok || !b.UseCache || b.cacheBusted { + if !ok || b.options.NoCache || b.cacheBusted { return false, nil } cache, err := c.GetCachedImage(b.image, b.runConfig) @@ -477,21 +477,21 @@ func (b *Builder) create() (string, error) { b.runConfig.Image = b.image resources := container.Resources{ - CgroupParent: b.CgroupParent, - CPUShares: b.CPUShares, - CPUPeriod: b.CPUPeriod, - CPUQuota: b.CPUQuota, - CpusetCpus: b.CPUSetCpus, - CpusetMems: b.CPUSetMems, - Memory: b.Memory, - MemorySwap: b.MemorySwap, - Ulimits: b.Ulimits, + CgroupParent: b.options.CgroupParent, + CPUShares: b.options.CPUShares, + CPUPeriod: b.options.CPUPeriod, + CPUQuota: b.options.CPUQuota, + CpusetCpus: b.options.CPUSetCPUs, + CpusetMems: b.options.CPUSetMems, + Memory: b.options.Memory, + MemorySwap: b.options.MemorySwap, + Ulimits: b.options.Ulimits, } // TODO: why not embed a hostconfig in builder? hostConfig := &container.HostConfig{ - Isolation: b.Isolation, - ShmSize: b.ShmSize, + Isolation: b.options.IsolationLevel, + ShmSize: b.options.ShmSize, Resources: resources, } @@ -587,20 +587,20 @@ func (b *Builder) readDockerfile() error { // If no -f was specified then look for 'Dockerfile'. If we can't find // that then look for 'dockerfile'. If neither are found then default // back to 'Dockerfile' and use that in the error message. - if b.DockerfileName == "" { - b.DockerfileName = api.DefaultDockerfileName - if _, _, err := b.context.Stat(b.DockerfileName); os.IsNotExist(err) { - lowercase := strings.ToLower(b.DockerfileName) + if b.options.Dockerfile == "" { + b.options.Dockerfile = api.DefaultDockerfileName + if _, _, err := b.context.Stat(b.options.Dockerfile); os.IsNotExist(err) { + lowercase := strings.ToLower(b.options.Dockerfile) if _, _, err := b.context.Stat(lowercase); err == nil { - b.DockerfileName = lowercase + b.options.Dockerfile = lowercase } } } - f, err := b.context.Open(b.DockerfileName) + f, err := b.context.Open(b.options.Dockerfile) if err != nil { if os.IsNotExist(err) { - return fmt.Errorf("Cannot locate specified Dockerfile: %s", b.DockerfileName) + return fmt.Errorf("Cannot locate specified Dockerfile: %s", b.options.Dockerfile) } return err } @@ -611,7 +611,7 @@ func (b *Builder) readDockerfile() error { return fmt.Errorf("Unexpected error reading Dockerfile: %v", err) } if fi.Size() == 0 { - return fmt.Errorf("The Dockerfile (%s) cannot be empty", b.DockerfileName) + return fmt.Errorf("The Dockerfile (%s) cannot be empty", b.options.Dockerfile) } } b.dockerfile, err = parser.Parse(f) @@ -629,7 +629,7 @@ func (b *Builder) readDockerfile() error { // Note that this assumes the Dockerfile has been read into memory and // is now safe to be removed. if dockerIgnore, ok := b.context.(builder.DockerIgnoreContext); ok { - dockerIgnore.Process([]string{b.DockerfileName}) + dockerIgnore.Process([]string{b.options.Dockerfile}) } return nil } diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index fb1f96677f..fceb2da42c 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -899,8 +899,8 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error { } shmSize := container.DefaultSHMSize - if c.HostConfig.ShmSize != nil { - shmSize = *c.HostConfig.ShmSize + if c.HostConfig.ShmSize != 0 { + shmSize = c.HostConfig.ShmSize } shmproperty := "mode=1777,size=" + strconv.FormatInt(shmSize, 10) if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel(shmproperty, c.GetMountLabel())); err != nil { diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 68e04ea882..5186b29107 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -191,9 +191,8 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf // By default, MemorySwap is set to twice the size of Memory. hostConfig.MemorySwap = hostConfig.Memory * 2 } - if hostConfig.ShmSize == nil { - shmSize := container.DefaultSHMSize - hostConfig.ShmSize = &shmSize + if hostConfig.ShmSize == 0 { + hostConfig.ShmSize = container.DefaultSHMSize } var err error if hostConfig.SecurityOpt == nil { @@ -365,7 +364,7 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. } warnings = append(warnings, w...) - if hostConfig.ShmSize != nil && *hostConfig.ShmSize <= 0 { + if hostConfig.ShmSize < 0 { return warnings, fmt.Errorf("SHM size must be greater then 0") } diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go index 5c33520170..6e1d288e61 100644 --- a/integration-cli/docker_api_containers_test.go +++ b/integration-cli/docker_api_containers_test.go @@ -1403,18 +1403,6 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeNegative(c *check.C) { c.Assert(string(body), checker.Contains, "SHM size must be greater then 0") } -func (s *DockerSuite) TestPostContainersCreateShmSizeZero(c *check.C) { - config := map[string]interface{}{ - "Image": "busybox", - "HostConfig": map[string]interface{}{"ShmSize": 0}, - } - - status, body, err := sockRequest("POST", "/containers/create", config) - c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusInternalServerError) - c.Assert(string(body), checker.Contains, "SHM size must be greater then 0") -} - func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *check.C) { var defaultSHMSize int64 = 67108864 config := map[string]interface{}{ @@ -1436,7 +1424,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *check. var containerJSON types.ContainerJSON c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil) - c.Assert(*containerJSON.HostConfig.ShmSize, check.Equals, defaultSHMSize) + c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, defaultSHMSize) out, _ := dockerCmd(c, "start", "-i", containerJSON.ID) shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`) @@ -1466,7 +1454,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *check.C) { var containerJSON types.ContainerJSON c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil) - c.Assert(*containerJSON.HostConfig.ShmSize, check.Equals, int64(67108864)) + c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, int64(67108864)) out, _ := dockerCmd(c, "start", "-i", containerJSON.ID) shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`) @@ -1496,7 +1484,7 @@ func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *check.C) { var containerJSON types.ContainerJSON c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil) - c.Assert(*containerJSON.HostConfig.ShmSize, check.Equals, int64(1073741824)) + c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, int64(1073741824)) out, _ := dockerCmd(c, "start", "-i", containerJSON.ID) shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=1048576k`) diff --git a/runconfig/opts/parse.go b/runconfig/opts/parse.go index bef65c8779..ad3c0eeaab 100644 --- a/runconfig/opts/parse.go +++ b/runconfig/opts/parse.go @@ -186,13 +186,12 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host return nil, nil, cmd, fmt.Errorf("Invalid value: %d. Valid memory swappiness range is 0-100", swappiness) } - var parsedShm *int64 + var shmSize int64 if *flShmSize != "" { - shmSize, err := units.RAMInBytes(*flShmSize) + shmSize, err = units.RAMInBytes(*flShmSize) if err != nil { return nil, nil, cmd, err } - parsedShm = &shmSize } var binds []string @@ -397,7 +396,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host LogConfig: container.LogConfig{Type: *flLoggingDriver, Config: loggingOpts}, VolumeDriver: *flVolumeDriver, Isolation: container.IsolationLevel(*flIsolation), - ShmSize: parsedShm, + ShmSize: shmSize, Resources: resources, Tmpfs: tmpfs, } diff --git a/runconfig/opts/parse_test.go b/runconfig/opts/parse_test.go index 90703ea878..2c7e100ef9 100644 --- a/runconfig/opts/parse_test.go +++ b/runconfig/opts/parse_test.go @@ -535,8 +535,8 @@ func TestParseModes(t *testing.T) { if err != nil { t.Fatal(err) } - if *hostconfig.ShmSize != 134217728 { - t.Fatalf("Expected a valid ShmSize, got %d", *hostconfig.ShmSize) + if hostconfig.ShmSize != 134217728 { + t.Fatalf("Expected a valid ShmSize, got %d", hostconfig.ShmSize) } }