github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/common/ssh.go (about)

     1  package common
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/aws/aws-sdk-go/service/ec2"
     9  	"github.com/hashicorp/packer/helper/multistep"
    10  )
    11  
    12  type ec2Describer interface {
    13  	DescribeInstances(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error)
    14  }
    15  
    16  var (
    17  	// modified in tests
    18  	sshHostSleepDuration = time.Second
    19  )
    20  
    21  // SSHHost returns a function that can be given to the SSH communicator
    22  // for determining the SSH address based on the instance DNS name.
    23  func SSHHost(e ec2Describer, sshInterface string) func(multistep.StateBag) (string, error) {
    24  	return func(state multistep.StateBag) (string, error) {
    25  		const tries = 2
    26  		// <= with current structure to check result of describing `tries` times
    27  		for j := 0; j <= tries; j++ {
    28  			var host string
    29  			i := state.Get("instance").(*ec2.Instance)
    30  			if sshInterface != "" {
    31  				switch sshInterface {
    32  				case "public_ip":
    33  					if i.PublicIpAddress != nil {
    34  						host = *i.PublicIpAddress
    35  					}
    36  				case "private_ip":
    37  					if i.PrivateIpAddress != nil {
    38  						host = *i.PrivateIpAddress
    39  					}
    40  				case "public_dns":
    41  					if i.PublicDnsName != nil {
    42  						host = *i.PublicDnsName
    43  					}
    44  				case "private_dns":
    45  					if i.PrivateDnsName != nil {
    46  						host = *i.PrivateDnsName
    47  					}
    48  				default:
    49  					panic(fmt.Sprintf("Unknown interface type: %s", sshInterface))
    50  				}
    51  			} else if i.VpcId != nil && *i.VpcId != "" {
    52  				if i.PublicIpAddress != nil && *i.PublicIpAddress != "" {
    53  					host = *i.PublicIpAddress
    54  				} else if i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" {
    55  					host = *i.PrivateIpAddress
    56  				}
    57  			} else if i.PublicDnsName != nil && *i.PublicDnsName != "" {
    58  				host = *i.PublicDnsName
    59  			}
    60  
    61  			if host != "" {
    62  				return host, nil
    63  			}
    64  
    65  			r, err := e.DescribeInstances(&ec2.DescribeInstancesInput{
    66  				InstanceIds: []*string{i.InstanceId},
    67  			})
    68  			if err != nil {
    69  				return "", err
    70  			}
    71  
    72  			if len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 {
    73  				return "", fmt.Errorf("instance not found: %s", *i.InstanceId)
    74  			}
    75  
    76  			state.Put("instance", r.Reservations[0].Instances[0])
    77  			time.Sleep(sshHostSleepDuration)
    78  		}
    79  
    80  		return "", errors.New("couldn't determine address for instance")
    81  	}
    82  }