From 303967e8432aeeefad26810140a90811fd0e95bc Mon Sep 17 00:00:00 2001 From: Brian Olsen Date: Wed, 14 Aug 2013 00:40:23 +0200 Subject: [PATCH 1/3] Set environment variables using a file. Upstream-commit: be7eb4bfcb09e17a2c45179bab268ba15050cb6a Component: engine --- components/engine/container.go | 50 ++++++++++++++++++++-------- components/engine/graph.go | 1 + components/engine/lxc_template.go | 3 ++ components/engine/sysinit/sysinit.go | 15 +++++---- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/components/engine/container.go b/components/engine/container.go index 1888e91ff9..9fff926e40 100644 --- a/components/engine/container.go +++ b/components/engine/container.go @@ -431,6 +431,20 @@ func (container *Container) SaveHostConfig(hostConfig *HostConfig) (err error) { return ioutil.WriteFile(container.hostConfigPath(), data, 0666) } +func (container *Container) generateEnvConfig(env []string) error { + fo, err := os.Create(container.EnvConfigPath()) + if err != nil { + return err + } + defer fo.Close() + for _, item := range env { + if _, err := fo.WriteString(item + "\n"); err != nil { + return err + } + } + return nil +} + func (container *Container) generateLXCConfig(hostConfig *HostConfig) error { fo, err := os.Create(container.lxcConfigPath()) if err != nil { @@ -841,17 +855,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 +901,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 +927,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 +1434,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/components/engine/graph.go b/components/engine/graph.go index 992b396285..d4ce12e67b 100644 --- a/components/engine/graph.go +++ b/components/engine/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/components/engine/lxc_template.go b/components/engine/lxc_template.go index 382c16029d..d6da584ae0 100644 --- a/components/engine/lxc_template.go +++ b/components/engine/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/components/engine/sysinit/sysinit.go b/components/engine/sysinit/sysinit.go index a37db72423..05ee9c08ce 100644 --- a/components/engine/sysinit/sysinit.go +++ b/components/engine/sysinit/sysinit.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/dotcloud/docker/netlink" "github.com/dotcloud/docker/utils" + "io/ioutil" "log" "net" "os" @@ -69,9 +70,14 @@ func changeUser(u string) { } // Clear environment pollution introduced by lxc-start -func cleanupEnv(env utils.ListOpts) { +func cleanupEnv() { os.Clearenv() - for _, kv := range env { + content, err := ioutil.ReadFile("/.dockerenv") + if err != nil { + log.Fatalf("Unable to load environment variables: %v", err) + } + lines := strings.Split(string(content), "\n") + for _, kv := range lines { parts := strings.SplitN(kv, "=", 2) if len(parts) == 1 { parts = append(parts, "") @@ -104,12 +110,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) From fe428bd3cdcd05d04c5c72ac964fd9b4795a11e1 Mon Sep 17 00:00:00 2001 From: Brian Olsen Date: Wed, 14 Aug 2013 02:31:04 +0200 Subject: [PATCH 2/3] Support copying value from env with -e option. Upstream-commit: 25c4c87c86aca2f17363dbcd9d7bc47640ff9c23 Component: engine --- components/engine/container.go | 14 +++++++++++++- components/engine/container_test.go | 14 ++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/components/engine/container.go b/components/engine/container.go index 9fff926e40..8b7f98955f 100644 --- a/components/engine/container.go +++ b/components/engine/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, diff --git a/components/engine/container_test.go b/components/engine/container_test.go index 262d6fcb1d..90ca6defea 100644 --- a/components/engine/container_test.go +++ b/components/engine/container_test.go @@ -973,14 +973,14 @@ func TestTty(t *testing.T) { } func TestEnv(t *testing.T) { + os.Setenv("TRUE", "false") 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", GetTestImage(runtime).ID, "env"}, nil) + if err != nil { + t.Fatal(err) + } + container, _, err := runtime.Create(config, "") if err != nil { t.Fatal(err) } @@ -1010,6 +1010,8 @@ func TestEnv(t *testing.T) { "HOME=/", "container=lxc", "HOSTNAME=" + container.ShortID(), + "FALSE=true", + "TRUE=false", } sort.Strings(goodEnv) if len(goodEnv) != len(actualEnv) { From 67465c23f00e6d4e7c54af06dd2ff4428a9374e3 Mon Sep 17 00:00:00 2001 From: Brian Olsen Date: Thu, 15 Aug 2013 02:14:30 +0200 Subject: [PATCH 3/3] Fixed problem with variables containing \n. The /.dockerenv file is now a marshalled json array so that environment variables with \n and other weird values are supported. Upstream-commit: 1c3a674444c6a6f08ea5ce3812046a00678e4a29 Component: engine --- components/engine/container.go | 9 ++------- components/engine/container_test.go | 6 +++++- components/engine/sysinit/sysinit.go | 7 ++++++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/components/engine/container.go b/components/engine/container.go index 8b7f98955f..9448932674 100644 --- a/components/engine/container.go +++ b/components/engine/container.go @@ -444,16 +444,11 @@ func (container *Container) SaveHostConfig(hostConfig *HostConfig) (err error) { } func (container *Container) generateEnvConfig(env []string) error { - fo, err := os.Create(container.EnvConfigPath()) + data, err := json.Marshal(env) if err != nil { return err } - defer fo.Close() - for _, item := range env { - if _, err := fo.WriteString(item + "\n"); err != nil { - return err - } - } + ioutil.WriteFile(container.EnvConfigPath(), data, 0600) return nil } diff --git a/components/engine/container_test.go b/components/engine/container_test.go index 90ca6defea..69495d6d81 100644 --- a/components/engine/container_test.go +++ b/components/engine/container_test.go @@ -974,9 +974,10 @@ 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) - config, _, _, err := ParseRun([]string{"-e=FALSE=true", "-e=TRUE", GetTestImage(runtime).ID, "env"}, nil) + config, _, _, err := ParseRun([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil) if err != nil { t.Fatal(err) } @@ -1012,6 +1013,9 @@ func TestEnv(t *testing.T) { "HOSTNAME=" + container.ShortID(), "FALSE=true", "TRUE=false", + "TRICKY=tri", + "cky", + "", } sort.Strings(goodEnv) if len(goodEnv) != len(actualEnv) { diff --git a/components/engine/sysinit/sysinit.go b/components/engine/sysinit/sysinit.go index 05ee9c08ce..63e91a02e4 100644 --- a/components/engine/sysinit/sysinit.go +++ b/components/engine/sysinit/sysinit.go @@ -1,6 +1,7 @@ package sysinit import ( + "encoding/json" "flag" "fmt" "github.com/dotcloud/docker/netlink" @@ -72,11 +73,15 @@ func changeUser(u string) { // Clear environment pollution introduced by lxc-start func cleanupEnv() { os.Clearenv() + var lines []string content, err := ioutil.ReadFile("/.dockerenv") if err != nil { log.Fatalf("Unable to load environment variables: %v", err) } - lines := strings.Split(string(content), "\n") + 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 {