diff --git a/communicator/shared/shared.go b/communicator/shared/shared.go index 509aadd28..a8535ac60 100644 --- a/communicator/shared/shared.go +++ b/communicator/shared/shared.go @@ -36,7 +36,7 @@ var ConnectionBlockSupersetSchema = &configschema.Block{ Optional: true, }, "port": { - Type: cty.String, + Type: cty.Number, Optional: true, }, "timeout": { diff --git a/communicator/ssh/communicator_test.go b/communicator/ssh/communicator_test.go index d71044320..b553576f8 100644 --- a/communicator/ssh/communicator_test.go +++ b/communicator/ssh/communicator_test.go @@ -331,7 +331,7 @@ func TestHostKey(t *testing.T) { Password: "pass", Host: host, HostKey: pubKey, - Port: port, + Port: uint16(port), Timeout: "30s", } @@ -363,7 +363,7 @@ func TestHostKey(t *testing.T) { port, _ = strconv.Atoi(p) connInfo.HostKey = testClientPublicKey - connInfo.Port = port + connInfo.Port = uint16(port) cfg, err = prepareSSHConfig(connInfo) if err != nil { @@ -406,7 +406,7 @@ func TestHostCert(t *testing.T) { Password: "pass", Host: host, HostKey: testCAPublicKey, - Port: port, + Port: uint16(port), Timeout: "30s", } @@ -438,7 +438,7 @@ func TestHostCert(t *testing.T) { port, _ = strconv.Atoi(p) connInfo.HostKey = testClientPublicKey - connInfo.Port = port + connInfo.Port = uint16(port) cfg, err = prepareSSHConfig(connInfo) if err != nil { @@ -528,7 +528,7 @@ func TestCertificateBasedAuth(t *testing.T) { Host: host, PrivateKey: CLIENT_PEM, Certificate: CLIENT_CERT_SIGNED_BY_SERVER, - Port: port, + Port: uint16(port), Timeout: "30s", } diff --git a/communicator/ssh/provisioner.go b/communicator/ssh/provisioner.go index 72a492f39..666f8fbea 100644 --- a/communicator/ssh/provisioner.go +++ b/communicator/ssh/provisioner.go @@ -10,7 +10,6 @@ import ( "net" "os" "path/filepath" - "strconv" "strings" "time" @@ -56,7 +55,7 @@ type connectionInfo struct { Certificate string Host string HostKey string - Port int + Port uint16 Agent bool ScriptPath string TargetPlatform string @@ -69,7 +68,7 @@ type connectionInfo struct { BastionCertificate string BastionHost string BastionHostKey string - BastionPort int + BastionPort uint16 AgentIdentity string } @@ -102,11 +101,9 @@ func decodeConnInfo(v cty.Value) (*connectionInfo, error) { case "host_key": connInfo.HostKey = v.AsString() case "port": - p, err := strconv.Atoi(v.AsString()) - if err != nil { + if err := gocty.FromCtyValue(v, &connInfo.Port); err != nil { return nil, err } - connInfo.Port = p case "agent": connInfo.Agent = v.True() case "script_path": diff --git a/communicator/ssh/provisioner_test.go b/communicator/ssh/provisioner_test.go index 98b3cf7e6..05d8179c5 100644 --- a/communicator/ssh/provisioner_test.go +++ b/communicator/ssh/provisioner_test.go @@ -159,3 +159,22 @@ func TestProvisioner_stringBastionPort(t *testing.T) { t.Fatalf("bad %v", conf) } } + +func TestProvisioner_invalidPortNumber(t *testing.T) { + v := cty.ObjectVal(map[string]cty.Value{ + "type": cty.StringVal("ssh"), + "user": cty.StringVal("root"), + "password": cty.StringVal("supersecret"), + "private_key": cty.StringVal("someprivatekeycontents"), + "host": cty.StringVal("example.com"), + "port": cty.NumberIntVal(123456789), + }) + + _, err := parseConnectionInfo(v) + if err == nil { + t.Fatalf("bad: should not allow invalid port number") + } + if got, want := err.Error(), "value must be a whole number, between 0 and 65535 inclusive"; got != want { + t.Errorf("unexpected error\n got: %s\nwant: %s", got, want) + } +} diff --git a/communicator/winrm/communicator.go b/communicator/winrm/communicator.go index 4f9f28838..d877e3065 100644 --- a/communicator/winrm/communicator.go +++ b/communicator/winrm/communicator.go @@ -33,7 +33,7 @@ func New(v cty.Value) (*Communicator, error) { endpoint := &winrm.Endpoint{ Host: connInfo.Host, - Port: connInfo.Port, + Port: int(connInfo.Port), HTTPS: connInfo.HTTPS, Insecure: connInfo.Insecure, Timeout: connInfo.TimeoutVal, diff --git a/communicator/winrm/provisioner.go b/communicator/winrm/provisioner.go index 7a71fe92f..f77918ec8 100644 --- a/communicator/winrm/provisioner.go +++ b/communicator/winrm/provisioner.go @@ -4,12 +4,12 @@ import ( "fmt" "log" "path/filepath" - "strconv" "strings" "time" "github.com/hashicorp/terraform/communicator/shared" "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/gocty" ) const ( @@ -37,7 +37,7 @@ type connectionInfo struct { User string Password string Host string - Port int + Port uint16 HTTPS bool Insecure bool NTLM bool `mapstructure:"use_ntlm"` @@ -69,11 +69,9 @@ func decodeConnInfo(v cty.Value) (*connectionInfo, error) { case "host": connInfo.Host = v.AsString() case "port": - p, err := strconv.Atoi(v.AsString()) - if err != nil { + if err := gocty.FromCtyValue(v, &connInfo.Port); err != nil { return nil, err } - connInfo.Port = p case "https": connInfo.HTTPS = v.True() case "insecure": diff --git a/terraform/node_resource_validate.go b/terraform/node_resource_validate.go index 0f6640849..071f8e9b2 100644 --- a/terraform/node_resource_validate.go +++ b/terraform/node_resource_validate.go @@ -177,7 +177,7 @@ var connectionBlockSupersetSchema = &configschema.Block{ Optional: true, }, "port": { - Type: cty.String, + Type: cty.Number, Optional: true, }, "timeout": { diff --git a/terraform/node_resource_validate_test.go b/terraform/node_resource_validate_test.go index 1c89d32e3..3d63bf222 100644 --- a/terraform/node_resource_validate_test.go +++ b/terraform/node_resource_validate_test.go @@ -31,6 +31,7 @@ func TestNodeValidatableResource_ValidateProvisioner_valid(t *testing.T) { Config: configs.SynthBody("", map[string]cty.Value{ "host": cty.StringVal("localhost"), "type": cty.StringVal("ssh"), + "port": cty.NumberIntVal(10022), }), }, } @@ -104,7 +105,7 @@ func TestNodeValidatableResource_ValidateProvisioner__warning(t *testing.T) { } } -func TestNodeValidatableResource_ValidateProvisioner__conntectionInvalid(t *testing.T) { +func TestNodeValidatableResource_ValidateProvisioner__connectionInvalid(t *testing.T) { ctx := &MockEvalContext{} ctx.installSimpleEval() mp := &MockProvisioner{}