From b2efff6d5942fd728a0f4d2bf6d71702511b07ed Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 17 Apr 2020 11:44:04 -0700 Subject: [PATCH 1/2] Make resolver file world-readable, improve logging and errors --- pkg/minikube/tunnel/route_darwin.go | 54 +++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/pkg/minikube/tunnel/route_darwin.go b/pkg/minikube/tunnel/route_darwin.go index 0e2f5064ff28..6adcfb5701b5 100644 --- a/pkg/minikube/tunnel/route_darwin.go +++ b/pkg/minikube/tunnel/route_darwin.go @@ -22,10 +22,12 @@ import ( "net" "os" "os/exec" + "path/filepath" "regexp" "strings" "github.com/golang/glog" + "github.com/pkg/errors" ) func (router *osRouter) EnsureRouteIsAdded(route *Route) error { @@ -37,7 +39,7 @@ func (router *osRouter) EnsureRouteIsAdded(route *Route) error { return nil } if err := writeResolverFile(route); err != nil { - return fmt.Errorf("could not write /etc/resolver/{cluster_domain} file: %s", err) + glog.Errorf("DNS forwarding unavailable: %v", err) } serviceCIDR := route.DestCIDR.String() @@ -178,26 +180,48 @@ func (router *osRouter) Cleanup(route *Route) error { func writeResolverFile(route *Route) error { resolverFile := "/etc/resolver/" + route.ClusterDomain + content := fmt.Sprintf("nameserver %s\nsearch_order 1\n", route.ClusterDNSIP) - // write resolver content into tmpFile, then copy it to /etc/resolver/clusterDomain - tmpFile, err := ioutil.TempFile("", "minikube-tunnel-resolver-") + + glog.Infof("preparing DNS forwarding config in %q:\n%s", resolverFile, content) + + // write resolver content into tf, then copy it to /etc/resolver/clusterDomain + tf, err := ioutil.TempFile("", "minikube-tunnel-resolver-") if err != nil { - return err + return errors.Wrap(err, "tempfile") } - defer os.Remove(tmpFile.Name()) - if _, err = tmpFile.WriteString(content); err != nil { - return err + defer os.Remove(tf.Name()) + + if _, err = tf.WriteString(content); err != nil { + return errors.Wrap(err, "write") } - if err = tmpFile.Close(); err != nil { - return err + + if err = tf.Close(); err != nil { + return errors.Wrap(err, "close") } - cmd := exec.Command("sudo", "mkdir", "-p", "/etc/resolver") - if err := cmd.Run(); err != nil { - return err + + if err = os.Chmod(tf.Name(), 0644); err != nil { + return errors.Wrap(err, "chmod") } - cmd = exec.Command("sudo", "cp", "-f", tmpFile.Name(), resolverFile) - if err := cmd.Run(); err != nil { - return err + + cmd := exec.Command("sudo", "mkdir", "-p", filepath.Dir(resolverFile)) + _, err = cmd.Output() + if err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + return fmt.Errorf("%q failed: %v: %q", strings.Join(cmd.Args, " "), exitErr, exitErr.Stderr) + } + return errors.Wrap(err, "mkdir") + } + + cmd = exec.Command("sudo", "cp", "-fp", tf.Name(), resolverFile) + + _, err = cmd.Output() + if err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + return fmt.Errorf("%q failed: %v: %q", strings.Join(cmd.Args, " "), exitErr, exitErr.Stderr) + } + return errors.Wrap(err, "copy") } + glog.Infof("DNS forwarding now configured in %q", resolverFile) return nil } From e7f08ee7a65816065e29f3878b875b1ec2de07da Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 17 Apr 2020 11:44:32 -0700 Subject: [PATCH 2/2] Add DNS forwarding to tunnel integration tests, make it work on macOS --- test/integration/fn_tunnel_cmd.go | 41 +++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/test/integration/fn_tunnel_cmd.go b/test/integration/fn_tunnel_cmd.go index 8f43a9a5fdb8..75f282cae0b4 100644 --- a/test/integration/fn_tunnel_cmd.go +++ b/test/integration/fn_tunnel_cmd.go @@ -41,9 +41,8 @@ func validateTunnelCmd(ctx context.Context, t *testing.T, profile string) { ctx, cancel := context.WithTimeout(ctx, Minutes(20)) defer cancel() - if runtime.GOOS != "windows" { - // Otherwise minikube fails waiting for a password. - if err := exec.Command("sudo", "-n", "route").Run(); err != nil { + if !KicDriver() && runtime.GOOS != "windows" { + if err := exec.Command("sudo", "-n", "ifconfig").Run(); err != nil { t.Skipf("password required to execute 'route', skipping testTunnel: %v", err) } } @@ -59,7 +58,7 @@ func validateTunnelCmd(ctx context.Context, t *testing.T, profile string) { } // Start the tunnel - args := []string{"-p", profile, "tunnel", "--alsologtostderr", "-v=1"} + args := []string{"-p", profile, "tunnel", "--alsologtostderr"} ss, err := Start(t, exec.CommandContext(ctx, Target(), args...)) if err != nil { t.Errorf("failed to start a tunnel: args %q: %v", args, err) @@ -80,14 +79,14 @@ func validateTunnelCmd(ctx context.Context, t *testing.T, profile string) { } // Wait until the nginx-svc has a loadbalancer ingress IP - nginxIP := "" - err = wait.PollImmediate(1*time.Second, Minutes(3), func() (bool, error) { + hostname := "" + err = wait.PollImmediate(5*time.Second, Minutes(3), func() (bool, error) { rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "get", "svc", "nginx-svc", "-o", "jsonpath={.status.loadBalancer.ingress[0].ip}")) if err != nil { return false, err } if len(rr.Stdout.String()) > 0 { - nginxIP = rr.Stdout.String() + hostname = rr.Stdout.String() return true, nil } return false, nil @@ -103,9 +102,11 @@ func validateTunnelCmd(ctx context.Context, t *testing.T, profile string) { } got := []byte{} + url := fmt.Sprintf("http://%s", hostname) + fetch := func() error { h := &http.Client{Timeout: time.Second * 10} - resp, err := h.Get(fmt.Sprintf("http://%s", nginxIP)) + resp, err := h.Get(url) if err != nil { return &retry.RetriableError{Err: err} } @@ -119,12 +120,32 @@ func validateTunnelCmd(ctx context.Context, t *testing.T, profile string) { } return nil } - if err = retry.Expo(fetch, time.Millisecond*500, Minutes(2), 13); err != nil { - t.Errorf("failed to hit nginx at %q: %v", nginxIP, err) + if err = retry.Expo(fetch, 3*time.Second, Minutes(2), 13); err != nil { + t.Errorf("failed to hit nginx at %q: %v", url, err) } want := "Welcome to nginx!" if !strings.Contains(string(got), want) { t.Errorf("expected body to contain %q, but got *%q*", want, got) + } else { + t.Logf("tunnel at %s is working!", url) + } + + // Not all platforms support DNS forwarding + if runtime.GOOS != "darwin" { + return + } + + url = "http://nginx-svc.default.svc.cluster.local" + if err = retry.Expo(fetch, 3*time.Second, Seconds(30), 10); err != nil { + t.Errorf("failed to hit nginx with DNS forwarded %q: %v", url, err) + } + + want = "Welcome to nginx!" + if !strings.Contains(string(got), want) { + t.Errorf("expected body to contain %q, but got *%q*", want, got) + } else { + t.Logf("tunnel at %s is working!", url) } + }