Docker run -e FOO should erase FOO if FOO isn't set in client env
| ... | ... |
@@ -1736,9 +1736,12 @@ ports in Docker. |
| 1736 | 1736 |
|
| 1737 | 1737 |
This sets environmental variables in the container. For illustration all three |
| 1738 | 1738 |
flags are shown here. Where `-e`, `--env` take an environment variable and |
| 1739 |
-value, or if no "=" is provided, then that variable's current value is passed |
|
| 1740 |
-through (i.e. `$MYVAR1` from the host is set to `$MYVAR1` in the container). All |
|
| 1741 |
-three flags, `-e`, `--env` and `--env-file` can be repeated. |
|
| 1739 |
+value, or if no `=` is provided, then that variable's current value is passed |
|
| 1740 |
+through (i.e. `$MYVAR1` from the host is set to `$MYVAR1` in the container). |
|
| 1741 |
+When no `=` is provided and that variable is not defined in the client's |
|
| 1742 |
+environment then that variable will be removed from the container's list of |
|
| 1743 |
+environment variables. |
|
| 1744 |
+All three flags, `-e`, `--env` and `--env-file` can be repeated. |
|
| 1742 | 1745 |
|
| 1743 | 1746 |
Regardless of the order of these three flags, the `--env-file` are processed |
| 1744 | 1747 |
first, and then `-e`, `--env` flags. This way, the `-e` or `--env` will |
| ... | ... |
@@ -792,10 +792,7 @@ func TestRunEnvironment(t *testing.T) {
|
| 792 | 792 |
t.Fatal(err, out) |
| 793 | 793 |
} |
| 794 | 794 |
|
| 795 |
- actualEnv := strings.Split(out, "\n") |
|
| 796 |
- if actualEnv[len(actualEnv)-1] == "" {
|
|
| 797 |
- actualEnv = actualEnv[:len(actualEnv)-1] |
|
| 798 |
- } |
|
| 795 |
+ actualEnv := strings.Split(strings.TrimSpace(out), "\n") |
|
| 799 | 796 |
sort.Strings(actualEnv) |
| 800 | 797 |
|
| 801 | 798 |
goodEnv := []string{
|
| ... | ... |
@@ -823,6 +820,72 @@ func TestRunEnvironment(t *testing.T) {
|
| 823 | 823 |
logDone("run - verify environment")
|
| 824 | 824 |
} |
| 825 | 825 |
|
| 826 |
+func TestRunEnvironmentErase(t *testing.T) {
|
|
| 827 |
+ // Test to make sure that when we use -e on env vars that are |
|
| 828 |
+ // not set in our local env that they're removed (if present) in |
|
| 829 |
+ // the container |
|
| 830 |
+ cmd := exec.Command(dockerBinary, "run", "-e", "FOO", "-e", "HOSTNAME", "busybox", "env") |
|
| 831 |
+ cmd.Env = []string{}
|
|
| 832 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 833 |
+ if err != nil {
|
|
| 834 |
+ t.Fatal(err, out) |
|
| 835 |
+ } |
|
| 836 |
+ |
|
| 837 |
+ actualEnv := strings.Split(strings.TrimSpace(out), "\n") |
|
| 838 |
+ sort.Strings(actualEnv) |
|
| 839 |
+ |
|
| 840 |
+ goodEnv := []string{
|
|
| 841 |
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
|
| 842 |
+ "HOME=/root", |
|
| 843 |
+ } |
|
| 844 |
+ sort.Strings(goodEnv) |
|
| 845 |
+ if len(goodEnv) != len(actualEnv) {
|
|
| 846 |
+ t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
|
|
| 847 |
+ } |
|
| 848 |
+ for i := range goodEnv {
|
|
| 849 |
+ if actualEnv[i] != goodEnv[i] {
|
|
| 850 |
+ t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
|
|
| 851 |
+ } |
|
| 852 |
+ } |
|
| 853 |
+ |
|
| 854 |
+ deleteAllContainers() |
|
| 855 |
+ |
|
| 856 |
+ logDone("run - verify environment erase")
|
|
| 857 |
+} |
|
| 858 |
+ |
|
| 859 |
+func TestRunEnvironmentOverride(t *testing.T) {
|
|
| 860 |
+ // Test to make sure that when we use -e on env vars that are |
|
| 861 |
+ // already in the env that we're overriding them |
|
| 862 |
+ cmd := exec.Command(dockerBinary, "run", "-e", "HOSTNAME", "-e", "HOME=/root2", "busybox", "env") |
|
| 863 |
+ cmd.Env = []string{"HOSTNAME=bar"}
|
|
| 864 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 865 |
+ if err != nil {
|
|
| 866 |
+ t.Fatal(err, out) |
|
| 867 |
+ } |
|
| 868 |
+ |
|
| 869 |
+ actualEnv := strings.Split(strings.TrimSpace(out), "\n") |
|
| 870 |
+ sort.Strings(actualEnv) |
|
| 871 |
+ |
|
| 872 |
+ goodEnv := []string{
|
|
| 873 |
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
|
| 874 |
+ "HOME=/root2", |
|
| 875 |
+ "HOSTNAME=bar", |
|
| 876 |
+ } |
|
| 877 |
+ sort.Strings(goodEnv) |
|
| 878 |
+ if len(goodEnv) != len(actualEnv) {
|
|
| 879 |
+ t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
|
|
| 880 |
+ } |
|
| 881 |
+ for i := range goodEnv {
|
|
| 882 |
+ if actualEnv[i] != goodEnv[i] {
|
|
| 883 |
+ t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
|
|
| 884 |
+ } |
|
| 885 |
+ } |
|
| 886 |
+ |
|
| 887 |
+ deleteAllContainers() |
|
| 888 |
+ |
|
| 889 |
+ logDone("run - verify environment override")
|
|
| 890 |
+} |
|
| 891 |
+ |
|
| 826 | 892 |
func TestRunContainerNetwork(t *testing.T) {
|
| 827 | 893 |
cmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "127.0.0.1") |
| 828 | 894 |
if _, err := runCommand(cmd); err != nil {
|
| ... | ... |
@@ -11,6 +11,7 @@ import ( |
| 11 | 11 |
"github.com/docker/docker/api" |
| 12 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 13 | 13 |
"github.com/docker/docker/pkg/parsers" |
| 14 |
+ "github.com/docker/docker/utils" |
|
| 14 | 15 |
) |
| 15 | 16 |
|
| 16 | 17 |
var ( |
| ... | ... |
@@ -168,6 +169,9 @@ func ValidateEnv(val string) (string, error) {
|
| 168 | 168 |
if len(arr) > 1 {
|
| 169 | 169 |
return val, nil |
| 170 | 170 |
} |
| 171 |
+ if !utils.DoesEnvExist(val) {
|
|
| 172 |
+ return val, nil |
|
| 173 |
+ } |
|
| 171 | 174 |
return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
|
| 172 | 175 |
} |
| 173 | 176 |
|
| ... | ... |
@@ -401,7 +401,17 @@ func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
|
| 401 | 401 |
parts := strings.SplitN(e, "=", 2) |
| 402 | 402 |
cache[parts[0]] = i |
| 403 | 403 |
} |
| 404 |
+ |
|
| 404 | 405 |
for _, value := range overrides {
|
| 406 |
+ // Values w/o = means they want this env to be removed/unset. |
|
| 407 |
+ if !strings.Contains(value, "=") {
|
|
| 408 |
+ if i, exists := cache[value]; exists {
|
|
| 409 |
+ defaults[i] = "" // Used to indicate it should be removed |
|
| 410 |
+ } |
|
| 411 |
+ continue |
|
| 412 |
+ } |
|
| 413 |
+ |
|
| 414 |
+ // Just do a normal set/update |
|
| 405 | 415 |
parts := strings.SplitN(value, "=", 2) |
| 406 | 416 |
if i, exists := cache[parts[0]]; exists {
|
| 407 | 417 |
defaults[i] = value |
| ... | ... |
@@ -409,9 +419,28 @@ func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
|
| 409 | 409 |
defaults = append(defaults, value) |
| 410 | 410 |
} |
| 411 | 411 |
} |
| 412 |
+ |
|
| 413 |
+ // Now remove all entries that we want to "unset" |
|
| 414 |
+ for i := 0; i < len(defaults); i++ {
|
|
| 415 |
+ if defaults[i] == "" {
|
|
| 416 |
+ defaults = append(defaults[:i], defaults[i+1:]...) |
|
| 417 |
+ i-- |
|
| 418 |
+ } |
|
| 419 |
+ } |
|
| 420 |
+ |
|
| 412 | 421 |
return defaults |
| 413 | 422 |
} |
| 414 | 423 |
|
| 424 |
+func DoesEnvExist(name string) bool {
|
|
| 425 |
+ for _, entry := range os.Environ() {
|
|
| 426 |
+ parts := strings.SplitN(entry, "=", 2) |
|
| 427 |
+ if parts[0] == name {
|
|
| 428 |
+ return true |
|
| 429 |
+ } |
|
| 430 |
+ } |
|
| 431 |
+ return false |
|
| 432 |
+} |
|
| 433 |
+ |
|
| 415 | 434 |
// ReadSymlinkedDirectory returns the target directory of a symlink. |
| 416 | 435 |
// The target of the symbolic link may not be a file. |
| 417 | 436 |
func ReadSymlinkedDirectory(path string) (string, error) {
|