diff --git a/commands/env.go b/commands/env.go index e15dbe1369..f8f4643ae0 100644 --- a/commands/env.go +++ b/commands/env.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "strings" "text/template" "github.com/codegangsta/cli" @@ -11,7 +12,7 @@ import ( ) const ( - envTmpl = `{{ .Prefix }}DOCKER_TLS_VERIFY{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}DOCKER_HOST{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}DOCKER_CERT_PATH{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}DOCKER_MACHINE_NAME{{ .Delimiter }}{{ .MachineName }}{{ .Suffix }}{{ .UsageHint }}` + envTmpl = `{{ .Prefix }}DOCKER_TLS_VERIFY{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}DOCKER_HOST{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}DOCKER_CERT_PATH{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}DOCKER_MACHINE_NAME{{ .Delimiter }}{{ .MachineName }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}` ) var ( @@ -27,6 +28,8 @@ type ShellConfig struct { DockerTLSVerify string UsageHint string MachineName string + NoProxyVar string + NoProxyValue string } func cmdEnv(c *cli.Context) { @@ -54,11 +57,42 @@ func cmdEnv(c *cli.Context) { usageHint := generateUsageHint(c.App.Name, c.Args().First(), userShell) - shellCfg := ShellConfig{ - DockerCertPath: "", - DockerHost: "", - DockerTLSVerify: "", - MachineName: "", + shellCfg := &ShellConfig{ + DockerCertPath: authOptions.CertDir, + DockerHost: dockerHost, + DockerTLSVerify: "1", + UsageHint: usageHint, + MachineName: h.Name, + } + + if c.Bool("no-proxy") { + ip, err := h.Driver.GetIP() + if err != nil { + log.Fatalf("Error getting host IP: %s", err) + } + + // first check for an existing lower case no_proxy var + noProxyVar := "no_proxy" + noProxyValue := os.Getenv("no_proxy") + + // otherwise default to allcaps HTTP_PROXY + if noProxyValue == "" { + noProxyVar = "NO_PROXY" + noProxyValue = os.Getenv("NO_PROXY") + } + + // add the docker host to the no_proxy list idempotently + switch { + case noProxyValue == "": + noProxyValue = ip + case strings.Contains(noProxyValue, ip): + //ip already in no_proxy list, nothing to do + default: + noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ip) + } + + shellCfg.NoProxyVar = noProxyVar + shellCfg.NoProxyValue = noProxyValue } // unset vars @@ -97,14 +131,6 @@ func cmdEnv(c *cli.Context) { return } - shellCfg = ShellConfig{ - DockerCertPath: authOptions.CertDir, - DockerHost: dockerHost, - DockerTLSVerify: "1", - UsageHint: usageHint, - MachineName: h.Name, - } - switch userShell { case "fish": shellCfg.Prefix = "set -x " diff --git a/docs/reference/env.md b/docs/reference/env.md index dd547ba1d5..9927c9ee08 100644 --- a/docs/reference/env.md +++ b/docs/reference/env.md @@ -75,4 +75,29 @@ set DOCKER_HOST=tcp://192.168.99.101:2376 set DOCKER_CERT_PATH=C:\Users\captain\.docker\machine\machines\dev set DOCKER_MACHINE_NAME=dev # Run this command to configure your shell: copy and paste the above values into your command prompt -``` \ No newline at end of file +``` + +## Excluding the created machine from proxies + +The env command supports a `--no-proxy` flag which will ensure that the created +machine's IP address is added to the [`NO_PROXY`/`no_proxy` environment +variable](https://wiki.archlinux.org/index.php/Proxy_settings). + +This is useful when using `docker-machine` with a local VM provider (e.g. +`virtualbox` or `vmwarefusion`) in network environments where a HTTP proxy is +required for internet access. + +``` +$ docker-machine env --no-proxy default +export DOCKER_TLS_VERIFY="1" +export DOCKER_HOST="tcp://192.168.99.104:2376" +export DOCKER_CERT_PATH="/Users/databus23/.docker/machine/certs" +export DOCKER_MACHINE_NAME="default" +export NO_PROXY="192.168.99.104" +# Run this command to configure your shell: +# eval "$(docker-machine env default)" +``` + +You may also want to visit the [documentation on setting `HTTP_PROXY` for the +created daemon using the `--engine-env` flag for `docker-machine +create`](https://docs.docker.com/machine/reference/create/#specifying-configuration-options-for-the-created-docker-engine). diff --git a/test/integration/core/env_shell.bats b/test/integration/core/env_shell.bats index 5cc07dc623..5dc9a8505c 100644 --- a/test/integration/core/env_shell.bats +++ b/test/integration/core/env_shell.bats @@ -8,33 +8,43 @@ load ${BASE_TEST_DIR}/helpers.bash } @test "$DRIVER: test powershell notation" { - run machine env --shell powershell $NAME + run machine env --shell powershell --no-proxy $NAME [[ ${lines[0]} == "\$Env:DOCKER_TLS_VERIFY = \"1\"" ]] [[ ${lines[1]} == "\$Env:DOCKER_HOST = \"$(machine url $NAME)\"" ]] [[ ${lines[2]} == "\$Env:DOCKER_CERT_PATH = \"$MACHINE_STORAGE_PATH/certs\"" ]] [[ ${lines[3]} == "\$Env:DOCKER_MACHINE_NAME = \"$NAME\"" ]] + [[ ${lines[4]} == "\$Env:NO_PROXY = \"$(machine ip $NAME)\"" ]] } @test "$DRIVER: test bash / zsh notation" { - run machine env $NAME + run machine env --no-proxy $NAME [[ ${lines[0]} == "export DOCKER_TLS_VERIFY=\"1\"" ]] [[ ${lines[1]} == "export DOCKER_HOST=\"$(machine url $NAME)\"" ]] [[ ${lines[2]} == "export DOCKER_CERT_PATH=\"$MACHINE_STORAGE_PATH/certs\"" ]] [[ ${lines[3]} == "export DOCKER_MACHINE_NAME=\"$NAME\"" ]] + [[ ${lines[4]} == "export NO_PROXY=\"$(machine ip $NAME)\"" ]] } @test "$DRIVER: test cmd.exe notation" { - run machine env --shell cmd $NAME + run machine env --shell cmd --no-proxy $NAME [[ ${lines[0]} == "set DOCKER_TLS_VERIFY=1" ]] [[ ${lines[1]} == "set DOCKER_HOST=$(machine url $NAME)" ]] [[ ${lines[2]} == "set DOCKER_CERT_PATH=$MACHINE_STORAGE_PATH/certs" ]] [[ ${lines[3]} == "set DOCKER_MACHINE_NAME=$NAME" ]] + [[ ${lines[4]} == "set NO_PROXY=$(machine ip $NAME)" ]] } @test "$DRIVER: test fish notation" { - run machine env --shell fish $NAME + run machine env --shell fish --no-proxy $NAME [[ ${lines[0]} == "set -x DOCKER_TLS_VERIFY \"1\";" ]] [[ ${lines[1]} == "set -x DOCKER_HOST \"$(machine url $NAME)\";" ]] [[ ${lines[2]} == "set -x DOCKER_CERT_PATH \"$MACHINE_STORAGE_PATH/certs\";" ]] [[ ${lines[3]} == "set -x DOCKER_MACHINE_NAME \"$NAME\";" ]] + [[ ${lines[4]} == "set -x NO_PROXY \"$(machine ip $NAME)\";" ]] +} + +@test "$DRIVER: no proxy with NO_PROXY already set" { + export NO_PROXY=localhost + run machine env --no-proxy $NAME + [[ ${lines[4]} == "export NO_PROXY=\"localhost,$(machine ip $NAME)\"" ]] }