Selaa lähdekoodia

Merge pull request #4174 from vbatts/vbatts-env_file

support for `docker run` environment variables file
Michael Crosby 11 vuotta sitten
vanhempi
commit
b45c1061bf
3 muutettua tiedostoa jossa 120 lisäystä ja 1 poistoa
  1. 49 0
      docs/sources/reference/commandline/cli.rst
  2. 54 0
      opts/envfile.go
  3. 17 1
      runconfig/parse.go

+ 49 - 0
docs/sources/reference/commandline/cli.rst

@@ -1152,6 +1152,7 @@ image is removed.
       --cidfile="": Write the container ID to the file
       -d, --detach=false: Detached mode: Run container in the background, print new container id
       -e, --env=[]: Set environment variables
+      --env-file="": Read in a line delimited file of ENV variables
       -h, --hostname="": Container host name
       -i, --interactive=false: Keep stdin open even if not attached
       --privileged=false: Give extended privileges to this container
@@ -1284,6 +1285,54 @@ This exposes port ``80`` of the container for use within a link without
 publishing the port to the host system's interfaces. :ref:`port_redirection`
 explains in detail how to manipulate ports in Docker.
 
+.. code-block:: bash
+
+    $ sudo docker run -e MYVAR1 --env MYVAR2=foo --env-file ./env.list ubuntu bash
+
+This sets environmental variables in the container. For illustration all three
+flags are shown here. Where ``-e``, ``--env`` take an environment variable and
+value, or if no "=" is provided, then that variable's current value is passed
+through (i.e. $MYVAR1 from the host is set to $MYVAR1 in the container). All
+three flags, ``-e``, ``--env``  and ``--env-file`` can be repeated.
+
+Regardless of the order of these three flags, the ``--env-file`` are processed
+first, and then ``-e``/``--env`` flags. This way, the ``-e`` or ``--env`` will
+override variables as needed.
+
+.. code-block:: bash
+
+    $ cat ./env.list
+    TEST_FOO=BAR
+    $ sudo docker run --env TEST_FOO="This is a test" --env-file ./env.list busybox env | grep TEST_FOO
+    TEST_FOO=This is a test
+
+The ``--env-file`` flag takes a filename as an argument and expects each line
+to be in the VAR=VAL format, mimicking the argument passed to ``--env``.
+Comment lines need only be prefixed with ``#``
+
+An example of a file passed with ``--env-file``
+
+.. code-block:: bash
+
+    $ cat ./env.list
+    TEST_FOO=BAR
+
+    # this is a comment
+    TEST_APP_DEST_HOST=10.10.0.127
+    TEST_APP_DEST_PORT=8888
+
+    # pass through this variable from the caller
+    TEST_PASSTHROUGH
+    $ sudo TEST_PASSTHROUGH=howdy docker run --env-file ./env.list busybox env
+    HOME=/
+    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+    HOSTNAME=5198e0745561
+    TEST_FOO=BAR
+    TEST_APP_DEST_HOST=10.10.0.127
+    TEST_APP_DEST_PORT=8888
+    TEST_PASSTHROUGH=howdy
+
+
 .. code-block:: bash
 
     $ sudo docker run --name console -t -i ubuntu bash

+ 54 - 0
opts/envfile.go

@@ -0,0 +1,54 @@
+package opts
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strings"
+)
+
+/*
+Read in a line delimited file with environment variables enumerated
+*/
+func ParseEnvFile(filename string) ([]string, error) {
+	fh, err := os.Open(filename)
+	if err != nil {
+		return []string{}, err
+	}
+	defer fh.Close()
+
+	lines := []string{}
+	scanner := bufio.NewScanner(fh)
+	for scanner.Scan() {
+		line := scanner.Text()
+		// line is not empty, and not starting with '#'
+		if len(line) > 0 && !strings.HasPrefix(line, "#") {
+			if strings.Contains(line, "=") {
+				data := strings.SplitN(line, "=", 2)
+
+				// trim the front of a variable, but nothing else
+				variable := strings.TrimLeft(data[0], whiteSpaces)
+				if strings.ContainsAny(variable, whiteSpaces) {
+					return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' has white spaces", variable)}
+				}
+
+				// pass the value through, no trimming
+				lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
+			} else {
+				// if only a pass-through variable is given, clean it up.
+				lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line)))
+			}
+		}
+	}
+	return lines, nil
+}
+
+var whiteSpaces = " \t"
+
+type ErrBadEnvVariable struct {
+	msg string
+}
+
+func (e ErrBadEnvVariable) Error() string {
+	return fmt.Sprintf("poorly formatted environment: %s", e.msg)
+}

+ 17 - 1
runconfig/parse.go

@@ -52,6 +52,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
 		flVolumesFrom opts.ListOpts
 		flLxcOpts     opts.ListOpts
 		flDriverOpts  opts.ListOpts
+		flEnvFile     opts.ListOpts
 
 		flAutoRemove      = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
 		flDetach          = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: Run container in the background, print new container id")
@@ -78,6 +79,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
 	cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
 	cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)")
 	cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
+	cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a line delimited file of ENV variables")
 
 	cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat))
 	cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host")
@@ -199,6 +201,20 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
 		}
 	}
 
+	// collect all the environment variables for the container
+	envVariables := []string{}
+	for _, ef := range flEnvFile.GetAll() {
+		parsedVars, err := opts.ParseEnvFile(ef)
+		if err != nil {
+			return nil, nil, cmd, err
+		}
+		envVariables = append(envVariables, parsedVars...)
+	}
+	// parse the '-e' and '--env' after, to allow override
+	envVariables = append(envVariables, flEnv.GetAll()...)
+	// boo, there's no debug output for docker run
+	//utils.Debugf("Environment variables for the container: %#v", envVariables)
+
 	config := &Config{
 		Hostname:        hostname,
 		Domainname:      domainname,
@@ -213,7 +229,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
 		AttachStdin:     flAttach.Get("stdin"),
 		AttachStdout:    flAttach.Get("stdout"),
 		AttachStderr:    flAttach.Get("stderr"),
-		Env:             flEnv.GetAll(),
+		Env:             envVariables,
 		Cmd:             runCmd,
 		Dns:             flDns.GetAll(),
 		DnsSearch:       flDnsSearch.GetAll(),