func (d *ESX5Driver) connect() error { address := fmt.Sprintf("%s:%d", d.Host, d.Port) auth := []gossh.ClientAuth{ gossh.ClientAuthPassword(ssh.Password(d.Password)), gossh.ClientAuthKeyboardInteractive( ssh.PasswordKeyboardInteractive(d.Password)), } // TODO(dougm) KeyPath support sshConfig := &ssh.Config{ Connection: ssh.ConnectFunc("tcp", address), SSHConfig: &gossh.ClientConfig{ User: d.Username, Auth: auth, }, NoPty: true, } comm, err := ssh.New(sshConfig) if err != nil { return err } d.comm = comm return nil }
func sshConfig(state map[string]interface{}) (*gossh.ClientConfig, error) { config := state["config"].(*config) return &gossh.ClientConfig{ User: config.SSHUser, Auth: []gossh.ClientAuth{ gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.ClientAuthKeyboardInteractive( ssh.PasswordKeyboardInteractive(config.SSHPassword)), }, }, nil }
func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) { return func(state multistep.StateBag) (*gossh.ClientConfig, error) { auth := []gossh.ClientAuth{ gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.ClientAuthKeyboardInteractive( ssh.PasswordKeyboardInteractive(config.SSHPassword)), } if config.SSHKeyPath != "" { keyring, err := sshKeyToKeyring(config.SSHKeyPath) if err != nil { return nil, err } auth = append(auth, gossh.ClientAuthKeyring(keyring)) } return &gossh.ClientConfig{ User: config.SSHUser, Auth: auth, }, nil } }
func sshConfig(state map[string]interface{}) (*gossh.ClientConfig, error) { config := state["config"].(*config) auth := []gossh.ClientAuth{ gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.ClientAuthKeyboardInteractive( ssh.PasswordKeyboardInteractive(config.SSHPassword)), } if config.SSHKeyPath != "" { keyring, err := sshKeyToKeyring(config.SSHKeyPath) if err != nil { return nil, err } auth = append(auth, gossh.ClientAuthKeyring(keyring)) } return &gossh.ClientConfig{ User: config.SSHUser, Auth: auth, }, nil }
// SSHConfig returns a function that can be used for the SSH communicator // config for connecting to the specified host via SSH // private_key_file has precedence over password! func SSHConfig(username string, password string, privateKeyFile string) func(multistep.StateBag) (*gossh.ClientConfig, error) { return func(state multistep.StateBag) (*gossh.ClientConfig, error) { if privateKeyFile != "" { // key based auth bytes, err := ioutil.ReadFile(privateKeyFile) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } privateKey := string(bytes) keyring := new(ssh.SimpleKeychain) if err := keyring.AddPEMKey(privateKey); err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } return &gossh.ClientConfig{ User: username, Auth: []gossh.ClientAuth{ gossh.ClientAuthKeyring(keyring), }, }, nil } else { // password based auth return &gossh.ClientConfig{ User: username, Auth: []gossh.ClientAuth{ gossh.ClientAuthPassword(ssh.Password(password)), gossh.ClientAuthKeyboardInteractive(ssh.PasswordKeyboardInteractive(password)), }, }, nil } } }
// This blocks until SSH becomes available, and sends the communicator // on the given channel. func (s *stepWaitForSSH) waitForSSH(state map[string]interface{}) (packer.Communicator, error) { config := state["config"].(*config) ui := state["ui"].(packer.Ui) sshHostPort := state["sshHostPort"].(uint) ui.Say("Waiting for SSH to become available...") var comm packer.Communicator var nc net.Conn for { if nc != nil { nc.Close() } time.Sleep(5 * time.Second) if s.cancel { log.Println("SSH wait cancelled. Exiting loop.") return nil, errors.New("SSH wait cancelled") } // Attempt to connect to SSH port nc, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", sshHostPort)) if err != nil { log.Printf("TCP connection to SSH ip/port failed: %s", err) continue } // Then we attempt to connect via SSH sshConfig := &gossh.ClientConfig{ User: config.SSHUser, Auth: []gossh.ClientAuth{ gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.ClientAuthKeyboardInteractive( ssh.PasswordKeyboardInteractive(config.SSHPassword)), }, } sshConnectSuccess := make(chan bool, 1) go func() { comm, err = ssh.New(nc, sshConfig) if err != nil { log.Printf("SSH connection fail: %s", err) sshConnectSuccess <- false return } sshConnectSuccess <- true }() select { case success := <-sshConnectSuccess: if !success { continue } case <-time.After(5 * time.Second): log.Printf("SSH handshake timeout. Trying again.") continue } ui.Say("Connected via SSH!") break } // Store the connection so we can close it later s.conn = nc return comm, nil }
// This blocks until SSH becomes available, and sends the communicator // on the given channel. func (s *stepWaitForSSH) waitForSSH(state map[string]interface{}) (packer.Communicator, error) { config := state["config"].(*config) ui := state["ui"].(packer.Ui) vmxPath := state["vmx_path"].(string) handshakeAttempts := 0 ui.Say("Waiting for SSH to become available...") var comm packer.Communicator for { time.Sleep(5 * time.Second) if s.cancel { log.Println("SSH wait cancelled. Exiting loop.") return nil, errors.New("SSH wait cancelled") } // First we wait for the IP to become available... log.Println("Lookup up IP information...") ipLookup, err := s.dhcpLeaseLookup(vmxPath) if err != nil { log.Printf("Can't lookup via DHCP lease: %s", err) } ip, err := ipLookup.GuestIP() if err != nil { log.Printf("IP lookup failed: %s", err) continue } log.Printf("Detected IP: %s", ip) // Attempt to connect to SSH port connFunc := ssh.ConnectFunc( "tcp", fmt.Sprintf("%s:%d", ip, config.SSHPort), 5*time.Minute) nc, err := connFunc() if err != nil { log.Printf("TCP connection to SSH ip/port failed: %s", err) continue } nc.Close() // Then we attempt to connect via SSH config := &ssh.Config{ Connection: connFunc, SSHConfig: &gossh.ClientConfig{ User: config.SSHUser, Auth: []gossh.ClientAuth{ gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.ClientAuthKeyboardInteractive( ssh.PasswordKeyboardInteractive(config.SSHPassword)), }, }, } comm, err = ssh.New(config) if err != nil { log.Printf("SSH handshake err: %s", err) handshakeAttempts += 1 if handshakeAttempts < 10 { // Try to connect via SSH a handful of times continue } return nil, err } ui.Say("Connected via SSH!") break } return comm, nil }