From 4b80b04e854be2dfb1ba06152dd581ad7fbcd013 Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Fri, 22 Aug 2014 12:18:32 +1000 Subject: [PATCH] Add a sleep-loop to get the Docker daemon's tcp socket - the pid file isn't ready the first time we ask for it on one slower box I have --- cmds.go | 68 ++++++++++++++++++++++++++++++++++--------------- util.go | 79 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 87 insertions(+), 60 deletions(-) diff --git a/cmds.go b/cmds.go index 88a95eb..c9a1c30 100644 --- a/cmds.go +++ b/cmds.go @@ -40,34 +40,51 @@ func cmdUp() error { return fmt.Errorf("Failed to start machine %q (run again with -v for details)", B2D.VM) } - fmt.Println("Waiting for VM to be started...") + fmt.Println("Waiting for VM and Docker daemon to start...") //give the VM a little time to start, so we don't kill the Serial Pipe/Socket time.Sleep(600 * time.Millisecond) natSSH := fmt.Sprintf("localhost:%d", m.GetSSHPort()) IP := "" for i := 1; i < 30; i++ { + print(".") if B2D.Serial && runtime.GOOS != "windows" { - if IP = RequestIPFromSerialPort(m.GetSerialFile()); IP != "" { + if IP, err = RequestIPFromSerialPort(m.GetSerialFile()); err == nil { break } } - if err := read(natSSH, 1, 2*time.Second); err == nil { - IP = RequestIPFromSSH(m) - break + if err := read(natSSH, 1, 300*time.Millisecond); err == nil { + if IP, err = RequestIPFromSSH(m); err == nil { + break + } } + } + if B2D.Verbose { + fmt.Printf("VM Host-only IP address: %s", IP) + fmt.Printf("\nWaiting for Docker daemon to start...\n") + } + time.Sleep(300 * time.Millisecond) + socket := "" + for i := 1; i < 30; i++ { print(".") + if socket, err = RequestSocketFromSSH(m); err == nil { + break + } + if B2D.Verbose { + fmt.Printf("Error requesting socket: %s\n", err) + } + time.Sleep(300 * time.Millisecond) } - print("\n") + fmt.Printf("\nStarted.\n") - fmt.Printf("Started.\n") - - if IP == "" { + if socket == "" { // lets try one more time time.Sleep(600 * time.Millisecond) - fmt.Printf(" Trying to get IP one more time\n") + fmt.Printf(" Trying to get Docker socket one more time\n") - IP = RequestIPFromSSH(m) + if socket, err = RequestSocketFromSSH(m); err != nil { + fmt.Printf("Error requesting socket: %s\n", err) + } } // Copying the certs here - someone might have have written a Windows API client. certPath, err := RequestCertsUsingSSH(m) @@ -81,12 +98,11 @@ func cmdUp() error { fmt.Printf(" \"%s\" ssh\n", os.Args[0]) fmt.Printf("to SSH into the VM instead.\n") default: - if IP == "" { - fmt.Fprintf(os.Stderr, "Auto detection of the VM's IP address failed.\n") + if socket == "" { + fmt.Fprintf(os.Stderr, "Auto detection of the VM's Docker socket failed.\n") fmt.Fprintf(os.Stderr, "Please run `boot2docker -v up` to diagnose.\n") } else { // Check if $DOCKER_HOST ENV var is properly configured. - socket := RequestSocketFromSSH(m) if os.Getenv("DOCKER_HOST") != socket || os.Getenv("DOCKER_CERT_PATH") != certPath { fmt.Printf("\nTo connect the Docker client to the Docker daemon, please set:\n") printExport(socket, certPath) @@ -110,7 +126,10 @@ func cmdShellInit() error { return fmt.Errorf("VM %q is not running.", B2D.VM) } - socket := RequestSocketFromSSH(m) + socket, err := RequestSocketFromSSH(m) + if err != nil { + return fmt.Errorf("Error requesting socket: %s\n", err) + } certPath, err := RequestCertsUsingSSH(m) if err != nil && B2D.Verbose { @@ -270,7 +289,10 @@ func cmdSocket() error { return fmt.Errorf("VM %q is not running.", B2D.VM) } - socket := RequestSocketFromSSH(m) + socket, err := RequestSocketFromSSH(m) + if err != nil { + return fmt.Errorf("Error requesting socket: %s\n", err) + } fmt.Fprintf(os.Stderr, "\n\t export DOCKER_HOST=") fmt.Printf("%s", socket) @@ -316,17 +338,21 @@ func cmdIP() error { IP := "" if B2D.Serial { - for i := 1; i < 20; i++ { - if runtime.GOOS != "windows" { - if IP = RequestIPFromSerialPort(m.GetSerialFile()); IP != "" { - break + if runtime.GOOS != "windows" { + if IP, err = RequestIPFromSerialPort(m.GetSerialFile()); err != nil { + if B2D.Verbose { + fmt.Printf("Error getting IP via Serial: %s\n", err) } } } } if IP == "" { - IP = RequestIPFromSSH(m) + if IP, err = RequestIPFromSSH(m); err != nil { + if B2D.Verbose { + fmt.Printf("Error getting IP via SSH: %s\n", err) + } + } } if IP != "" { fmt.Fprintf(os.Stderr, "\nThe VM's Host only interface IP address is: ") diff --git a/util.go b/util.go index 4db14c6..5f89931 100644 --- a/util.go +++ b/util.go @@ -189,60 +189,62 @@ func getSSHCommand(m driver.Machine, args ...string) *exec.Cmd { return cmd } -func RequestIPFromSSH(m driver.Machine) string { +func RequestIPFromSSH(m driver.Machine) (string, error) { cmd := getSSHCommand(m, "ip addr show dev eth1") b, err := cmd.Output() - IP := "" if err != nil { - fmt.Printf("%s", err) - } else { - out := string(b) - if B2D.Verbose { - fmt.Printf("SSH returned: %s\nEND SSH\n", out) - } - // parse to find: inet 192.168.59.103/24 brd 192.168.59.255 scope global eth1 - lines := strings.Split(out, "\n") - for _, line := range lines { - vals := strings.Split(strings.TrimSpace(line), " ") - if len(vals) >= 2 && vals[0] == "inet" { - IP = vals[1][:strings.Index(vals[1], "/")] - break - } + return "", err + } + out := string(b) + if B2D.Verbose { + fmt.Printf("SSH returned: %s\nEND SSH\n", out) + } + // parse to find: inet 192.168.59.103/24 brd 192.168.59.255 scope global eth1 + lines := strings.Split(out, "\n") + for _, line := range lines { + vals := strings.Split(strings.TrimSpace(line), " ") + if len(vals) >= 2 && vals[0] == "inet" { + return vals[1][:strings.Index(vals[1], "/")], nil } } - return IP + + return "", fmt.Errorf("No IP address found %s", out) } -func RequestSocketFromSSH(m driver.Machine) string { +func RequestSocketFromSSH(m driver.Machine) (string, error) { cmd := getSSHCommand(m, "grep tcp:// /proc/$(cat /var/run/docker.pid)/cmdline") b, err := cmd.Output() if err != nil { - fmt.Printf("%s", err) - } else { - out := string(b) - if B2D.Verbose { - fmt.Printf("SSH returned: %s\nEND SSH\n", out) - } - // Lets only use the first one - its possible to specify more than one... - lines := strings.Split(out, "\n") - tcpRE := regexp.MustCompile(`^(tcp://)(0.0.0.0)(:.*)`) - if s := tcpRE.FindStringSubmatch(lines[0]); s != nil { - IP := RequestIPFromSSH(m) - return s[1] + IP + s[3] + return "", err + } + out := string(b) + if B2D.Verbose { + fmt.Printf("SSH returned: %s\nEND SSH\n", out) + } + // Lets only use the first one - its possible to specify more than one... + lines := strings.Split(out, "\n") + tcpRE := regexp.MustCompile(`^(tcp://)(0.0.0.0)(:.*)`) + if s := tcpRE.FindStringSubmatch(lines[0]); s != nil { + IP, err := RequestIPFromSSH(m) + if err != nil { + return "", err } - return lines[0] + return s[1] + IP + s[3], nil + } + if !strings.HasPrefix(lines[0], "tcp://") { + return "", fmt.Errorf("Error requesting Docker Socket: %s", lines[0]) } - return "" + return lines[0], nil } // use the serial port socket to ask what the VM's host only IP is -func RequestIPFromSerialPort(socket string) string { +func RequestIPFromSerialPort(socket string) (string, error) { c, err := net.Dial("unix", socket) if err != nil { - return "" + return "", err } defer c.Close() c.SetDeadline(time.Now().Add(time.Second)) @@ -257,15 +259,14 @@ func RequestIPFromSerialPort(socket string) string { for IP == "" { _, err := c.Write([]byte("ip addr show dev eth1\r")) if err != nil { - println(err) - break + return "", err } time.Sleep(1 * time.Second) buf := make([]byte, 1024) for { n, err := c.Read(buf[:]) if err != nil { - return IP + return "", err } line = line + string(buf[0:n]) fullLog += string(buf[0:n]) @@ -293,11 +294,11 @@ func RequestIPFromSerialPort(socket string) string { fmt.Printf(fullLog) } - return IP + return IP, nil } // TODO: need to add or abstract to get a Serial coms version -// RequestCertsUsingSSH requests certs using SSH. +// RequestCertsUsingSSH requests certs using SSH. // The assumption is that if the certs are in b2d:/home/docker/.docker // then the daemon is using TLS. We can't assume that because there are // certs in the local host's user dir, that the server is using them, so