Merge pull request #5630 from johndaviesco/winrm_no_proxy

Winrm no proxy
This commit is contained in:
Matthew Hooker 2017-12-07 15:41:16 -08:00 committed by GitHub
commit 2c1c7b9659
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 136 additions and 42 deletions

View File

@ -54,6 +54,7 @@ type RunConfig struct {
Comm communicator.Config `mapstructure:",squash"` Comm communicator.Config `mapstructure:",squash"`
SSHKeyPairName string `mapstructure:"ssh_keypair_name"` SSHKeyPairName string `mapstructure:"ssh_keypair_name"`
SSHPrivateIp bool `mapstructure:"ssh_private_ip"` SSHPrivateIp bool `mapstructure:"ssh_private_ip"`
SSHInterface string `mapstructure:"ssh_interface"`
} }
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
@ -77,6 +78,24 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
// Validation // Validation
errs := c.Comm.Prepare(ctx) errs := c.Comm.Prepare(ctx)
if c.SSHPrivateIp && c.SSHInterface != "" {
errs = append(errs, errors.New("ssh_interface and ssh_private_ip should not both be specified"))
}
// Legacy configurable
if c.SSHPrivateIp {
c.SSHInterface = "private_ip"
}
// Valadating ssh_interface
if c.SSHInterface != "public_ip" &&
c.SSHInterface != "private_ip" &&
c.SSHInterface != "public_dns" &&
c.SSHInterface != "private_dns" &&
c.SSHInterface != "" {
errs = append(errs, errors.New(fmt.Sprintf("Unknown interface type: %s", c.SSHInterface)))
}
if c.SSHKeyPairName != "" { if c.SSHKeyPairName != "" {
if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKey == "" { if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKey == "" {
errs = append(errs, errors.New("A private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name.")) errs = append(errs, errors.New("A private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))

View File

@ -25,21 +25,40 @@ var (
// SSHHost returns a function that can be given to the SSH communicator // SSHHost returns a function that can be given to the SSH communicator
// for determining the SSH address based on the instance DNS name. // for determining the SSH address based on the instance DNS name.
func SSHHost(e ec2Describer, private bool) func(multistep.StateBag) (string, error) { func SSHHost(e ec2Describer, sshInterface string) func(multistep.StateBag) (string, error) {
return func(state multistep.StateBag) (string, error) { return func(state multistep.StateBag) (string, error) {
const tries = 2 const tries = 2
// <= with current structure to check result of describing `tries` times // <= with current structure to check result of describing `tries` times
for j := 0; j <= tries; j++ { for j := 0; j <= tries; j++ {
var host string var host string
i := state.Get("instance").(*ec2.Instance) i := state.Get("instance").(*ec2.Instance)
if i.VpcId != nil && *i.VpcId != "" { if sshInterface != "" {
if i.PublicIpAddress != nil && *i.PublicIpAddress != "" && !private { switch sshInterface {
case "public_ip":
if i.PublicIpAddress != nil {
host = *i.PublicIpAddress
}
case "private_ip":
if i.PrivateIpAddress != nil {
host = *i.PrivateIpAddress
}
case "public_dns":
if i.PublicDnsName != nil {
host = *i.PublicDnsName
}
case "private_dns":
if i.PrivateDnsName != nil {
host = *i.PrivateDnsName
}
default:
panic(fmt.Sprintf("Unknown interface type: %s", sshInterface))
}
} else if i.VpcId != nil && *i.VpcId != "" {
if i.PublicIpAddress != nil && *i.PublicIpAddress != "" {
host = *i.PublicIpAddress host = *i.PublicIpAddress
} else if i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" { } else if i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" {
host = *i.PrivateIpAddress host = *i.PrivateIpAddress
} }
} else if private && i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" {
host = *i.PrivateIpAddress
} else if i.PublicDnsName != nil && *i.PublicDnsName != "" { } else if i.PublicDnsName != nil && *i.PublicDnsName != "" {
host = *i.PublicDnsName host = *i.PublicDnsName
} }
@ -63,7 +82,7 @@ func SSHHost(e ec2Describer, private bool) func(multistep.StateBag) (string, err
time.Sleep(sshHostSleepDuration) time.Sleep(sshHostSleepDuration)
} }
return "", errors.New("couldn't determine IP address for instance") return "", errors.New("couldn't determine address for instance")
} }
} }

View File

@ -9,9 +9,10 @@ import (
) )
const ( const (
privateIP = "10.0.0.1" privateIP = "10.0.0.1"
publicIP = "192.168.1.1" publicIP = "192.168.1.1"
publicDNS = "public.dns.test" privateDNS = "private.dns.test"
publicDNS = "public.dns.test"
) )
func TestSSHHost(t *testing.T) { func TestSSHHost(t *testing.T) {
@ -20,44 +21,54 @@ func TestSSHHost(t *testing.T) {
sshHostSleepDuration = 0 sshHostSleepDuration = 0
var cases = []struct { var cases = []struct {
allowTries int allowTries int
vpcId string vpcId string
private bool sshInterface string
ok bool ok bool
wantHost string wantHost string
}{ }{
{1, "", false, true, publicDNS}, {1, "", "", true, publicDNS},
{1, "", true, true, privateIP}, {1, "", "private_ip", true, privateIP},
{1, "vpc-id", false, true, publicIP}, {1, "vpc-id", "", true, publicIP},
{1, "vpc-id", true, true, privateIP}, {1, "vpc-id", "private_ip", true, privateIP},
{2, "", false, true, publicDNS}, {1, "vpc-id", "private_dns", true, privateDNS},
{2, "", true, true, privateIP}, {1, "vpc-id", "public_dns", true, publicDNS},
{2, "vpc-id", false, true, publicIP}, {1, "vpc-id", "public_ip", true, publicIP},
{2, "vpc-id", true, true, privateIP}, {2, "", "", true, publicDNS},
{3, "", false, false, ""}, {2, "", "private_ip", true, privateIP},
{3, "", true, false, ""}, {2, "vpc-id", "", true, publicIP},
{3, "vpc-id", false, false, ""}, {2, "vpc-id", "private_ip", true, privateIP},
{3, "vpc-id", true, false, ""}, {2, "vpc-id", "private_dns", true, privateDNS},
{2, "vpc-id", "public_dns", true, publicDNS},
{2, "vpc-id", "public_ip", true, publicIP},
{3, "", "", false, ""},
{3, "", "private_ip", false, ""},
{3, "vpc-id", "", false, ""},
{3, "vpc-id", "private_ip", false, ""},
{3, "vpc-id", "private_dns", false, ""},
{3, "vpc-id", "public_dns", false, ""},
{3, "vpc-id", "public_ip", false, ""},
} }
for _, c := range cases { for _, c := range cases {
testSSHHost(t, c.allowTries, c.vpcId, c.private, c.ok, c.wantHost) testSSHHost(t, c.allowTries, c.vpcId, c.sshInterface, c.ok, c.wantHost)
} }
} }
func testSSHHost(t *testing.T, allowTries int, vpcId string, private, ok bool, wantHost string) { func testSSHHost(t *testing.T, allowTries int, vpcId string, sshInterface string, ok bool, wantHost string) {
t.Logf("allowTries=%d vpcId=%s private=%t ok=%t wantHost=%q", allowTries, vpcId, private, ok, wantHost) t.Logf("allowTries=%d vpcId=%s sshInterface=%s ok=%t wantHost=%q", allowTries, vpcId, sshInterface, ok, wantHost)
e := &fakeEC2Describer{ e := &fakeEC2Describer{
allowTries: allowTries, allowTries: allowTries,
vpcId: vpcId, vpcId: vpcId,
privateIP: privateIP, privateIP: privateIP,
publicIP: publicIP, publicIP: publicIP,
privateDNS: privateDNS,
publicDNS: publicDNS, publicDNS: publicDNS,
} }
f := SSHHost(e, private) f := SSHHost(e, sshInterface)
st := &multistep.BasicStateBag{} st := &multistep.BasicStateBag{}
st.Put("instance", &ec2.Instance{ st.Put("instance", &ec2.Instance{
InstanceId: aws.String("instance-id"), InstanceId: aws.String("instance-id"),
@ -85,8 +96,8 @@ type fakeEC2Describer struct {
allowTries int allowTries int
tries int tries int
vpcId string vpcId string
privateIP, publicIP, publicDNS string privateIP, publicIP, privateDNS, publicDNS string
} }
func (d *fakeEC2Describer) DescribeInstances(in *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { func (d *fakeEC2Describer) DescribeInstances(in *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) {
@ -104,6 +115,7 @@ func (d *fakeEC2Describer) DescribeInstances(in *ec2.DescribeInstancesInput) (*e
instance.PublicIpAddress = aws.String(d.publicIP) instance.PublicIpAddress = aws.String(d.publicIP)
instance.PrivateIpAddress = aws.String(d.privateIP) instance.PrivateIpAddress = aws.String(d.privateIP)
instance.PublicDnsName = aws.String(d.publicDNS) instance.PublicDnsName = aws.String(d.publicDNS)
instance.PrivateDnsName = aws.String(d.privateDNS)
} }
out := &ec2.DescribeInstancesOutput{ out := &ec2.DescribeInstancesOutput{

View File

@ -193,7 +193,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm, Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost( Host: awscommon.SSHHost(
ec2conn, ec2conn,
b.config.SSHPrivateIp), b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig( SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth, b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername, b.config.RunConfig.Comm.SSHUsername,

View File

@ -204,7 +204,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm, Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost( Host: awscommon.SSHHost(
ec2conn, ec2conn,
b.config.SSHPrivateIp), b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig( SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth, b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername, b.config.RunConfig.Comm.SSHUsername,

View File

@ -181,7 +181,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm, Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost( Host: awscommon.SSHHost(
ec2conn, ec2conn,
b.config.SSHPrivateIp), b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig( SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth, b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername, b.config.RunConfig.Comm.SSHUsername,

View File

@ -268,7 +268,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm, Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost( Host: awscommon.SSHHost(
ec2conn, ec2conn,
b.config.SSHPrivateIp), b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig( SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth, b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername, b.config.RunConfig.Comm.SSHUsername,

View File

@ -328,8 +328,19 @@ builder.
in AWS with the source instance, set the `ssh_keypair_name` field to the name in AWS with the source instance, set the `ssh_keypair_name` field to the name
of the key pair. of the key pair.
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private - `ssh_private_ip` (boolean) - *Deprecated* use `ssh_interface` instead. If `true`,
IP if available. Also works for WinRM. then SSH will always use the private IP if available. Also works for WinRM.
- `ssh_interface` (string) - One of `public_ip`, `private_ip`,
`public_dns` or `private_dns`. If set, either the public IP address,
private IP address, public DNS name or private DNS name will used as the host for SSH.
The default behaviour if inside a VPC is to use the public IP address if available,
otherwise the private IP address will be used. If not in a VPC the public DNS name
will be used.
Where Packer is configured for an outbound proxy but WinRM traffic should be direct
`ssh_interface` must be set to `private_dns` and `<region>.compute.internal` included
in the `NO_PROXY` environment variable.
- `subnet_id` (string) - If using VPC, the ID of the subnet, such as - `subnet_id` (string) - If using VPC, the ID of the subnet, such as
`subnet-12345def`, where Packer will launch the EC2 instance. This field is `subnet-12345def`, where Packer will launch the EC2 instance. This field is

View File

@ -321,8 +321,19 @@ builder.
in AWS with the source instance, set the `ssh_keypair_name` field to the name in AWS with the source instance, set the `ssh_keypair_name` field to the name
of the key pair. of the key pair.
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private - `ssh_private_ip` (boolean) - *Deprecated* use `ssh_interface` instead. If `true`,
IP if available. then SSH will always use the private IP if available. Also works for WinRM.
- `ssh_interface` (string) - One of `public_ip`, `private_ip`,
`public_dns` or `private_dns`. If set, either the public IP address,
private IP address, public DNS name or private DNS name will used as the host for SSH.
The default behaviour if inside a VPC is to use the public IP address if available,
otherwise the private IP address will be used. If not in a VPC the public DNS name
will be used.
Where Packer is configured for an outbound proxy but WinRM traffic should be direct
`ssh_interface` must be set to `private_dns` and `<region>.compute.internal` included
in the `NO_PROXY` environment variable.
- `subnet_id` (string) - If using VPC, the ID of the subnet, such as - `subnet_id` (string) - If using VPC, the ID of the subnet, such as
`subnet-12345def`, where Packer will launch the EC2 instance. This field is `subnet-12345def`, where Packer will launch the EC2 instance. This field is

View File

@ -225,8 +225,19 @@ builder.
[`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file) [`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file)
must be specified with this. must be specified with this.
- `ssh_private_ip` (boolean) - If `true`, then SSH will always use the private - `ssh_private_ip` (boolean) - *Deprecated* use `ssh_interface` instead. If `true`,
IP if available. Also works for WinRM. then SSH will always use the private IP if available. Also works for WinRM.
- `ssh_interface` (string) - One of `public_ip`, `private_ip`,
`public_dns` or `private_dns`. If set, either the public IP address,
private IP address, public DNS name or private DNS name will used as the host for SSH.
The default behaviour if inside a VPC is to use the public IP address if available,
otherwise the private IP address will be used. If not in a VPC the public DNS name
will be used.
Where Packer is configured for an outbound proxy but WinRM traffic should be direct
`ssh_interface` must be set to `private_dns` and `<region>.compute.internal` included
in the `NO_PROXY` environment variable.
- `subnet_id` (string) - If using VPC, the ID of the subnet, such as - `subnet_id` (string) - If using VPC, the ID of the subnet, such as
`subnet-12345def`, where Packer will launch the EC2 instance. This field is `subnet-12345def`, where Packer will launch the EC2 instance. This field is

View File

@ -329,8 +329,19 @@ builder.
in AWS with the source instance, set the `ssh_keypair_name` field to the name in AWS with the source instance, set the `ssh_keypair_name` field to the name
of the key pair. of the key pair.
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private - `ssh_private_ip` (boolean) - *Deprecated* use `ssh_interface` instead. If `true`,
IP if available. Also works for WinRM. then SSH will always use the private IP if available. Also works for WinRM.
- `ssh_interface` (string) - One of `public_ip`, `private_ip`,
`public_dns` or `private_dns`. If set, either the public IP address,
private IP address, public DNS name or private DNS name will used as the host for SSH.
The default behaviour if inside a VPC is to use the public IP address if available,
otherwise the private IP address will be used. If not in a VPC the public DNS name
will be used.
Where Packer is configured for an outbound proxy but WinRM traffic should be direct
`ssh_interface` must be set to `private_dns` and `<region>.compute.internal` included
in the `NO_PROXY` environment variable.
- `subnet_id` (string) - If using VPC, the ID of the subnet, such as - `subnet_id` (string) - If using VPC, the ID of the subnet, such as
`subnet-12345def`, where Packer will launch the EC2 instance. This field is `subnet-12345def`, where Packer will launch the EC2 instance. This field is