diff --git a/libmachine/engine/engine.go b/libmachine/engine/engine.go index 6ce2106b44..2910432c19 100644 --- a/libmachine/engine/engine.go +++ b/libmachine/engine/engine.go @@ -1,5 +1,9 @@ package engine +const ( + DefaultPort = 2376 +) + type Options struct { ArbitraryFlags []string DNS []string `json:"Dns"` diff --git a/libmachine/host/host.go b/libmachine/host/host.go index d894e175e9..18526c1cf2 100644 --- a/libmachine/host/host.go +++ b/libmachine/host/host.go @@ -111,6 +111,17 @@ func (h *Host) Start() error { } log.Infof("Machine %q was started.", h.Name) + + provisioner, err := provision.DetectProvisioner(h.Driver) + if err != nil { + return err + } + + // TODO: Migrate away from using hardcoded daemon port. + if err := provision.WaitForDocker(provisioner, engine.DefaultPort); err != nil { + return err + } + return nil } diff --git a/libmachine/host/host_test.go b/libmachine/host/host_test.go index 746a4ca0e2..e1bc716f91 100644 --- a/libmachine/host/host_test.go +++ b/libmachine/host/host_test.go @@ -3,7 +3,10 @@ package host import ( "testing" + "github.com/docker/machine/drivers/fakedriver" _ "github.com/docker/machine/drivers/none" + "github.com/docker/machine/libmachine/provision" + "github.com/docker/machine/libmachine/state" ) func TestValidateHostnameValid(t *testing.T) { @@ -35,3 +38,47 @@ func TestValidateHostnameInvalid(t *testing.T) { } } } + +type NetstatProvisioner struct { + *provision.FakeProvisioner +} + +func (p *NetstatProvisioner) SSHCommand(args string) (string, error) { + return `Active Internet connections (servers and established) +Proto Recv-Q Send-Q Local Address Foreign Address State +tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN +tcp 0 72 192.168.25.141:ssh 192.168.25.1:63235 ESTABLISHED +tcp 0 0 :::2376 :::* LISTEN +tcp 0 0 :::ssh :::* LISTEN +Active UNIX domain sockets (servers and established) +Proto RefCnt Flags Type State I-Node Path +unix 2 [ ACC ] STREAM LISTENING 17990 /var/run/acpid.socket +unix 2 [ ACC ] SEQPACKET LISTENING 14233 /run/udev/control +unix 2 [ ACC ] STREAM LISTENING 19365 /var/run/docker.sock +unix 3 [ ] STREAM CONNECTED 19774 +unix 3 [ ] STREAM CONNECTED 19775 +unix 3 [ ] DGRAM 14243 +unix 3 [ ] DGRAM 14242`, nil +} + +func NewNetstatProvisioner() provision.Provisioner { + return &NetstatProvisioner{ + &provision.FakeProvisioner{}, + } +} + +func TestStart(t *testing.T) { + provision.SetDetector(&provision.FakeDetector{ + NewNetstatProvisioner(), + }) + + host := &Host{ + Driver: &fakedriver.Driver{ + MockState: state.Stopped, + }, + } + + if err := host.Start(); err != nil { + t.Fatalf("Expected no error but got one: %s", err) + } +} diff --git a/libmachine/provision/boot2docker.go b/libmachine/provision/boot2docker.go index ddf54d4481..442a6b62c2 100644 --- a/libmachine/provision/boot2docker.go +++ b/libmachine/provision/boot2docker.go @@ -194,35 +194,31 @@ func (provisioner *Boot2DockerProvisioner) AttemptIPContact(dockerPort int) { } if conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, dockerPort), 5*time.Second); err != nil { - log.Warn(` + log.Warnf(` This machine has been allocated an IP address, but Docker Machine could not reach it successfully. SSH for the machine should still work, but connecting to exposed ports, such as -the Docker daemon port (usually :2376), may not work properly. +the Docker daemon port (usually :%d), may not work properly. You may need to add the route manually, or use another related workaround. This could be due to a VPN, proxy, or host file configuration issue. -You also might want to clear any VirtualBox host only interfaces you are not using.`) +You also might want to clear any VirtualBox host only interfaces you are not using.`, engine.DefaultPort) } else { conn.Close() } } func (provisioner *Boot2DockerProvisioner) Provision(swarmOptions swarm.Options, authOptions auth.Options, engineOptions engine.Options) error { - const ( - dockerPort = 2376 - ) - var ( err error ) defer func() { if err == nil { - provisioner.AttemptIPContact(dockerPort) + provisioner.AttemptIPContact(engine.DefaultPort) } }() @@ -241,7 +237,7 @@ func (provisioner *Boot2DockerProvisioner) Provision(swarmOptions swarm.Options, // b2d hosts need to wait for the daemon to be up // before continuing with provisioning - if err = waitForDocker(provisioner, dockerPort); err != nil { + if err = WaitForDocker(provisioner, engine.DefaultPort); err != nil { return err } diff --git a/libmachine/provision/utils.go b/libmachine/provision/utils.go index 57b52324d6..8f17cb4c5a 100644 --- a/libmachine/provision/utils.go +++ b/libmachine/provision/utils.go @@ -13,6 +13,7 @@ import ( "github.com/docker/machine/libmachine/auth" "github.com/docker/machine/libmachine/cert" + "github.com/docker/machine/libmachine/engine" "github.com/docker/machine/libmachine/log" "github.com/docker/machine/libmachine/mcnutils" "github.com/docker/machine/libmachine/provision/serviceaction" @@ -161,7 +162,7 @@ func ConfigureAuth(p Provisioner) error { if err != nil { return err } - dockerPort := 2376 + dockerPort := engine.DefaultPort parts := strings.Split(u.Host, ":") if len(parts) == 2 { dPort, err := strconv.Atoi(parts[1]) @@ -186,7 +187,7 @@ func ConfigureAuth(p Provisioner) error { return err } - return waitForDocker(p, dockerPort) + return WaitForDocker(p, dockerPort) } func matchNetstatOut(reDaemonListening, netstatOut string) bool { @@ -262,7 +263,7 @@ func checkDaemonUp(p Provisioner, dockerPort int) func() bool { } } -func waitForDocker(p Provisioner, dockerPort int) error { +func WaitForDocker(p Provisioner, dockerPort int) error { if err := mcnutils.WaitForSpecific(checkDaemonUp(p, dockerPort), 10, 3*time.Second); err != nil { return NewErrDaemonAvailable(err) } diff --git a/libmachine/provision/utils_test.go b/libmachine/provision/utils_test.go index 78484dbc12..c6f73e7f36 100644 --- a/libmachine/provision/utils_test.go +++ b/libmachine/provision/utils_test.go @@ -102,7 +102,7 @@ func TestMachinePortBoot2Docker(t *testing.T) { p := &Boot2DockerProvisioner{ Driver: &fakedriver.Driver{}, } - dockerPort := 2376 + dockerPort := engine.DefaultPort bindURL := fmt.Sprintf("tcp://0.0.0.0:%d", dockerPort) p.AuthOptions = auth.Options{ CaCertRemotePath: "/test/ca-cert",