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