github.com/kimor79/packer@v0.8.7-0.20151221212622-d507b18eb4cf/builder/openstack/ssh.go (about) 1 package openstack 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "time" 8 9 "github.com/mitchellh/multistep" 10 "github.com/rackspace/gophercloud" 11 "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip" 12 "github.com/rackspace/gophercloud/openstack/compute/v2/servers" 13 "golang.org/x/crypto/ssh" 14 ) 15 16 // CommHost looks up the host for the communicator. 17 func CommHost( 18 client *gophercloud.ServiceClient, 19 sshinterface string) func(multistep.StateBag) (string, error) { 20 return func(state multistep.StateBag) (string, error) { 21 s := state.Get("server").(*servers.Server) 22 23 // If we have a specific interface, try that 24 if sshinterface != "" { 25 if addr := sshAddrFromPool(s, sshinterface); addr != "" { 26 log.Printf("[DEBUG] Using IP address %s from specified interface %s for SSH", addr, sshinterface) 27 return addr, nil 28 } 29 } 30 31 // If we have a floating IP, use that 32 ip := state.Get("access_ip").(*floatingip.FloatingIP) 33 if ip != nil && ip.IP != "" { 34 log.Printf("[DEBUG] Using floating IP %s for SSH", ip.IP) 35 return ip.IP, nil 36 } 37 38 if s.AccessIPv4 != "" { 39 log.Printf("[DEBUG] Using AccessIPv4 %s for SSH", s.AccessIPv4) 40 return s.AccessIPv4, nil 41 } 42 43 // Try to get it from the requested interface 44 if addr := sshAddrFromPool(s, sshinterface); addr != "" { 45 log.Printf("[DEBUG] Using IP address %s for SSH", addr) 46 return addr, nil 47 } 48 49 s, err := servers.Get(client, s.ID).Extract() 50 if err != nil { 51 return "", err 52 } 53 54 state.Put("server", s) 55 time.Sleep(1 * time.Second) 56 57 return "", errors.New("couldn't determine IP address for server") 58 } 59 } 60 61 // SSHConfig returns a function that can be used for the SSH communicator 62 // config for connecting to the instance created over SSH using the generated 63 // private key. 64 func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, error) { 65 return func(state multistep.StateBag) (*ssh.ClientConfig, error) { 66 privateKey := state.Get("privateKey").(string) 67 68 signer, err := ssh.ParsePrivateKey([]byte(privateKey)) 69 if err != nil { 70 return nil, fmt.Errorf("Error setting up SSH config: %s", err) 71 } 72 73 return &ssh.ClientConfig{ 74 User: username, 75 Auth: []ssh.AuthMethod{ 76 ssh.PublicKeys(signer), 77 }, 78 }, nil 79 } 80 } 81 82 func sshAddrFromPool(s *servers.Server, desired string) string { 83 // Get all the addresses associated with this server. This 84 // was taken directly from Terraform. 85 for pool, networkAddresses := range s.Addresses { 86 // If we have an SSH interface specified, skip it if no match 87 if desired != "" && pool != desired { 88 log.Printf( 89 "[INFO] Skipping pool %s, doesn't match requested %s", 90 pool, desired) 91 continue 92 } 93 94 elements, ok := networkAddresses.([]interface{}) 95 if !ok { 96 log.Printf( 97 "[ERROR] Unknown return type for address field: %#v", 98 networkAddresses) 99 continue 100 } 101 102 for _, element := range elements { 103 var addr string 104 address := element.(map[string]interface{}) 105 if address["OS-EXT-IPS:type"] == "floating" { 106 addr = address["addr"].(string) 107 } else { 108 if address["version"].(float64) == 6 { 109 addr = fmt.Sprintf("[%s]", address["addr"].(string)) 110 } else { 111 addr = address["addr"].(string) 112 } 113 } 114 115 if addr != "" { 116 log.Printf("[DEBUG] Detected address: %s", addr) 117 return addr 118 } 119 } 120 } 121 122 return "" 123 }