diff --git a/container.go b/container.go index 1888e91ff9..9448932674 100644 --- a/container.go +++ b/container.go @@ -226,6 +226,18 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, } } + envs := []string{} + + for _, env := range flEnv { + arr := strings.Split(env, "=") + if len(arr) > 1 { + envs = append(envs, env) + } else { + v := os.Getenv(env) + envs = append(envs, env+"="+v) + } + } + var binds []string // add any bind targets to the list of container volumes @@ -298,7 +310,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, AttachStdin: flAttach.Get("stdin"), AttachStdout: flAttach.Get("stdout"), AttachStderr: flAttach.Get("stderr"), - Env: flEnv, + Env: envs, Cmd: runCmd, Dns: flDns, Image: image, @@ -431,6 +443,15 @@ func (container *Container) SaveHostConfig(hostConfig *HostConfig) (err error) { return ioutil.WriteFile(container.hostConfigPath(), data, 0666) } +func (container *Container) generateEnvConfig(env []string) error { + data, err := json.Marshal(env) + if err != nil { + return err + } + ioutil.WriteFile(container.EnvConfigPath(), data, 0600) + return nil +} + func (container *Container) generateLXCConfig(hostConfig *HostConfig) error { fo, err := os.Create(container.lxcConfigPath()) if err != nil { @@ -841,17 +862,17 @@ func (container *Container) Start(hostConfig *HostConfig) (err error) { params = append(params, "-u", container.Config.User) } - if container.Config.Tty { - params = append(params, "-e", "TERM=xterm") + // Setup environment + env := []string{ + "HOME=/", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "container=lxc", + "HOSTNAME=" + container.Config.Hostname, } - // Setup environment - params = append(params, - "-e", "HOME=/", - "-e", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "-e", "container=lxc", - "-e", "HOSTNAME="+container.Config.Hostname, - ) + if container.Config.Tty { + env = append(env, "TERM=xterm") + } // Init any links between the parent and children runtime := container.runtime @@ -887,11 +908,19 @@ func (container *Container) Start(hostConfig *HostConfig) (err error) { } for _, envVar := range link.ToEnv() { - params = append(params, "-e", envVar) + env = append(env, envVar) } } } + for _, elem := range container.Config.Env { + env = append(env, elem) + } + + if err := container.generateEnvConfig(env); err != nil { + return err + } + if container.Config.WorkingDir != "" { workingDir := path.Clean(container.Config.WorkingDir) utils.Debugf("[working dir] working dir is %s", workingDir) @@ -905,10 +934,6 @@ func (container *Container) Start(hostConfig *HostConfig) (err error) { ) } - for _, elem := range container.Config.Env { - params = append(params, "-e", elem) - } - // Program params = append(params, "--", container.Path) params = append(params, container.Args...) @@ -1416,6 +1441,10 @@ func (container *Container) jsonPath() string { return path.Join(container.root, "config.json") } +func (container *Container) EnvConfigPath() string { + return path.Join(container.root, "config.env") +} + func (container *Container) lxcConfigPath() string { return path.Join(container.root, "config.lxc") } diff --git a/container_test.go b/container_test.go index 262d6fcb1d..69495d6d81 100644 --- a/container_test.go +++ b/container_test.go @@ -973,14 +973,15 @@ func TestTty(t *testing.T) { } func TestEnv(t *testing.T) { + os.Setenv("TRUE", "false") + os.Setenv("TRICKY", "tri\ncky\n") runtime := mkRuntime(t) defer nuke(runtime) - container, _, err := runtime.Create(&Config{ - Image: GetTestImage(runtime).ID, - Cmd: []string{"env"}, - }, - "", - ) + config, _, _, err := ParseRun([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil) + if err != nil { + t.Fatal(err) + } + container, _, err := runtime.Create(config, "") if err != nil { t.Fatal(err) } @@ -1010,6 +1011,11 @@ func TestEnv(t *testing.T) { "HOME=/", "container=lxc", "HOSTNAME=" + container.ShortID(), + "FALSE=true", + "TRUE=false", + "TRICKY=tri", + "cky", + "", } sort.Strings(goodEnv) if len(goodEnv) != len(actualEnv) { diff --git a/graph.go b/graph.go index 992b396285..d4ce12e67b 100644 --- a/graph.go +++ b/graph.go @@ -201,6 +201,7 @@ func (graph *Graph) getDockerInitLayer() (string, error) { "/proc": "dir", "/sys": "dir", "/.dockerinit": "file", + "/.dockerenv": "file", "/etc/resolv.conf": "file", "/etc/hosts": "file", "/etc/hostname": "file", diff --git a/lxc_template.go b/lxc_template.go index 382c16029d..d6da584ae0 100644 --- a/lxc_template.go +++ b/lxc_template.go @@ -97,6 +97,9 @@ lxc.mount.entry = shm {{$ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec # Inject dockerinit lxc.mount.entry = {{.SysInitPath}} {{$ROOTFS}}/.dockerinit none bind,ro 0 0 +# Inject env +lxc.mount.entry = {{.EnvConfigPath}} {{$ROOTFS}}/.dockerenv none bind,ro 0 0 + # In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container lxc.mount.entry = {{.ResolvConfPath}} {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0 {{if .Volumes}} diff --git a/sysinit/sysinit.go b/sysinit/sysinit.go index a37db72423..63e91a02e4 100644 --- a/sysinit/sysinit.go +++ b/sysinit/sysinit.go @@ -1,10 +1,12 @@ package sysinit import ( + "encoding/json" "flag" "fmt" "github.com/dotcloud/docker/netlink" "github.com/dotcloud/docker/utils" + "io/ioutil" "log" "net" "os" @@ -69,9 +71,18 @@ func changeUser(u string) { } // Clear environment pollution introduced by lxc-start -func cleanupEnv(env utils.ListOpts) { +func cleanupEnv() { os.Clearenv() - for _, kv := range env { + var lines []string + content, err := ioutil.ReadFile("/.dockerenv") + if err != nil { + log.Fatalf("Unable to load environment variables: %v", err) + } + err = json.Unmarshal(content, &lines) + if err != nil { + log.Fatalf("Unable to unmarshal environment variables: %v", err) + } + for _, kv := range lines { parts := strings.SplitN(kv, "=", 2) if len(parts) == 1 { parts = append(parts, "") @@ -104,12 +115,9 @@ func SysInit() { var gw = flag.String("g", "", "gateway address") var workdir = flag.String("w", "", "workdir") - var flEnv utils.ListOpts - flag.Var(&flEnv, "e", "Set environment variables") - flag.Parse() - cleanupEnv(flEnv) + cleanupEnv() setupNetworking(*gw) setupWorkingDirectory(*workdir) changeUser(*u)