Use ImageBuildOptions in builder.

dockerfile.Config is almost redundant with ImageBuildOptions.
Unify the two so that the latter can be removed. This also
helps build's API endpoint code to be less dependent on package
dockerfile.

Signed-off-by: Anusha Ragunathan <anusha@docker.com>
This commit is contained in:
Anusha Ragunathan 2015-12-29 12:49:17 -08:00
parent d5685a65d7
commit 5190794f1d
14 changed files with 147 additions and 178 deletions

View file

@ -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,
}

View file

@ -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
}

View file

@ -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))
}

View file

@ -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
}

View file

@ -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

View file

@ -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)
}

View file

@ -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))

View file

@ -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.

View file

@ -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
}

View file

@ -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 {

View file

@ -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")
}

View file

@ -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`)

View file

@ -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,
}

View file

@ -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)
}
}