Fix issue where GetIP failes due to no SSH

The main goal of this patch was to make the VirtualBox driver wait for
SSH before trying to get the IP of the VM.  The generic WaitForSSH
method required a Host struct as an arg.  This patch moves most of the
logic to the driver package so that drivers can call WaitForSSH.  The
existing functions in host are just wrappers to the real
implementation in drivers now.

Signed-off-by: Darren Shepherd <darren@rancher.com>
This commit is contained in:
Darren Shepherd 2015-05-04 16:17:09 -07:00
parent e4b6ff1ae9
commit 8afe967a80
5 changed files with 84 additions and 85 deletions

View File

@ -8,7 +8,6 @@ import (
"github.com/codegangsta/cli"
"github.com/docker/machine/log"
"github.com/docker/machine/provider"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
)
@ -173,34 +172,6 @@ type DriverOptions interface {
Bool(key string) bool
}
func RunSSHCommandFromDriver(d Driver, args string) (ssh.Output, error) {
var output ssh.Output
host, err := d.GetSSHHostname()
if err != nil {
return output, err
}
port, err := d.GetSSHPort()
if err != nil {
return output, err
}
user := d.GetSSHUsername()
keyPath := d.GetSSHKeyPath()
auth := &ssh.Auth{
Keys: []string{keyPath},
}
client, err := ssh.NewClient(user, host, port, auth)
if err != nil {
return output, err
}
return client.Run(args)
}
func MachineInState(d Driver, desiredState state.State) func() bool {
return func() bool {
currentState, err := d.GetState()

67
drivers/utils.go Normal file
View File

@ -0,0 +1,67 @@
package drivers
import (
"fmt"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/utils"
)
func RunSSHCommandFromDriver(d Driver, command string) (ssh.Output, error) {
var output ssh.Output
addr, err := d.GetSSHHostname()
if err != nil {
return output, err
}
port, err := d.GetSSHPort()
if err != nil {
return output, err
}
auth := &ssh.Auth{
Keys: []string{d.GetSSHKeyPath()},
}
client, err := ssh.NewClient(d.GetSSHUsername(), addr, port, auth)
if err != nil {
return output, err
}
return client.Run(command)
}
func sshAvailableFunc(d Driver) func() bool {
return func() bool {
log.Debug("Getting to WaitForSSH function...")
hostname, err := d.GetSSHHostname()
if err != nil {
log.Debugf("Error getting IP address waiting for SSH: %s", err)
return false
}
port, err := d.GetSSHPort()
if err != nil {
log.Debugf("Error getting SSH port: %s", err)
return false
}
if err := ssh.WaitForTCP(fmt.Sprintf("%s:%d", hostname, port)); err != nil {
log.Debugf("Error waiting for TCP waiting for SSH: %s", err)
return false
}
if _, err := RunSSHCommandFromDriver(d, "exit 0"); err != nil {
log.Debugf("Error getting ssh command 'exit 0' : %s", err)
return false
}
return true
}
}
func WaitForSSH(d Driver) error {
if err := utils.WaitFor(sshAvailableFunc(d)); err != nil {
return fmt.Errorf("Too many retries. Last error: %s", err)
}
return nil
}

View File

@ -393,6 +393,10 @@ func (d *Driver) Start() error {
log.Infof("VM not in restartable state")
}
if err := drivers.WaitForSSH(d); err != nil {
return err
}
d.IPAddress, err = d.GetIP()
return err
}

View File

@ -136,25 +136,7 @@ func (h *Host) Create(name string) error {
}
func (h *Host) RunSSHCommand(command string) (ssh.Output, error) {
var output ssh.Output
addr, err := h.Driver.GetSSHHostname()
if err != nil {
return output, err
}
port, err := h.Driver.GetSSHPort()
if err != nil {
return output, err
}
auth := &ssh.Auth{
Keys: []string{h.Driver.GetSSHKeyPath()},
}
client, err := ssh.NewClient(h.Driver.GetSSHUsername(), addr, port, auth)
return client.Run(command)
return drivers.RunSSHCommandFromDriver(h.Driver, command)
}
func (h *Host) CreateSSHShell() error {
@ -352,37 +334,8 @@ func (h *Host) PrintIP() error {
return nil
}
func sshAvailableFunc(h *Host) func() bool {
return func() bool {
log.Debug("Getting to WaitForSSH function...")
hostname, err := h.Driver.GetSSHHostname()
if err != nil {
log.Debugf("Error getting IP address waiting for SSH: %s", err)
return false
}
port, err := h.Driver.GetSSHPort()
if err != nil {
log.Debugf("Error getting SSH port: %s", err)
return false
}
if err := ssh.WaitForTCP(fmt.Sprintf("%s:%d", hostname, port)); err != nil {
log.Debugf("Error waiting for TCP waiting for SSH: %s", err)
return false
}
if _, err := h.RunSSHCommand("exit 0"); err != nil {
log.Debugf("Error getting ssh command 'exit 0' : %s", err)
return false
}
return true
}
}
func WaitForSSH(h *Host) error {
if err := utils.WaitFor(sshAvailableFunc(h)); err != nil {
return fmt.Errorf("Too many retries. Last error: %s", err)
}
return nil
return drivers.WaitForSSH(h.Driver)
}
func getHostState(host Host, hostListItemsChan chan<- HostListItem) {

View File

@ -1,18 +1,22 @@
package ssh
import "net"
import (
"net"
"time"
"github.com/docker/machine/log"
)
func WaitForTCP(addr string) error {
for {
conn, err := net.Dial("tcp", addr)
log.Debugf("Testing TCP connection to: %s", addr)
conn, err := net.DialTimeout("tcp", addr, 2*time.Second)
if err != nil {
continue
}
defer conn.Close()
if _, err = conn.Read(make([]byte, 1)); err != nil {
continue
}
break
return nil
}
return nil
}