package wol import ( "context" "fmt" "net" "os/exec" "time" ) var ErrTimeout = fmt.Errorf("timeout waiting for machine to respond") func WaitUntilReady(ctx context.Context, host string, sshPort int, maxWait, checkInterval time.Duration, usePing bool) error { deadline := time.Now().Add(maxWait) interval := checkInterval ticker := time.NewTicker(checkInterval) defer ticker.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-ticker.C: } addr := fmt.Sprintf("%s:%d", host, sshPort) dialer := net.Dialer{Timeout: 3 * time.Second} conn, err := dialer.DialContext(ctx, "tcp", addr) if err == nil { conn.Close() return nil } if usePing { cmd := exec.CommandContext(ctx, "ping", "-c", "1", "-W", "1", host) if err := cmd.Run(); err == nil { return nil } } if time.Now().After(deadline) { return ErrTimeout } elapsed := time.Since(time.Now().Add(-maxWait)) if elapsed > maxWait/2 && interval < 10*time.Second { interval = interval * 3 / 2 if interval > 10*time.Second { interval = 10 * time.Second } ticker.Reset(interval) } } } func IsHostReachable(host string, port int, timeout time.Duration) bool { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() addr := fmt.Sprintf("%s:%d", host, port) dialer := net.Dialer{Timeout: timeout} conn, err := dialer.DialContext(ctx, "tcp", addr) if err == nil { conn.Close() return true } return false }