diff --git a/helper/communicator/config.go b/helper/communicator/config.go index f2664b192..52b81a3a6 100644 --- a/helper/communicator/config.go +++ b/helper/communicator/config.go @@ -41,14 +41,15 @@ type Config struct { SSHReadWriteTimeout time.Duration `mapstructure:"ssh_read_write_timeout"` // WinRM - WinRMUser string `mapstructure:"winrm_username"` - WinRMPassword string `mapstructure:"winrm_password"` WinRMHost string `mapstructure:"winrm_host"` + WinRMInsecure bool `mapstructure:"winrm_insecure"` + WinRMNoProxy bool `mapstructure:"winrm_no_proxy"` + WinRMPassword string `mapstructure:"winrm_password"` WinRMPort int `mapstructure:"winrm_port"` WinRMTimeout time.Duration `mapstructure:"winrm_timeout"` - WinRMUseSSL bool `mapstructure:"winrm_use_ssl"` - WinRMInsecure bool `mapstructure:"winrm_insecure"` WinRMUseNTLM bool `mapstructure:"winrm_use_ntlm"` + WinRMUseSSL bool `mapstructure:"winrm_use_ssl"` + WinRMUser string `mapstructure:"winrm_username"` WinRMTransportDecorator func() winrm.Transporter } diff --git a/helper/communicator/step_connect_test.go b/helper/communicator/step_connect_test.go index fb61f6463..6db32fba5 100644 --- a/helper/communicator/step_connect_test.go +++ b/helper/communicator/step_connect_test.go @@ -3,10 +3,12 @@ package communicator import ( "bytes" "context" + "os" "testing" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" + "github.com/stretchr/testify/assert" ) func TestStepConnect_impl(t *testing.T) { @@ -29,6 +31,28 @@ func TestStepConnect_none(t *testing.T) { } } +var noProxyTests = []struct { + current string + expected string +}{ + {"", "foo:1"}, + {"foo:1", "foo:1"}, + {"foo:1,bar:2", "foo:1,bar:2"}, + {"bar:2", "bar:2,foo:1"}, +} + +func TestStepConnect_setNoProxy(t *testing.T) { + key := "NO_PROXY" + for _, tt := range noProxyTests { + if value := os.Getenv(key); value != "" { + os.Unsetenv(key) + defer func() { os.Setenv(key, value) }() + os.Setenv(key, tt.current) + assert.Equal(t, tt.expected, os.Getenv(key), "env not set correctly.") + } + } +} + func testState(t *testing.T) multistep.StateBag { state := new(multistep.BasicStateBag) state.Put("hook", &packer.MockHook{}) diff --git a/helper/communicator/step_connect_winrm.go b/helper/communicator/step_connect_winrm.go index 06e6236f8..cdda73a5a 100644 --- a/helper/communicator/step_connect_winrm.go +++ b/helper/communicator/step_connect_winrm.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "log" + "os" "strings" "time" @@ -128,6 +129,12 @@ func (s *StepConnectWinRM) waitForWinRM(state multistep.StateBag, cancel <-chan } } + if s.Config.WinRMNoProxy { + if err := setNoProxy(host, port); err != nil { + return nil, fmt.Errorf("Error setting no_proxy: %s", err) + } + } + log.Println("[INFO] Attempting WinRM connection...") comm, err = winrm.New(&winrm.Config{ Host: host, @@ -182,3 +189,22 @@ func (s *StepConnectWinRM) waitForWinRM(state multistep.StateBag, cancel <-chan return comm, nil } + +// setNoProxy configures the $NO_PROXY env var +func setNoProxy(host string, port int) error { + current := os.Getenv("NO_PROXY") + p := fmt.Sprintf("%s:%d", host, port) + // not set + // set + // is set and not contains + // set + // is set and contains + if current == "" { + return os.Setenv("NO_PROXY", p) + } + if !strings.Contains(current, p) { + return os.Setenv("NO_PROXY", strings.Join([]string{current, p}, ",")) + } + return nil + +} diff --git a/website/source/docs/templates/communicator.html.md b/website/source/docs/templates/communicator.html.md index 0165ab5a1..db768a90a 100644 --- a/website/source/docs/templates/communicator.html.md +++ b/website/source/docs/templates/communicator.html.md @@ -139,16 +139,21 @@ The WinRM communicator has the following options. - `winrm_password` (string) - The password to use to connect to WinRM. +- `winrm_insecure` (boolean) - If true, do not check server certificate + chain and host name + +* `winrm_no_proxy` (boolean) - Setting this to `true` adds the remote + `host:post` to the `NO_PROXY` environment variable. This has the effect of + bypassing any configured proxies when connecting to the remote host. + Default to `false`. + - `winrm_timeout` (string) - The amount of time to wait for WinRM to become available. This defaults to "30m" since setting up a Windows machine generally takes a long time. -- `winrm_use_ssl` (boolean) - If true, use HTTPS for WinRM - -- `winrm_insecure` (boolean) - If true, do not check server certificate - chain and host name - - `winrm_use_ntlm` (boolean) - If true, NTLM authentication will be used for WinRM, rather than default (basic authentication), removing the requirement for basic authentication to be enabled within the target guest. Further reading for remote connection authentication can be found [here](https://msdn.microsoft.com/en-us/library/aa384295(v=vs.85).aspx). + +- `winrm_use_ssl` (boolean) - If true, use HTTPS for WinRM