diff --git a/builder.go b/builder.go index 02c51fb557..ab07233cb8 100644 --- a/builder.go +++ b/builder.go @@ -50,12 +50,23 @@ func (builder *Builder) Create(config *Config) (*Container, error) { config.Hostname = id[:12] } + var args []string + var entrypoint string + + if len(config.Entrypoint) != 0 { + entrypoint = config.Entrypoint[0] + args = append(config.Entrypoint[1:], config.Cmd...) + } else { + entrypoint = config.Cmd[0] + args = config.Cmd[1:] + } + container := &Container{ // FIXME: we should generate the ID here instead of receiving it as an argument ID: id, Created: time.Now(), - Path: config.Cmd[0], - Args: config.Cmd[1:], //FIXME: de-duplicate from config + Path: entrypoint, + Args: args, //FIXME: de-duplicate from config Config: config, Image: img.ID, // Always use the resolved image id NetworkSettings: &NetworkSettings{}, diff --git a/buildfile.go b/buildfile.go index 63625e1a40..cdc2a6b041 100644 --- a/buildfile.go +++ b/buildfile.go @@ -141,7 +141,7 @@ func (b *buildFile) CmdEnv(args string) error { func (b *buildFile) CmdCmd(args string) error { var cmd []string if err := json.Unmarshal([]byte(args), &cmd); err != nil { - utils.Debugf("Error unmarshalling: %s, using /bin/sh -c", err) + utils.Debugf("Error unmarshalling: %s, setting cmd to /bin/sh -c", err) cmd = []string{"/bin/sh", "-c", args} } if err := b.commit("", cmd, fmt.Sprintf("CMD %v", cmd)); err != nil { @@ -165,6 +165,23 @@ func (b *buildFile) CmdCopy(args string) error { return fmt.Errorf("COPY has been deprecated. Please use ADD instead") } +func (b *buildFile) CmdEntrypoint(args string) error { + if args == "" { + return fmt.Errorf("Entrypoint cannot be empty") + } + + var entrypoint []string + if err := json.Unmarshal([]byte(args), &entrypoint); err != nil { + b.config.Entrypoint = []string{"/bin/sh", "-c", args} + } else { + b.config.Entrypoint = entrypoint + } + if err := b.commit("", b.config.Cmd, fmt.Sprintf("ENTRYPOINT %s", args)); err != nil { + return err + } + return nil +} + func (b *buildFile) addRemote(container *Container, orig, dest string) error { file, err := utils.Download(orig, ioutil.Discard) if err != nil { diff --git a/buildfile_test.go b/buildfile_test.go index c2ae79f199..0895cccc80 100644 --- a/buildfile_test.go +++ b/buildfile_test.go @@ -79,6 +79,15 @@ run [ "$(cat /somewheeeere/over/the/rainbooow/ga)" = "bu" ] from %s env FOO BAR run [ "$FOO" = "BAR" ] +`, + nil, + }, + + { + ` +from docker-ut +ENTRYPOINT /bin/echo +CMD Hello world `, nil, }, diff --git a/container.go b/container.go index 45bb728b96..508f39c0ef 100644 --- a/container.go +++ b/container.go @@ -76,6 +76,7 @@ type Config struct { Image string // Name of the image as it was passed by the operator (eg. could be symbolic) Volumes map[string]struct{} VolumesFrom string + Entrypoint []string } type HostConfig struct { @@ -123,6 +124,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, cmd.Var(flVolumes, "v", "Attach a data volume") flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container") + flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image") var flBinds ListOpts cmd.Var(&flBinds, "b", "Bind mount a volume from the host (e.g. -b /host:/container)") @@ -153,6 +155,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, parsedArgs := cmd.Args() runCmd := []string{} + entrypoint := []string{} image := "" if len(parsedArgs) >= 1 { image = cmd.Arg(0) @@ -160,6 +163,10 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, if len(parsedArgs) > 1 { runCmd = parsedArgs[1:] } + if *flEntrypoint != "" { + entrypoint = []string{*flEntrypoint} + } + config := &Config{ Hostname: *flHostname, PortSpecs: flPorts, @@ -177,6 +184,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, Image: image, Volumes: flVolumes, VolumesFrom: *flVolumesFrom, + Entrypoint: entrypoint, } hostConfig := &HostConfig{ Binds: flBinds, diff --git a/container_test.go b/container_test.go index cb33dcf983..8ffcf2a0de 100644 --- a/container_test.go +++ b/container_test.go @@ -1043,6 +1043,32 @@ func TestEnv(t *testing.T) { } } +func TestEntrypoint(t *testing.T) { + runtime, err := newTestRuntime() + if err != nil { + t.Fatal(err) + } + defer nuke(runtime) + container, err := NewBuilder(runtime).Create( + &Config{ + Image: GetTestImage(runtime).ID, + Entrypoint: []string{"/bin/echo"}, + Cmd: []string{"-n", "foobar"}, + }, + ) + if err != nil { + t.Fatal(err) + } + defer runtime.Destroy(container) + output, err := container.Output() + if err != nil { + t.Fatal(err) + } + if string(output) != "foobar" { + t.Error(string(output)) + } +} + func grepFile(t *testing.T, path string, pattern string) { f, err := os.Open(path) if err != nil { diff --git a/docs/sources/commandline/command/run.rst b/docs/sources/commandline/command/run.rst index c119ce11e2..4529013b2e 100644 --- a/docs/sources/commandline/command/run.rst +++ b/docs/sources/commandline/command/run.rst @@ -26,3 +26,4 @@ -v=[]: Creates a new volume and mounts it at the specified path. -volumes-from="": Mount all volumes from the given container. -b=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro] + -entrypoint="": Overwrite the default entrypoint set by the image. diff --git a/docs/sources/use/builder.rst b/docs/sources/use/builder.rst index 0978bd7d4c..6a12beadf8 100644 --- a/docs/sources/use/builder.rst +++ b/docs/sources/use/builder.rst @@ -153,6 +153,13 @@ of `` will be written at ``. If `` doesn't exist, it is created along with all missing directories in its path. All new files and directories are created with mode 0700, uid and gid 0. +2.8 ENTRYPOINT +------------- + + ``ENTRYPOINT /bin/echo`` + +The `ENTRYPOINT` instruction adds an entry command that will not be overwritten when arguments are passed to docker run, unlike the behavior of `CMD`. This allows arguments to be passed to the entrypoint. i.e. `docker run -d` will pass the "-d" argument to the entrypoint. + 3. Dockerfile Examples ====================== diff --git a/utils.go b/utils.go index 5a9d02c490..22613e9f49 100644 --- a/utils.go +++ b/utils.go @@ -44,7 +44,11 @@ func CompareConfig(a, b *Config) bool { return false } } - + for i := 0; i < len(a.Entrypoint); i++ { + if a.Entrypoint[i] != b.Entrypoint[i] { + return false + } + } return true } @@ -85,4 +89,7 @@ func MergeConfig(userConf, imageConf *Config) { if userConf.Dns == nil || len(userConf.Dns) == 0 { userConf.Dns = imageConf.Dns } + if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 { + userConf.Entrypoint = imageConf.Entrypoint + } }