Decode container configurations into typed structures.
Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
parent
002afbbe77
commit
767df67e31
|
@ -33,6 +33,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/streamformatter"
|
"github.com/docker/docker/pkg/streamformatter"
|
||||||
"github.com/docker/docker/pkg/version"
|
"github.com/docker/docker/pkg/version"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -811,14 +812,14 @@ func postContainersCreate(eng *engine.Engine, version version.Version, w http.Re
|
||||||
var (
|
var (
|
||||||
warnings []string
|
warnings []string
|
||||||
name = r.Form.Get("name")
|
name = r.Form.Get("name")
|
||||||
env = new(engine.Env)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := env.Decode(r.Body); err != nil {
|
config, hostConfig, err := runconfig.DecodeContainerConfig(r.Body)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
containerId, warnings, err := getDaemon(eng).ContainerCreate(name, env)
|
containerId, warnings, err := getDaemon(eng).ContainerCreate(name, config, hostConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -917,10 +918,6 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res
|
||||||
if vars == nil {
|
if vars == nil {
|
||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
var (
|
|
||||||
name = vars["name"]
|
|
||||||
env = new(engine.Env)
|
|
||||||
)
|
|
||||||
|
|
||||||
// If contentLength is -1, we can assumed chunked encoding
|
// If contentLength is -1, we can assumed chunked encoding
|
||||||
// or more technically that the length is unknown
|
// or more technically that the length is unknown
|
||||||
|
@ -928,17 +925,21 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res
|
||||||
// net/http otherwise seems to swallow any headers related to chunked encoding
|
// net/http otherwise seems to swallow any headers related to chunked encoding
|
||||||
// including r.TransferEncoding
|
// including r.TransferEncoding
|
||||||
// allow a nil body for backwards compatibility
|
// allow a nil body for backwards compatibility
|
||||||
|
var hostConfig *runconfig.HostConfig
|
||||||
if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
|
if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
|
||||||
if err := checkForJson(r); err != nil {
|
if err := checkForJson(r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := env.Decode(r.Body); err != nil {
|
c, err := runconfig.DecodeHostConfig(r.Body)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostConfig = c
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := getDaemon(eng).ContainerStart(name, env); err != nil {
|
if err := getDaemon(eng).ContainerStart(vars["name"], hostConfig); err != nil {
|
||||||
if err.Error() == "Container already started" {
|
if err.Error() == "Container already started" {
|
||||||
w.WriteHeader(http.StatusNotModified)
|
w.WriteHeader(http.StatusNotModified)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -262,7 +262,7 @@ func run(b *Builder, args []string, attributes map[string]bool, original string)
|
||||||
b.Config.Cmd = config.Cmd
|
b.Config.Cmd = config.Cmd
|
||||||
runconfig.Merge(b.Config, config)
|
runconfig.Merge(b.Config, config)
|
||||||
|
|
||||||
defer func(cmd []string) { b.Config.Cmd = cmd }(cmd)
|
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
|
||||||
|
|
||||||
logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)
|
logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)
|
||||||
|
|
||||||
|
@ -301,13 +301,15 @@ func run(b *Builder, args []string, attributes map[string]bool, original string)
|
||||||
// Argument handling is the same as RUN.
|
// Argument handling is the same as RUN.
|
||||||
//
|
//
|
||||||
func cmd(b *Builder, args []string, attributes map[string]bool, original string) error {
|
func cmd(b *Builder, args []string, attributes map[string]bool, original string) error {
|
||||||
b.Config.Cmd = handleJsonArgs(args, attributes)
|
cmdSlice := handleJsonArgs(args, attributes)
|
||||||
|
|
||||||
if !attributes["json"] {
|
if !attributes["json"] {
|
||||||
b.Config.Cmd = append([]string{"/bin/sh", "-c"}, b.Config.Cmd...)
|
cmdSlice = append([]string{"/bin/sh", "-c"}, cmdSlice...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", b.Config.Cmd)); err != nil {
|
b.Config.Cmd = runconfig.NewCommand(cmdSlice...)
|
||||||
|
|
||||||
|
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,13 +334,13 @@ func entrypoint(b *Builder, args []string, attributes map[string]bool, original
|
||||||
switch {
|
switch {
|
||||||
case attributes["json"]:
|
case attributes["json"]:
|
||||||
// ENTRYPOINT ["echo", "hi"]
|
// ENTRYPOINT ["echo", "hi"]
|
||||||
b.Config.Entrypoint = parsed
|
b.Config.Entrypoint = runconfig.NewEntrypoint(parsed...)
|
||||||
case len(parsed) == 0:
|
case len(parsed) == 0:
|
||||||
// ENTRYPOINT []
|
// ENTRYPOINT []
|
||||||
b.Config.Entrypoint = nil
|
b.Config.Entrypoint = nil
|
||||||
default:
|
default:
|
||||||
// ENTRYPOINT echo hi
|
// ENTRYPOINT echo hi
|
||||||
b.Config.Entrypoint = []string{"/bin/sh", "-c", parsed[0]}
|
b.Config.Entrypoint = runconfig.NewEntrypoint("/bin/sh", "-c", parsed[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// when setting the entrypoint if a CMD was not explicitly set then
|
// when setting the entrypoint if a CMD was not explicitly set then
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (b *Builder) readContext(context io.Reader) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) commit(id string, autoCmd []string, comment string) error {
|
func (b *Builder) commit(id string, autoCmd *runconfig.Command, comment string) error {
|
||||||
if b.disableCommit {
|
if b.disableCommit {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,8 @@ func (b *Builder) commit(id string, autoCmd []string, comment string) error {
|
||||||
b.Config.Image = b.image
|
b.Config.Image = b.image
|
||||||
if id == "" {
|
if id == "" {
|
||||||
cmd := b.Config.Cmd
|
cmd := b.Config.Cmd
|
||||||
b.Config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + comment}
|
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment)
|
||||||
defer func(cmd []string) { b.Config.Cmd = cmd }(cmd)
|
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
|
||||||
|
|
||||||
hit, err := b.probeCache()
|
hit, err := b.probeCache()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -182,8 +182,8 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowDecomp
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := b.Config.Cmd
|
cmd := b.Config.Cmd
|
||||||
b.Config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest)}
|
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
|
||||||
defer func(cmd []string) { b.Config.Cmd = cmd }(cmd)
|
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
|
||||||
|
|
||||||
hit, err := b.probeCache()
|
hit, err := b.probeCache()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -559,12 +559,13 @@ func (b *Builder) create() (*daemon.Container, error) {
|
||||||
b.TmpContainers[c.ID] = struct{}{}
|
b.TmpContainers[c.ID] = struct{}{}
|
||||||
fmt.Fprintf(b.OutStream, " ---> Running in %s\n", stringid.TruncateID(c.ID))
|
fmt.Fprintf(b.OutStream, " ---> Running in %s\n", stringid.TruncateID(c.ID))
|
||||||
|
|
||||||
if len(config.Cmd) > 0 {
|
if config.Cmd.Len() > 0 {
|
||||||
// override the entry point that may have been picked up from the base image
|
// override the entry point that may have been picked up from the base image
|
||||||
c.Path = config.Cmd[0]
|
s := config.Cmd.Slice()
|
||||||
c.Args = config.Cmd[1:]
|
c.Path = s[0]
|
||||||
|
c.Args = s[1:]
|
||||||
} else {
|
} else {
|
||||||
config.Cmd = []string{}
|
config.Cmd = runconfig.NewCommand()
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/engine"
|
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
|
@ -12,13 +11,10 @@ import (
|
||||||
"github.com/docker/libcontainer/label"
|
"github.com/docker/libcontainer/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (daemon *Daemon) ContainerCreate(name string, env *engine.Env) (string, []string, error) {
|
func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig) (string, []string, error) {
|
||||||
var warnings []string
|
var warnings []string
|
||||||
|
|
||||||
config := runconfig.ContainerConfigFromJob(env)
|
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
||||||
hostConfig := runconfig.ContainerHostConfigFromJob(env)
|
|
||||||
|
|
||||||
if len(hostConfig.LxcConf) > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
|
||||||
return "", warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
return "", warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
||||||
}
|
}
|
||||||
if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
|
if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
|
||||||
|
|
|
@ -119,12 +119,8 @@ type Daemon struct {
|
||||||
func (daemon *Daemon) Install(eng *engine.Engine) error {
|
func (daemon *Daemon) Install(eng *engine.Engine) error {
|
||||||
for name, method := range map[string]engine.Handler{
|
for name, method := range map[string]engine.Handler{
|
||||||
"container_inspect": daemon.ContainerInspect,
|
"container_inspect": daemon.ContainerInspect,
|
||||||
"container_stats": daemon.ContainerStats,
|
|
||||||
"export": daemon.ContainerExport,
|
|
||||||
"info": daemon.CmdInfo,
|
"info": daemon.CmdInfo,
|
||||||
"restart": daemon.ContainerRestart,
|
"restart": daemon.ContainerRestart,
|
||||||
"stop": daemon.ContainerStop,
|
|
||||||
"wait": daemon.ContainerWait,
|
|
||||||
"execCreate": daemon.ContainerExecCreate,
|
"execCreate": daemon.ContainerExecCreate,
|
||||||
"execStart": daemon.ContainerExecStart,
|
"execStart": daemon.ContainerExecStart,
|
||||||
} {
|
} {
|
||||||
|
@ -485,7 +481,7 @@ func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
|
if config.Entrypoint.Len() == 0 && config.Cmd.Len() == 0 {
|
||||||
return nil, fmt.Errorf("No command specified")
|
return nil, fmt.Errorf("No command specified")
|
||||||
}
|
}
|
||||||
return warnings, nil
|
return warnings, nil
|
||||||
|
@ -577,17 +573,20 @@ func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint, configCmd []string) (string, []string) {
|
func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *runconfig.Entrypoint, configCmd *runconfig.Command) (string, []string) {
|
||||||
var (
|
var (
|
||||||
entrypoint string
|
entrypoint string
|
||||||
args []string
|
args []string
|
||||||
)
|
)
|
||||||
if len(configEntrypoint) != 0 {
|
|
||||||
entrypoint = configEntrypoint[0]
|
cmdSlice := configCmd.Slice()
|
||||||
args = append(configEntrypoint[1:], configCmd...)
|
if configEntrypoint.Len() != 0 {
|
||||||
|
eSlice := configEntrypoint.Slice()
|
||||||
|
entrypoint = eSlice[0]
|
||||||
|
args = append(eSlice[1:], cmdSlice...)
|
||||||
} else {
|
} else {
|
||||||
entrypoint = configCmd[0]
|
entrypoint = cmdSlice[0]
|
||||||
args = configCmd[1:]
|
args = cmdSlice[1:]
|
||||||
}
|
}
|
||||||
return entrypoint, args
|
return entrypoint, args
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,8 @@ func (d *Daemon) ContainerExecCreate(job *engine.Job) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
entrypoint, args := d.getEntrypointAndArgs(nil, config.Cmd)
|
cmd := runconfig.NewCommand(config.Cmd...)
|
||||||
|
entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd)
|
||||||
|
|
||||||
processConfig := execdriver.ProcessConfig{
|
processConfig := execdriver.ProcessConfig{
|
||||||
Tty: config.Tty,
|
Tty: config.Tty,
|
||||||
|
|
|
@ -3,11 +3,10 @@ package daemon
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/engine"
|
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (daemon *Daemon) ContainerStart(name string, env *engine.Env) error {
|
func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConfig) error {
|
||||||
container, err := daemon.Get(name)
|
container, err := daemon.Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -21,15 +20,14 @@ func (daemon *Daemon) ContainerStart(name string, env *engine.Env) error {
|
||||||
return fmt.Errorf("Container already started")
|
return fmt.Errorf("Container already started")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no environment was set, then no hostconfig was passed.
|
|
||||||
// This is kept for backward compatibility - hostconfig should be passed when
|
// This is kept for backward compatibility - hostconfig should be passed when
|
||||||
// creating a container, not during start.
|
// creating a container, not during start.
|
||||||
if len(env.Map()) > 0 {
|
if hostConfig != nil {
|
||||||
hostConfig := runconfig.ContainerHostConfigFromJob(env)
|
|
||||||
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.Start(); err != nil {
|
if err := container.Start(); err != nil {
|
||||||
container.LogEvent("die")
|
container.LogEvent("die")
|
||||||
return fmt.Errorf("Cannot start container %s: %s", name, err)
|
return fmt.Errorf("Cannot start container %s: %s", name, err)
|
||||||
|
|
|
@ -42,7 +42,8 @@ func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig) ([]string, error)
|
||||||
|
|
||||||
// merge in the lxc conf options into the generic config map
|
// merge in the lxc conf options into the generic config map
|
||||||
if lxcConf := hostConfig.LxcConf; lxcConf != nil {
|
if lxcConf := hostConfig.LxcConf; lxcConf != nil {
|
||||||
for _, pair := range lxcConf {
|
lxSlice := lxcConf.Slice()
|
||||||
|
for _, pair := range lxSlice {
|
||||||
// because lxc conf gets the driver name lxc.XXXX we need to trim it off
|
// because lxc conf gets the driver name lxc.XXXX we need to trim it off
|
||||||
// and let the lxc driver add it back later if needed
|
// and let the lxc driver add it back later if needed
|
||||||
if !strings.Contains(pair.Key, ".") {
|
if !strings.Contains(pair.Key, ".") {
|
||||||
|
|
|
@ -7,10 +7,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMergeLxcConfig(t *testing.T) {
|
func TestMergeLxcConfig(t *testing.T) {
|
||||||
|
kv := []runconfig.KeyValuePair{
|
||||||
|
{"lxc.cgroups.cpuset", "1,2"},
|
||||||
|
}
|
||||||
hostConfig := &runconfig.HostConfig{
|
hostConfig := &runconfig.HostConfig{
|
||||||
LxcConf: []runconfig.KeyValuePair{
|
LxcConf: runconfig.NewLxcConfig(kv),
|
||||||
{Key: "lxc.cgroups.cpuset", Value: "1,2"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := mergeLxcConfIntoOptions(hostConfig)
|
out, err := mergeLxcConfIntoOptions(hostConfig)
|
||||||
|
|
|
@ -31,7 +31,7 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||||
history = append(history, &types.ImageHistory{
|
history = append(history, &types.ImageHistory{
|
||||||
ID: img.ID,
|
ID: img.ID,
|
||||||
Created: img.Created.Unix(),
|
Created: img.Created.Unix(),
|
||||||
CreatedBy: strings.Join(img.ContainerConfig.Cmd, " "),
|
CreatedBy: strings.Join(img.ContainerConfig.Cmd.Slice(), " "),
|
||||||
Tags: lookupMap[img.ID],
|
Tags: lookupMap[img.ID],
|
||||||
Size: img.Size,
|
Size: img.Size,
|
||||||
Comment: img.Comment,
|
Comment: img.Comment,
|
||||||
|
|
|
@ -91,7 +91,7 @@ func TestGetContainersTop(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/sh", "-c", "cat"},
|
Cmd: runconfig.NewCommand("/bin/sh", "-c", "cat"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -168,7 +168,7 @@ func TestPostCommit(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"touch", "/test"},
|
Cmd: runconfig.NewCommand("touch", "/test"),
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
)
|
)
|
||||||
|
@ -201,9 +201,8 @@ func TestPostContainersCreate(t *testing.T) {
|
||||||
defer mkDaemonFromEngine(eng, t).Nuke()
|
defer mkDaemonFromEngine(eng, t).Nuke()
|
||||||
|
|
||||||
configJSON, err := json.Marshal(&runconfig.Config{
|
configJSON, err := json.Marshal(&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Memory: 33554432,
|
Cmd: runconfig.NewCommand("touch", "/test"),
|
||||||
Cmd: []string{"touch", "/test"},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -242,9 +241,8 @@ func TestPostJsonVerify(t *testing.T) {
|
||||||
defer mkDaemonFromEngine(eng, t).Nuke()
|
defer mkDaemonFromEngine(eng, t).Nuke()
|
||||||
|
|
||||||
configJSON, err := json.Marshal(&runconfig.Config{
|
configJSON, err := json.Marshal(&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Memory: 33554432,
|
Cmd: runconfig.NewCommand("touch", "/test"),
|
||||||
Cmd: []string{"touch", "/test"},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -330,8 +328,8 @@ func TestPostCreateNull(t *testing.T) {
|
||||||
containerAssertExists(eng, containerID, t)
|
containerAssertExists(eng, containerID, t)
|
||||||
|
|
||||||
c, _ := daemon.Get(containerID)
|
c, _ := daemon.Get(containerID)
|
||||||
if c.Config.Cpuset != "" {
|
if c.HostConfig().CpusetCpus != "" {
|
||||||
t.Fatalf("Cpuset should have been empty - instead its:" + c.Config.Cpuset)
|
t.Fatalf("Cpuset should have been empty - instead its:" + c.HostConfig().CpusetCpus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +340,7 @@ func TestPostContainersKill(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/cat"},
|
Cmd: runconfig.NewCommand("/bin/cat"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -379,7 +377,7 @@ func TestPostContainersRestart(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/top"},
|
Cmd: runconfig.NewCommand("/bin/top"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -423,7 +421,7 @@ func TestPostContainersStart(t *testing.T) {
|
||||||
eng,
|
eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/cat"},
|
Cmd: runconfig.NewCommand("/bin/cat"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -473,7 +471,7 @@ func TestPostContainersStop(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/top"},
|
Cmd: runconfig.NewCommand("/bin/top"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -525,7 +523,7 @@ func TestPostContainersWait(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/sleep", "1"},
|
Cmd: runconfig.NewCommand("/bin/sleep", "1"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -561,7 +559,7 @@ func TestPostContainersAttach(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/cat"},
|
Cmd: runconfig.NewCommand("/bin/cat"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -637,7 +635,7 @@ func TestPostContainersAttachStderr(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
|
Cmd: runconfig.NewCommand("/bin/sh", "-c", "/bin/cat >&2"),
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
@ -818,7 +816,7 @@ func TestPostContainersCopy(t *testing.T) {
|
||||||
containerID := createTestContainer(eng,
|
containerID := createTestContainer(eng,
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: unitTestImageID,
|
Image: unitTestImageID,
|
||||||
Cmd: []string{"touch", "/test.txt"},
|
Cmd: runconfig.NewCommand("touch", "/test.txt"),
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,7 @@ func TestRestartStdin(t *testing.T) {
|
||||||
defer nuke(daemon)
|
defer nuke(daemon)
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"cat"},
|
Cmd: runconfig.NewCommand("cat"),
|
||||||
|
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
|
@ -79,7 +79,7 @@ func TestStdin(t *testing.T) {
|
||||||
defer nuke(daemon)
|
defer nuke(daemon)
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"cat"},
|
Cmd: runconfig.NewCommand("cat"),
|
||||||
|
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
|
@ -119,7 +119,7 @@ func TestTty(t *testing.T) {
|
||||||
defer nuke(daemon)
|
defer nuke(daemon)
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"cat"},
|
Cmd: runconfig.NewCommand("cat"),
|
||||||
|
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
},
|
},
|
||||||
|
@ -160,7 +160,7 @@ func BenchmarkRunSequential(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"echo", "-n", "foo"},
|
Cmd: runconfig.NewCommand("echo", "-n", "foo"),
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
"",
|
"",
|
||||||
|
@ -194,7 +194,7 @@ func BenchmarkRunParallel(b *testing.B) {
|
||||||
go func(i int, complete chan error) {
|
go func(i int, complete chan error) {
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"echo", "-n", "foo"},
|
Cmd: runconfig.NewCommand("echo", "-n", "foo"),
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -255,7 +255,7 @@ func TestDaemonCreate(t *testing.T) {
|
||||||
|
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"ls", "-al"},
|
Cmd: runconfig.NewCommand("ls", "-al"),
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
"",
|
"",
|
||||||
|
@ -296,15 +296,16 @@ func TestDaemonCreate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that conflict error displays correct details
|
// Test that conflict error displays correct details
|
||||||
|
cmd := runconfig.NewCommand("ls", "-al")
|
||||||
testContainer, _, _ := daemon.Create(
|
testContainer, _, _ := daemon.Create(
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"ls", "-al"},
|
Cmd: cmd,
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
"conflictname",
|
"conflictname",
|
||||||
)
|
)
|
||||||
if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: []string{"ls", "-al"}}, &runconfig.HostConfig{}, testContainer.Name); err == nil || !strings.Contains(err.Error(), stringid.TruncateID(testContainer.ID)) {
|
if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: cmd}, &runconfig.HostConfig{}, testContainer.Name); err == nil || !strings.Contains(err.Error(), stringid.TruncateID(testContainer.ID)) {
|
||||||
t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %v", err)
|
t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +317,7 @@ func TestDaemonCreate(t *testing.T) {
|
||||||
if _, _, err := daemon.Create(
|
if _, _, err := daemon.Create(
|
||||||
&runconfig.Config{
|
&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{},
|
Cmd: runconfig.NewCommand(),
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
"",
|
"",
|
||||||
|
@ -326,7 +327,7 @@ func TestDaemonCreate(t *testing.T) {
|
||||||
|
|
||||||
config := &runconfig.Config{
|
config := &runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"/bin/ls"},
|
Cmd: runconfig.NewCommand("/bin/ls"),
|
||||||
PortSpecs: []string{"80"},
|
PortSpecs: []string{"80"},
|
||||||
}
|
}
|
||||||
container, _, err = daemon.Create(config, &runconfig.HostConfig{}, "")
|
container, _, err = daemon.Create(config, &runconfig.HostConfig{}, "")
|
||||||
|
@ -339,7 +340,7 @@ func TestDaemonCreate(t *testing.T) {
|
||||||
// test expose 80:8000
|
// test expose 80:8000
|
||||||
container, warnings, err := daemon.Create(&runconfig.Config{
|
container, warnings, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"ls", "-al"},
|
Cmd: runconfig.NewCommand("ls", "-al"),
|
||||||
PortSpecs: []string{"80:8000"},
|
PortSpecs: []string{"80:8000"},
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
|
@ -359,7 +360,7 @@ func TestDestroy(t *testing.T) {
|
||||||
|
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"ls", "-al"},
|
Cmd: runconfig.NewCommand("ls", "-al"),
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
"")
|
"")
|
||||||
|
@ -451,13 +452,14 @@ func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daem
|
||||||
p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto))
|
p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto))
|
||||||
ep[p] = struct{}{}
|
ep[p] = struct{}{}
|
||||||
|
|
||||||
env := new(engine.Env)
|
c := &runconfig.Config{
|
||||||
env.Set("Image", unitTestImageID)
|
Image: unitTestImageID,
|
||||||
env.SetList("Cmd", []string{"sh", "-c", cmd})
|
Cmd: runconfig.NewCommand("sh", "-c", cmd),
|
||||||
env.SetList("PortSpecs", []string{fmt.Sprintf("%s/%s", strPort, proto)})
|
PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},
|
||||||
env.SetJson("ExposedPorts", ep)
|
ExposedPorts: ep,
|
||||||
|
}
|
||||||
|
|
||||||
id, _, err = daemon.ContainerCreate(unitTestImageID, env)
|
id, _, err = daemon.ContainerCreate(unitTestImageID, c, &runconfig.HostConfig{})
|
||||||
// FIXME: this relies on the undocumented behavior of daemon.Create
|
// FIXME: this relies on the undocumented behavior of daemon.Create
|
||||||
// which will return a nil error AND container if the exposed ports
|
// which will return a nil error AND container if the exposed ports
|
||||||
// are invalid. That behavior should be fixed!
|
// are invalid. That behavior should be fixed!
|
||||||
|
@ -468,16 +470,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daem
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
portBindings := make(map[nat.Port][]nat.PortBinding)
|
if err := daemon.ContainerStart(id, &runconfig.HostConfig{}); err != nil {
|
||||||
portBindings[p] = []nat.PortBinding{
|
|
||||||
{},
|
|
||||||
}
|
|
||||||
|
|
||||||
env := new(engine.Env)
|
|
||||||
if err := env.SetJson("PortsBindings", portBindings); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := daemon.ContainerStart(id, env); err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,12 +721,7 @@ func TestContainerNameValidation(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
env := new(engine.Env)
|
containerId, _, err := daemon.ContainerCreate(test.Name, config, &runconfig.HostConfig{})
|
||||||
if err := env.Import(config); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
containerId, _, err := daemon.ContainerCreate(test.Name, env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !test.Valid {
|
if !test.Valid {
|
||||||
continue
|
continue
|
||||||
|
@ -872,7 +860,7 @@ func TestDestroyWithInitLayer(t *testing.T) {
|
||||||
|
|
||||||
container, _, err := daemon.Create(&runconfig.Config{
|
container, _, err := daemon.Create(&runconfig.Config{
|
||||||
Image: GetTestImage(daemon).ID,
|
Image: GetTestImage(daemon).ID,
|
||||||
Cmd: []string{"ls", "-al"},
|
Cmd: runconfig.NewCommand("ls", "-al"),
|
||||||
},
|
},
|
||||||
&runconfig.HostConfig{},
|
&runconfig.HostConfig{},
|
||||||
"")
|
"")
|
||||||
|
|
|
@ -44,11 +44,7 @@ func mkDaemon(f Fataler) *daemon.Daemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler, name string) (shortId string) {
|
func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler, name string) (shortId string) {
|
||||||
env := new(engine.Env)
|
containerId, _, err := getDaemon(eng).ContainerCreate(name, config, &runconfig.HostConfig{})
|
||||||
if err := env.Import(config); err != nil {
|
|
||||||
f.Fatal(err)
|
|
||||||
}
|
|
||||||
containerId, _, err := getDaemon(eng).ContainerCreate(name, env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.Fatal(err)
|
f.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -60,8 +56,7 @@ func createTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler
|
||||||
}
|
}
|
||||||
|
|
||||||
func startContainer(eng *engine.Engine, id string, t Fataler) {
|
func startContainer(eng *engine.Engine, id string, t Fataler) {
|
||||||
env := new(engine.Env)
|
if err := getDaemon(eng).ContainerStart(id, &runconfig.HostConfig{}); err != nil {
|
||||||
if err := getDaemon(eng).ContainerStart(id, env); err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,25 +10,25 @@ func Compare(a, b *Config) bool {
|
||||||
if a.AttachStdout != b.AttachStdout ||
|
if a.AttachStdout != b.AttachStdout ||
|
||||||
a.AttachStderr != b.AttachStderr ||
|
a.AttachStderr != b.AttachStderr ||
|
||||||
a.User != b.User ||
|
a.User != b.User ||
|
||||||
a.Memory != b.Memory ||
|
|
||||||
a.MemorySwap != b.MemorySwap ||
|
|
||||||
a.CpuShares != b.CpuShares ||
|
|
||||||
a.OpenStdin != b.OpenStdin ||
|
a.OpenStdin != b.OpenStdin ||
|
||||||
a.Tty != b.Tty {
|
a.Tty != b.Tty {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(a.Cmd) != len(b.Cmd) ||
|
|
||||||
|
if a.Cmd.Len() != b.Cmd.Len() ||
|
||||||
len(a.Env) != len(b.Env) ||
|
len(a.Env) != len(b.Env) ||
|
||||||
len(a.Labels) != len(b.Labels) ||
|
len(a.Labels) != len(b.Labels) ||
|
||||||
len(a.PortSpecs) != len(b.PortSpecs) ||
|
len(a.PortSpecs) != len(b.PortSpecs) ||
|
||||||
len(a.ExposedPorts) != len(b.ExposedPorts) ||
|
len(a.ExposedPorts) != len(b.ExposedPorts) ||
|
||||||
len(a.Entrypoint) != len(b.Entrypoint) ||
|
a.Entrypoint.Len() != b.Entrypoint.Len() ||
|
||||||
len(a.Volumes) != len(b.Volumes) {
|
len(a.Volumes) != len(b.Volumes) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(a.Cmd); i++ {
|
aCmd := a.Cmd.Slice()
|
||||||
if a.Cmd[i] != b.Cmd[i] {
|
bCmd := b.Cmd.Slice()
|
||||||
|
for i := 0; i < len(aCmd); i++ {
|
||||||
|
if aCmd[i] != bCmd[i] {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,11 @@ func Compare(a, b *Config) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < len(a.Entrypoint); i++ {
|
|
||||||
if a.Entrypoint[i] != b.Entrypoint[i] {
|
aEntrypoint := a.Entrypoint.Slice()
|
||||||
|
bEntrypoint := b.Entrypoint.Slice()
|
||||||
|
for i := 0; i < len(aEntrypoint); i++ {
|
||||||
|
if aEntrypoint[i] != bEntrypoint[i] {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,103 @@
|
||||||
package runconfig
|
package runconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/docker/engine"
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/docker/docker/nat"
|
"github.com/docker/docker/nat"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Entrypoint encapsulates the container entrypoint.
|
||||||
|
// It might be represented as a string or an array of strings.
|
||||||
|
// We need to override the json decoder to accept both options.
|
||||||
|
// The JSON decoder will fail if the api sends an string and
|
||||||
|
// we try to decode it into an array of string.
|
||||||
|
type Entrypoint struct {
|
||||||
|
parts []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entrypoint) MarshalJSON() ([]byte, error) {
|
||||||
|
if e == nil {
|
||||||
|
return []byte{}, nil
|
||||||
|
}
|
||||||
|
return json.Marshal(e.Slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decoded the entrypoint whether it's a string or an array of strings.
|
||||||
|
func (e *Entrypoint) UnmarshalJSON(b []byte) error {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := make([]string, 0, 1)
|
||||||
|
if err := json.Unmarshal(b, &p); err != nil {
|
||||||
|
p = append(p, string(b))
|
||||||
|
}
|
||||||
|
e.parts = p
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entrypoint) Len() int {
|
||||||
|
if e == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(e.parts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entrypoint) Slice() []string {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e.parts
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntrypoint(parts ...string) *Entrypoint {
|
||||||
|
return &Entrypoint{parts}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
parts []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Command) MarshalJSON() ([]byte, error) {
|
||||||
|
if e == nil {
|
||||||
|
return []byte{}, nil
|
||||||
|
}
|
||||||
|
return json.Marshal(e.Slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decoded the entrypoint whether it's a string or an array of strings.
|
||||||
|
func (e *Command) UnmarshalJSON(b []byte) error {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := make([]string, 0, 1)
|
||||||
|
if err := json.Unmarshal(b, &p); err != nil {
|
||||||
|
p = append(p, string(b))
|
||||||
|
}
|
||||||
|
e.parts = p
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Command) Len() int {
|
||||||
|
if e == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(e.parts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Command) Slice() []string {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e.parts
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCommand(parts ...string) *Command {
|
||||||
|
return &Command{parts}
|
||||||
|
}
|
||||||
|
|
||||||
// Note: the Config structure should hold only portable information about the container.
|
// Note: the Config structure should hold only portable information about the container.
|
||||||
// Here, "portable" means "independent from the host we are running on".
|
// Here, "portable" means "independent from the host we are running on".
|
||||||
// Non-portable information *should* appear in HostConfig.
|
// Non-portable information *should* appear in HostConfig.
|
||||||
|
@ -12,10 +105,6 @@ type Config struct {
|
||||||
Hostname string
|
Hostname string
|
||||||
Domainname string
|
Domainname string
|
||||||
User string
|
User string
|
||||||
Memory int64 // FIXME: we keep it for backward compatibility, it has been moved to hostConfig.
|
|
||||||
MemorySwap int64 // FIXME: it has been moved to hostConfig.
|
|
||||||
CpuShares int64 // FIXME: it has been moved to hostConfig.
|
|
||||||
Cpuset string // FIXME: it has been moved to hostConfig and renamed to CpusetCpus.
|
|
||||||
AttachStdin bool
|
AttachStdin bool
|
||||||
AttachStdout bool
|
AttachStdout bool
|
||||||
AttachStderr bool
|
AttachStderr bool
|
||||||
|
@ -25,53 +114,37 @@ type Config struct {
|
||||||
OpenStdin bool // Open stdin
|
OpenStdin bool // Open stdin
|
||||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||||
Env []string
|
Env []string
|
||||||
Cmd []string
|
Cmd *Command
|
||||||
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
||||||
Volumes map[string]struct{}
|
Volumes map[string]struct{}
|
||||||
WorkingDir string
|
WorkingDir string
|
||||||
Entrypoint []string
|
Entrypoint *Entrypoint
|
||||||
NetworkDisabled bool
|
NetworkDisabled bool
|
||||||
MacAddress string
|
MacAddress string
|
||||||
OnBuild []string
|
OnBuild []string
|
||||||
Labels map[string]string
|
Labels map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ContainerConfigFromJob(env *engine.Env) *Config {
|
type ContainerConfigWrapper struct {
|
||||||
config := &Config{
|
*Config
|
||||||
Hostname: env.Get("Hostname"),
|
*hostConfigWrapper
|
||||||
Domainname: env.Get("Domainname"),
|
}
|
||||||
User: env.Get("User"),
|
|
||||||
Memory: env.GetInt64("Memory"),
|
func (c ContainerConfigWrapper) HostConfig() *HostConfig {
|
||||||
MemorySwap: env.GetInt64("MemorySwap"),
|
if c.hostConfigWrapper == nil {
|
||||||
CpuShares: env.GetInt64("CpuShares"),
|
return new(HostConfig)
|
||||||
Cpuset: env.Get("Cpuset"),
|
}
|
||||||
AttachStdin: env.GetBool("AttachStdin"),
|
|
||||||
AttachStdout: env.GetBool("AttachStdout"),
|
return c.hostConfigWrapper.GetHostConfig()
|
||||||
AttachStderr: env.GetBool("AttachStderr"),
|
}
|
||||||
Tty: env.GetBool("Tty"),
|
|
||||||
OpenStdin: env.GetBool("OpenStdin"),
|
func DecodeContainerConfig(src io.Reader) (*Config, *HostConfig, error) {
|
||||||
StdinOnce: env.GetBool("StdinOnce"),
|
decoder := json.NewDecoder(src)
|
||||||
Image: env.Get("Image"),
|
|
||||||
WorkingDir: env.Get("WorkingDir"),
|
var w ContainerConfigWrapper
|
||||||
NetworkDisabled: env.GetBool("NetworkDisabled"),
|
if err := decoder.Decode(&w); err != nil {
|
||||||
MacAddress: env.Get("MacAddress"),
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
env.GetJson("ExposedPorts", &config.ExposedPorts)
|
|
||||||
env.GetJson("Volumes", &config.Volumes)
|
return w.Config, w.HostConfig(), nil
|
||||||
if PortSpecs := env.GetList("PortSpecs"); PortSpecs != nil {
|
|
||||||
config.PortSpecs = PortSpecs
|
|
||||||
}
|
|
||||||
if Env := env.GetList("Env"); Env != nil {
|
|
||||||
config.Env = Env
|
|
||||||
}
|
|
||||||
if Cmd := env.GetList("Cmd"); Cmd != nil {
|
|
||||||
config.Cmd = Cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
env.GetJson("Labels", &config.Labels)
|
|
||||||
|
|
||||||
if Entrypoint := env.GetList("Entrypoint"); Entrypoint != nil {
|
|
||||||
config.Entrypoint = Entrypoint
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package runconfig
|
package runconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -260,5 +262,39 @@ func TestMerge(t *testing.T) {
|
||||||
t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs)
|
t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeContainerConfig(t *testing.T) {
|
||||||
|
fixtures := []struct {
|
||||||
|
file string
|
||||||
|
entrypoint *Entrypoint
|
||||||
|
}{
|
||||||
|
{"fixtures/container_config_1_14.json", NewEntrypoint()},
|
||||||
|
{"fixtures/container_config_1_17.json", NewEntrypoint("bash")},
|
||||||
|
{"fixtures/container_config_1_19.json", NewEntrypoint("bash")},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range fixtures {
|
||||||
|
b, err := ioutil.ReadFile(f.file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, h, err := DecodeContainerConfig(bytes.NewReader(b))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(fmt.Errorf("Error parsing %s: %v", f, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Image != "ubuntu" {
|
||||||
|
t.Fatalf("Expected ubuntu image, found %s\n", c.Image)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Entrypoint.Len() != f.entrypoint.Len() {
|
||||||
|
t.Fatalf("Expected %v, found %v\n", f.entrypoint, c.Entrypoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Memory != 1000 {
|
||||||
|
t.Fatalf("Expected memory to be 1000, found %d\n", h.Memory)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"Hostname":"",
|
||||||
|
"Domainname": "",
|
||||||
|
"User":"",
|
||||||
|
"Memory": 1000,
|
||||||
|
"MemorySwap":0,
|
||||||
|
"CpuShares": 512,
|
||||||
|
"Cpuset": "0,1",
|
||||||
|
"AttachStdin":false,
|
||||||
|
"AttachStdout":true,
|
||||||
|
"AttachStderr":true,
|
||||||
|
"PortSpecs":null,
|
||||||
|
"Tty":false,
|
||||||
|
"OpenStdin":false,
|
||||||
|
"StdinOnce":false,
|
||||||
|
"Env":null,
|
||||||
|
"Cmd":[
|
||||||
|
"bash"
|
||||||
|
],
|
||||||
|
"Image":"ubuntu",
|
||||||
|
"Volumes":{
|
||||||
|
"/tmp": {}
|
||||||
|
},
|
||||||
|
"WorkingDir":"",
|
||||||
|
"NetworkDisabled": false,
|
||||||
|
"ExposedPorts":{
|
||||||
|
"22/tcp": {}
|
||||||
|
},
|
||||||
|
"RestartPolicy": { "Name": "always" }
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"Hostname": "",
|
||||||
|
"Domainname": "",
|
||||||
|
"User": "",
|
||||||
|
"Memory": 1000,
|
||||||
|
"MemorySwap": 0,
|
||||||
|
"CpuShares": 512,
|
||||||
|
"Cpuset": "0,1",
|
||||||
|
"AttachStdin": false,
|
||||||
|
"AttachStdout": true,
|
||||||
|
"AttachStderr": true,
|
||||||
|
"Tty": false,
|
||||||
|
"OpenStdin": false,
|
||||||
|
"StdinOnce": false,
|
||||||
|
"Env": null,
|
||||||
|
"Cmd": [
|
||||||
|
"date"
|
||||||
|
],
|
||||||
|
"Entrypoint": "bash",
|
||||||
|
"Image": "ubuntu",
|
||||||
|
"Volumes": {
|
||||||
|
"/tmp": {}
|
||||||
|
},
|
||||||
|
"WorkingDir": "",
|
||||||
|
"NetworkDisabled": false,
|
||||||
|
"MacAddress": "12:34:56:78:9a:bc",
|
||||||
|
"ExposedPorts": {
|
||||||
|
"22/tcp": {}
|
||||||
|
},
|
||||||
|
"SecurityOpt": [""],
|
||||||
|
"HostConfig": {
|
||||||
|
"Binds": ["/tmp:/tmp"],
|
||||||
|
"Links": ["redis3:redis"],
|
||||||
|
"LxcConf": {"lxc.utsname":"docker"},
|
||||||
|
"PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
|
||||||
|
"PublishAllPorts": false,
|
||||||
|
"Privileged": false,
|
||||||
|
"ReadonlyRootfs": false,
|
||||||
|
"Dns": ["8.8.8.8"],
|
||||||
|
"DnsSearch": [""],
|
||||||
|
"ExtraHosts": null,
|
||||||
|
"VolumesFrom": ["parent", "other:ro"],
|
||||||
|
"CapAdd": ["NET_ADMIN"],
|
||||||
|
"CapDrop": ["MKNOD"],
|
||||||
|
"RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
|
||||||
|
"NetworkMode": "bridge",
|
||||||
|
"Devices": []
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"Hostname": "",
|
||||||
|
"Domainname": "",
|
||||||
|
"User": "",
|
||||||
|
"AttachStdin": false,
|
||||||
|
"AttachStdout": true,
|
||||||
|
"AttachStderr": true,
|
||||||
|
"Tty": false,
|
||||||
|
"OpenStdin": false,
|
||||||
|
"StdinOnce": false,
|
||||||
|
"Env": null,
|
||||||
|
"Cmd": [
|
||||||
|
"date"
|
||||||
|
],
|
||||||
|
"Entrypoint": "bash",
|
||||||
|
"Image": "ubuntu",
|
||||||
|
"Labels": {
|
||||||
|
"com.example.vendor": "Acme",
|
||||||
|
"com.example.license": "GPL",
|
||||||
|
"com.example.version": "1.0"
|
||||||
|
},
|
||||||
|
"Volumes": {
|
||||||
|
"/tmp": {}
|
||||||
|
},
|
||||||
|
"WorkingDir": "",
|
||||||
|
"NetworkDisabled": false,
|
||||||
|
"MacAddress": "12:34:56:78:9a:bc",
|
||||||
|
"ExposedPorts": {
|
||||||
|
"22/tcp": {}
|
||||||
|
},
|
||||||
|
"HostConfig": {
|
||||||
|
"Binds": ["/tmp:/tmp"],
|
||||||
|
"Links": ["redis3:redis"],
|
||||||
|
"LxcConf": {"lxc.utsname":"docker"},
|
||||||
|
"Memory": 1000,
|
||||||
|
"MemorySwap": 0,
|
||||||
|
"CpuShares": 512,
|
||||||
|
"CpusetCpus": "0,1",
|
||||||
|
"PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
|
||||||
|
"PublishAllPorts": false,
|
||||||
|
"Privileged": false,
|
||||||
|
"ReadonlyRootfs": false,
|
||||||
|
"Dns": ["8.8.8.8"],
|
||||||
|
"DnsSearch": [""],
|
||||||
|
"ExtraHosts": null,
|
||||||
|
"VolumesFrom": ["parent", "other:ro"],
|
||||||
|
"CapAdd": ["NET_ADMIN"],
|
||||||
|
"CapDrop": ["MKNOD"],
|
||||||
|
"RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
|
||||||
|
"NetworkMode": "bridge",
|
||||||
|
"Devices": [],
|
||||||
|
"Ulimits": [{}],
|
||||||
|
"LogConfig": { "Type": "json-file", "Config": {} },
|
||||||
|
"SecurityOpt": [""],
|
||||||
|
"CgroupParent": ""
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
package runconfig
|
package runconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/engine"
|
|
||||||
"github.com/docker/docker/nat"
|
"github.com/docker/docker/nat"
|
||||||
"github.com/docker/docker/pkg/ulimit"
|
"github.com/docker/docker/pkg/ulimit"
|
||||||
)
|
)
|
||||||
|
@ -108,10 +109,59 @@ type LogConfig struct {
|
||||||
Config map[string]string
|
Config map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LxcConfig struct {
|
||||||
|
values []KeyValuePair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LxcConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
if c == nil {
|
||||||
|
return []byte{}, nil
|
||||||
|
}
|
||||||
|
return json.Marshal(c.Slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LxcConfig) UnmarshalJSON(b []byte) error {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var kv []KeyValuePair
|
||||||
|
if err := json.Unmarshal(b, &kv); err != nil {
|
||||||
|
var h map[string]string
|
||||||
|
if err := json.Unmarshal(b, &h); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, v := range h {
|
||||||
|
kv = append(kv, KeyValuePair{k, v})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.values = kv
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LxcConfig) Len() int {
|
||||||
|
if c == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(c.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LxcConfig) Slice() []KeyValuePair {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.values
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLxcConfig(values []KeyValuePair) *LxcConfig {
|
||||||
|
return &LxcConfig{values}
|
||||||
|
}
|
||||||
|
|
||||||
type HostConfig struct {
|
type HostConfig struct {
|
||||||
Binds []string
|
Binds []string
|
||||||
ContainerIDFile string
|
ContainerIDFile string
|
||||||
LxcConf []KeyValuePair
|
LxcConf *LxcConfig
|
||||||
Memory int64 // Memory limit (in bytes)
|
Memory int64 // Memory limit (in bytes)
|
||||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
|
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
|
||||||
CpuShares int64 // CPU shares (relative weight vs. other containers)
|
CpuShares int64 // CPU shares (relative weight vs. other containers)
|
||||||
|
@ -138,96 +188,55 @@ type HostConfig struct {
|
||||||
CgroupParent string // Parent cgroup.
|
CgroupParent string // Parent cgroup.
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used by the create command when you want to set both the
|
func MergeConfigs(config *Config, hostConfig *HostConfig) *ContainerConfigWrapper {
|
||||||
// Config and the HostConfig in the same call
|
return &ContainerConfigWrapper{
|
||||||
type ConfigAndHostConfig struct {
|
config,
|
||||||
Config
|
&hostConfigWrapper{InnerHostConfig: hostConfig},
|
||||||
HostConfig HostConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func MergeConfigs(config *Config, hostConfig *HostConfig) *ConfigAndHostConfig {
|
|
||||||
return &ConfigAndHostConfig{
|
|
||||||
*config,
|
|
||||||
*hostConfig,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ContainerHostConfigFromJob(env *engine.Env) *HostConfig {
|
type hostConfigWrapper struct {
|
||||||
if env.Exists("HostConfig") {
|
InnerHostConfig *HostConfig `json:"HostConfig,omitempty"`
|
||||||
hostConfig := HostConfig{}
|
Cpuset string `json:",omitempty"` // Deprecated. Exported for backwards compatibility.
|
||||||
env.GetJson("HostConfig", &hostConfig)
|
|
||||||
|
|
||||||
// FIXME: These are for backward compatibility, if people use these
|
*HostConfig // Deprecated. Exported to read attrubutes from json that are not in the inner host config structure.
|
||||||
// options with `HostConfig`, we should still make them workable.
|
}
|
||||||
if env.Exists("Memory") && hostConfig.Memory == 0 {
|
|
||||||
hostConfig.Memory = env.GetInt64("Memory")
|
func (w hostConfigWrapper) GetHostConfig() *HostConfig {
|
||||||
}
|
hc := w.HostConfig
|
||||||
if env.Exists("MemorySwap") && hostConfig.MemorySwap == 0 {
|
|
||||||
hostConfig.MemorySwap = env.GetInt64("MemorySwap")
|
if hc == nil && w.InnerHostConfig != nil {
|
||||||
}
|
hc = w.InnerHostConfig
|
||||||
if env.Exists("CpuShares") && hostConfig.CpuShares == 0 {
|
} else if w.InnerHostConfig != nil {
|
||||||
hostConfig.CpuShares = env.GetInt64("CpuShares")
|
if hc.Memory != 0 && w.InnerHostConfig.Memory == 0 {
|
||||||
}
|
w.InnerHostConfig.Memory = hc.Memory
|
||||||
if env.Exists("Cpuset") && hostConfig.CpusetCpus == "" {
|
}
|
||||||
hostConfig.CpusetCpus = env.Get("Cpuset")
|
if hc.MemorySwap != 0 && w.InnerHostConfig.MemorySwap == 0 {
|
||||||
}
|
w.InnerHostConfig.MemorySwap = hc.MemorySwap
|
||||||
|
}
|
||||||
return &hostConfig
|
if hc.CpuShares != 0 && w.InnerHostConfig.CpuShares == 0 {
|
||||||
}
|
w.InnerHostConfig.CpuShares = hc.CpuShares
|
||||||
|
}
|
||||||
hostConfig := &HostConfig{
|
|
||||||
ContainerIDFile: env.Get("ContainerIDFile"),
|
hc = w.InnerHostConfig
|
||||||
Memory: env.GetInt64("Memory"),
|
}
|
||||||
MemorySwap: env.GetInt64("MemorySwap"),
|
|
||||||
CpuShares: env.GetInt64("CpuShares"),
|
if hc != nil && w.Cpuset != "" && hc.CpusetCpus == "" {
|
||||||
CpusetCpus: env.Get("CpusetCpus"),
|
hc.CpusetCpus = w.Cpuset
|
||||||
Privileged: env.GetBool("Privileged"),
|
}
|
||||||
PublishAllPorts: env.GetBool("PublishAllPorts"),
|
|
||||||
NetworkMode: NetworkMode(env.Get("NetworkMode")),
|
return hc
|
||||||
IpcMode: IpcMode(env.Get("IpcMode")),
|
}
|
||||||
PidMode: PidMode(env.Get("PidMode")),
|
|
||||||
ReadonlyRootfs: env.GetBool("ReadonlyRootfs"),
|
func DecodeHostConfig(src io.Reader) (*HostConfig, error) {
|
||||||
CgroupParent: env.Get("CgroupParent"),
|
decoder := json.NewDecoder(src)
|
||||||
}
|
|
||||||
|
var w hostConfigWrapper
|
||||||
// FIXME: This is for backward compatibility, if people use `Cpuset`
|
if err := decoder.Decode(&w); err != nil {
|
||||||
// in json, make it workable, we will only pass hostConfig.CpusetCpus
|
return nil, err
|
||||||
// to execDriver.
|
}
|
||||||
if env.Exists("Cpuset") && hostConfig.CpusetCpus == "" {
|
|
||||||
hostConfig.CpusetCpus = env.Get("Cpuset")
|
hc := w.GetHostConfig()
|
||||||
}
|
|
||||||
|
return hc, nil
|
||||||
env.GetJson("LxcConf", &hostConfig.LxcConf)
|
|
||||||
env.GetJson("PortBindings", &hostConfig.PortBindings)
|
|
||||||
env.GetJson("Devices", &hostConfig.Devices)
|
|
||||||
env.GetJson("RestartPolicy", &hostConfig.RestartPolicy)
|
|
||||||
env.GetJson("Ulimits", &hostConfig.Ulimits)
|
|
||||||
env.GetJson("LogConfig", &hostConfig.LogConfig)
|
|
||||||
hostConfig.SecurityOpt = env.GetList("SecurityOpt")
|
|
||||||
if Binds := env.GetList("Binds"); Binds != nil {
|
|
||||||
hostConfig.Binds = Binds
|
|
||||||
}
|
|
||||||
if Links := env.GetList("Links"); Links != nil {
|
|
||||||
hostConfig.Links = Links
|
|
||||||
}
|
|
||||||
if Dns := env.GetList("Dns"); Dns != nil {
|
|
||||||
hostConfig.Dns = Dns
|
|
||||||
}
|
|
||||||
if DnsSearch := env.GetList("DnsSearch"); DnsSearch != nil {
|
|
||||||
hostConfig.DnsSearch = DnsSearch
|
|
||||||
}
|
|
||||||
if ExtraHosts := env.GetList("ExtraHosts"); ExtraHosts != nil {
|
|
||||||
hostConfig.ExtraHosts = ExtraHosts
|
|
||||||
}
|
|
||||||
if VolumesFrom := env.GetList("VolumesFrom"); VolumesFrom != nil {
|
|
||||||
hostConfig.VolumesFrom = VolumesFrom
|
|
||||||
}
|
|
||||||
if CapAdd := env.GetList("CapAdd"); CapAdd != nil {
|
|
||||||
hostConfig.CapAdd = CapAdd
|
|
||||||
}
|
|
||||||
if CapDrop := env.GetList("CapDrop"); CapDrop != nil {
|
|
||||||
hostConfig.CapDrop = CapDrop
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostConfig
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,6 @@ func Merge(userConf, imageConf *Config) error {
|
||||||
if userConf.User == "" {
|
if userConf.User == "" {
|
||||||
userConf.User = imageConf.User
|
userConf.User = imageConf.User
|
||||||
}
|
}
|
||||||
if userConf.Memory == 0 {
|
|
||||||
userConf.Memory = imageConf.Memory
|
|
||||||
}
|
|
||||||
if userConf.MemorySwap == 0 {
|
|
||||||
userConf.MemorySwap = imageConf.MemorySwap
|
|
||||||
}
|
|
||||||
if userConf.CpuShares == 0 {
|
|
||||||
userConf.CpuShares = imageConf.CpuShares
|
|
||||||
}
|
|
||||||
if len(userConf.ExposedPorts) == 0 {
|
if len(userConf.ExposedPorts) == 0 {
|
||||||
userConf.ExposedPorts = imageConf.ExposedPorts
|
userConf.ExposedPorts = imageConf.ExposedPorts
|
||||||
} else if imageConf.ExposedPorts != nil {
|
} else if imageConf.ExposedPorts != nil {
|
||||||
|
@ -94,8 +85,8 @@ func Merge(userConf, imageConf *Config) error {
|
||||||
userConf.Labels = imageConf.Labels
|
userConf.Labels = imageConf.Labels
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(userConf.Entrypoint) == 0 {
|
if userConf.Entrypoint.Len() == 0 {
|
||||||
if len(userConf.Cmd) == 0 {
|
if userConf.Cmd.Len() == 0 {
|
||||||
userConf.Cmd = imageConf.Cmd
|
userConf.Cmd = imageConf.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,21 +185,22 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
|
|
||||||
var (
|
var (
|
||||||
parsedArgs = cmd.Args()
|
parsedArgs = cmd.Args()
|
||||||
runCmd []string
|
runCmd *Command
|
||||||
entrypoint []string
|
entrypoint *Entrypoint
|
||||||
image = cmd.Arg(0)
|
image = cmd.Arg(0)
|
||||||
)
|
)
|
||||||
if len(parsedArgs) > 1 {
|
if len(parsedArgs) > 1 {
|
||||||
runCmd = parsedArgs[1:]
|
runCmd = NewCommand(parsedArgs[1:]...)
|
||||||
}
|
}
|
||||||
if *flEntrypoint != "" {
|
if *flEntrypoint != "" {
|
||||||
entrypoint = []string{*flEntrypoint}
|
entrypoint = NewEntrypoint(*flEntrypoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
lxcConf, err := parseKeyValueOpts(flLxcOpts)
|
lc, err := parseKeyValueOpts(flLxcOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, cmd, err
|
return nil, nil, cmd, err
|
||||||
}
|
}
|
||||||
|
lxcConf := NewLxcConfig(lc)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
domainname string
|
domainname string
|
||||||
|
@ -288,10 +289,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
Tty: *flTty,
|
Tty: *flTty,
|
||||||
NetworkDisabled: !*flNetwork,
|
NetworkDisabled: !*flNetwork,
|
||||||
OpenStdin: *flStdin,
|
OpenStdin: *flStdin,
|
||||||
Memory: flMemory, // FIXME: for backward compatibility
|
|
||||||
MemorySwap: MemorySwap, // FIXME: for backward compatibility
|
|
||||||
CpuShares: *flCpuShares, // FIXME: for backward compatibility
|
|
||||||
Cpuset: *flCpusetCpus, // FIXME: for backward compatibility
|
|
||||||
AttachStdin: attachStdin,
|
AttachStdin: attachStdin,
|
||||||
AttachStdout: attachStdout,
|
AttachStdout: attachStdout,
|
||||||
AttachStderr: attachStderr,
|
AttachStderr: attachStderr,
|
||||||
|
|
Loading…
Reference in New Issue