Merge pull request #582 from aaron-prindle/error-reporting-prompt

Added opt in to stackdriver error reporting
pull/666/head
Aaron Prindle 2016-10-06 10:58:30 -07:00 committed by GitHub
commit a403a949dd
22 changed files with 306 additions and 186 deletions

View File

@ -25,6 +25,7 @@ import (
"os"
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
)
@ -92,6 +93,18 @@ var settings = []Setting{
name: "kubernetes-version",
set: SetString,
},
{
name: config.WantUpdateNotification,
set: SetBool,
},
{
name: config.ReminderWaitPeriodInHours,
set: SetInt,
},
{
name: config.WantReportError,
set: SetBool,
},
}
var ConfigCmd = &cobra.Command{

View File

@ -33,7 +33,7 @@ var configSetCmd = &cobra.Command{
fmt.Fprintln(os.Stderr, "usage: minikube config set PROPERTY_NAME PROPERTY_VALUE")
os.Exit(1)
}
err := set(args[0], args[1])
err := Set(args[0], args[1])
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
@ -45,7 +45,7 @@ func init() {
ConfigCmd.AddCommand(configSetCmd)
}
func set(name string, value string) error {
func Set(name string, value string) error {
s, err := findSetting(name)
if err != nil {
return err

View File

@ -19,7 +19,7 @@ package config
import "testing"
func TestNotFound(t *testing.T) {
err := set("nonexistant", "10")
err := Set("nonexistant", "10")
if err == nil {
t.Fatalf("Set did not return error for unknown property")
}

View File

@ -24,9 +24,9 @@ import (
"github.com/docker/machine/libmachine"
"github.com/pkg/browser"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
commonutil "k8s.io/minikube/pkg/util"
)
@ -50,14 +50,14 @@ var dashboardCmd = &cobra.Command{
if err := commonutil.RetryAfter(20, func() error { return CheckService(namespace, service) }, 6*time.Second); err != nil {
fmt.Fprintln(os.Stderr, "Could not find finalized endpoint being pointed to by %s: %s", service, err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
url, err := cluster.GetServiceURL(api, namespace, service)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, "Check that minikube is running.")
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
if dashboardURLMode {
fmt.Fprintln(os.Stdout, url)

View File

@ -21,9 +21,9 @@ import (
"github.com/docker/machine/libmachine"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
// deleteCmd represents the delete command
@ -39,7 +39,7 @@ associated files.`,
if err := cluster.DeleteHost(api); err != nil {
fmt.Println("Errors occurred deleting machine: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println("Machine deleted.")
},

View File

@ -30,9 +30,9 @@ import (
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
const (
@ -241,13 +241,13 @@ var dockerEnvCmd = &cobra.Command{
shellCfg, err = shellCfgUnset(api)
if err != nil {
glog.Errorln("Error setting machine env variable(s):", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
} else {
shellCfg, err = shellCfgSet(api)
if err != nil {
glog.Errorln("Error setting machine env variable(s):", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
}

View File

@ -22,8 +22,8 @@ import (
"github.com/docker/machine/libmachine"
"github.com/golang/glog"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
// ipCmd represents the ip command
@ -37,12 +37,12 @@ var ipCmd = &cobra.Command{
host, err := api.Load(constants.MachineName)
if err != nil {
glog.Errorln("Error getting IP: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
ip, err := host.Driver.GetIP()
if err != nil {
glog.Errorln("Error getting IP: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println(ip)
},

View File

@ -23,9 +23,9 @@ import (
"github.com/docker/machine/libmachine"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
// logsCmd represents the logs command
@ -39,7 +39,7 @@ var logsCmd = &cobra.Command{
s, err := cluster.GetHostLogs(api)
if err != nil {
log.Println("Error getting machine logs:", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Fprintln(os.Stdout, s)
},

View File

@ -139,5 +139,6 @@ func setupViper() {
viper.SetDefault(config.WantUpdateNotification, true)
viper.SetDefault(config.ReminderWaitPeriodInHours, 24)
viper.SetDefault(config.WantReportError, false)
viper.SetDefault(config.WantReportErrorPrompt, true)
setFlagsUsingViper()
}

View File

@ -27,6 +27,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
kubeApi "k8s.io/kubernetes/pkg/api"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
@ -47,7 +48,7 @@ var serviceCmd = &cobra.Command{
if len(args) == 0 || len(args) > 1 {
errText := "Please specify a service name."
fmt.Fprintln(os.Stderr, errText)
util.MaybeReportErrorAndExit(errors.New(errText))
cmdUtil.MaybeReportErrorAndExit(errors.New(errText))
}
service := args[0]
@ -57,14 +58,14 @@ var serviceCmd = &cobra.Command{
cluster.EnsureMinikubeRunningOrExit(api)
if err := util.RetryAfter(20, func() error { return CheckService(namespace, service) }, 6*time.Second); err != nil {
fmt.Fprintln(os.Stderr, "Could not find finalized endpoint being pointed to by %s: %s", service, err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
url, err := cluster.GetServiceURL(api, namespace, service)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, "Check that minikube is running and that you have specified the correct namespace (-n flag).")
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
if https {
url = strings.Replace(url, "http", "https", 1)

View File

@ -19,10 +19,11 @@ package cmd
import (
"github.com/docker/machine/libmachine"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
// sshCmd represents the docker-ssh command
@ -34,9 +35,10 @@ var sshCmd = &cobra.Command{
api := libmachine.NewClient(constants.Minipath, constants.MakeMiniPath("certs"))
defer api.Close()
err := cluster.CreateSSHShell(api, args)
err = errors.Wrap(err, "Error attempting to ssh/run-ssh-command")
if err != nil {
glog.Errorln("Error attempting to ssh into machine: ", err)
util.MaybeReportErrorAndExit(err)
glog.Errorln(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
},
}

View File

@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/kubeconfig"
@ -90,13 +91,13 @@ func runStart(cmd *cobra.Command, args []string) {
err := util.Retry(3, start)
if err != nil {
glog.Errorln("Error starting host: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
ip, err := host.Driver.GetIP()
if err != nil {
glog.Errorln("Error starting host: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
kubernetesConfig := cluster.KubernetesConfig{
KubernetesVersion: viper.GetString(kubernetesVersion),
@ -107,17 +108,17 @@ func runStart(cmd *cobra.Command, args []string) {
}
if err := cluster.UpdateCluster(host, host.Driver, kubernetesConfig); err != nil {
glog.Errorln("Error updating cluster: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
if err := cluster.SetupCerts(host.Driver); err != nil {
glog.Errorln("Error configuring authentication: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
if err := cluster.StartCluster(host, kubernetesConfig); err != nil {
glog.Errorln("Error starting cluster: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
kubeHost, err := host.Driver.GetURL()
@ -134,7 +135,7 @@ func runStart(cmd *cobra.Command, args []string) {
clientKey := constants.MakeMiniPath("apiserver.key")
if err := setupKubeconfig(name, kubeHost, certAuth, clientCert, clientKey); err != nil {
glog.Errorln("Error setting up kubeconfig: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println("Kubectl is now configured to use the cluster.")
}

View File

@ -24,9 +24,9 @@ import (
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
var statusFormat string
@ -47,7 +47,7 @@ var statusCmd = &cobra.Command{
ms, err := cluster.GetHostStatus(api)
if err != nil {
glog.Errorln("Error getting machine status:", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
ls := "N/A"
if ms == state.Running.String() {
@ -55,19 +55,19 @@ var statusCmd = &cobra.Command{
}
if err != nil {
glog.Errorln("Error getting machine status:", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
status := Status{ms, ls}
tmpl, err := template.New("status").Parse(statusFormat)
if err != nil {
glog.Errorln("Error creating status template:", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
err = tmpl.Execute(os.Stdout, status)
if err != nil {
glog.Errorln("Error executing status template:", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
},
}

View File

@ -21,9 +21,9 @@ import (
"github.com/docker/machine/libmachine"
"github.com/spf13/cobra"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
// stopCmd represents the stop command
@ -39,7 +39,7 @@ itself, leaving all files intact. The cluster can be started again with the "sta
if err := cluster.StopHost(api); err != nil {
fmt.Println("Error stopping machine: ", err)
util.MaybeReportErrorAndExit(err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println("Machine stopped.")
},

164
cmd/util/util.go Normal file
View File

@ -0,0 +1,164 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/viper"
"golang.org/x/crypto/ssh/terminal"
minikubeConfig "k8s.io/minikube/cmd/minikube/cmd/config"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/version"
)
type ServiceContext struct {
Service string `json:"service"`
Version string `json:"version"`
}
type Message struct {
Message string `json:"message"`
ServiceContext `json:"serviceContext"`
}
func ReportError(err error, url string) error {
errMsg, err := FormatError(err)
if err != nil {
return errors.Wrap(err, "Error formatting error message")
}
jsonErrorMsg, err := MarshallError(errMsg, "default", version.GetVersion())
if err != nil {
return errors.Wrap(err, "Error marshalling error message to JSON")
}
err = UploadError(jsonErrorMsg, url)
if err != nil {
return errors.Wrap(err, "Error uploading error message")
}
return nil
}
func FormatError(err error) (string, error) {
if err == nil {
return "", errors.New("Error: ReportError was called with nil error value")
}
type stackTracer interface {
StackTrace() errors.StackTrace
}
errOutput := []string{}
errOutput = append(errOutput, err.Error())
if err, ok := err.(stackTracer); ok {
for _, f := range err.StackTrace() {
errOutput = append(errOutput, fmt.Sprintf("\tat %n(%v)", f, f))
}
} else {
return "", errors.New("Error msg with no stack trace cannot be reported")
}
return strings.Join(errOutput, "\n"), nil
}
func MarshallError(errMsg, service, version string) ([]byte, error) {
m := Message{errMsg, ServiceContext{service, version}}
b, err := json.Marshal(m)
if err != nil {
return nil, errors.Wrap(err, "")
}
return b, nil
}
func UploadError(b []byte, url string) error {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
if err != nil {
return errors.Wrap(err, "")
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return errors.Wrap(err, "")
} else if resp.StatusCode != 200 {
return errors.Errorf("Error sending error report to %s, got response code %s", url, resp.StatusCode)
}
return nil
}
func MaybeReportErrorAndExit(errToReport error) {
var err error
if viper.GetBool(config.WantReportError) {
err = ReportError(errToReport, constants.ReportingURL)
} else if viper.GetBool(config.WantReportErrorPrompt) {
fmt.Println("========================================" +
"An error has occurred. Would you like to opt in to sending anonymized crash information to minikube to help prevent future errors?" +
"(To opt out of these messages, run the command)\n\tminikube config set WantReportErrorPrompt false" +
"========================================")
if PromptUserForAccept(os.Stdin) {
minikubeConfig.Set(config.WantReportError, "true")
err = ReportError(errToReport, constants.ReportingURL)
}
}
if err != nil {
glog.Errorf(err.Error())
}
os.Exit(1)
}
func getInput(input chan string, r io.Reader) {
reader := bufio.NewReader(r)
fmt.Print("Please enter your response [Y/n]: \n")
response, err := reader.ReadString('\n')
if err != nil {
glog.Errorf(err.Error())
}
input <- response
}
func PromptUserForAccept(r io.Reader) bool {
if !terminal.IsTerminal(int(os.Stdout.Fd())) {
return false
}
input := make(chan string, 1)
go getInput(input, r)
select {
case response := <-input:
response = strings.ToLower(strings.TrimSpace(response))
if response == "y" || response == "yes" || response == "" {
return true
} else if response == "n" || response == "no" {
return false
} else {
fmt.Println("Invalid response, error reporting remains disabled. Must be in form [Y/n]")
return false
}
case <-time.After(30 * time.Second):
return false
}
}

83
cmd/util/util_test.go Normal file
View File

@ -0,0 +1,83 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"k8s.io/minikube/pkg/version"
"github.com/pkg/errors"
)
func TestFormatError(t *testing.T) {
var testErr error
if _, err := FormatError(testErr); err == nil {
t.Fatalf("FormatError should have errored with a nil error input")
}
testErr = fmt.Errorf("Not a valid error to format as there is no stacktrace")
if out, err := FormatError(testErr); err == nil {
t.Fatalf("FormatError should have errored with a non pkg/errors error (no stacktrace info): %s", out)
}
testErr = errors.New("TestFormatError 1")
errors.Wrap(testErr, "TestFormatError 2")
errors.Wrap(testErr, "TestFormatError 3")
_, err := FormatError(testErr)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
}
func TestMarshallError(t *testing.T) {
testErr := errors.New("TestMarshallError 1")
errors.Wrap(testErr, "TestMarshallError 2")
errors.Wrap(testErr, "TestMarshallError 3")
errMsg, _ := FormatError(testErr)
if _, err := MarshallError(errMsg, "default", version.GetVersion()); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
}
func TestUploadError(t *testing.T) {
testErr := errors.New("TestUploadError 1")
errors.Wrap(testErr, "TestUploadError 2")
errors.Wrap(testErr, "TestUploadError 3")
errMsg, _ := FormatError(testErr)
jsonErrMsg, _ := MarshallError(errMsg, "default", version.GetVersion())
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
}))
if err := UploadError(jsonErrMsg, server.URL); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "failed to write report", 400)
}))
if err := UploadError(jsonErrMsg, server.URL); err == nil {
t.Fatalf("UploadError should have errored from a 400 response")
}
}

View File

@ -17,6 +17,9 @@ Configurable fields:
* show-libmachine-logs
* log_dir
* kubernetes-version
* WantUpdateNotification
* ReminderWaitPeriodInHours
* WantReportError
```
minikube config SUBCOMMAND [flags]

View File

@ -20,4 +20,5 @@ const (
WantUpdateNotification = "WantUpdateNotification"
ReminderWaitPeriodInHours = "ReminderWaitPeriodInHours"
WantReportError = "WantReportError"
WantReportErrorPrompt = "WantReportErrorPrompt"
)

View File

@ -85,3 +85,5 @@ var LocalkubeLinuxFilename = "localkube-linux-amd64"
// DockerAPIVersion is the API version implemented by Docker running in the minikube VM.
const DockerAPIVersion = "1.23"
const ReportingURL = "https://clouderrorreporting.googleapis.com/v1beta1/projects/k8s-minikube/events:report?key=AIzaSyACUwzG0dEPcl-eOgpDKnyKoUFgHdfoFuA"

View File

@ -28,5 +28,3 @@ const (
func GetAlternateDNS(domain string) []string {
return []string{"kubernetes.default.svc." + domain, "kubernetes.default.svc", "kubernetes.default", "kubernetes"}
}
const reportingURL = "https://clouderrorreporting.googleapis.com/v1beta1/projects/k8s-minikube/events:report?key=AIzaSyACUwzG0dEPcl-eOgpDKnyKoUFgHdfoFuA"

View File

@ -17,22 +17,17 @@ limitations under the License.
package util
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"github.com/blang/semver"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/version"
)
@ -159,88 +154,3 @@ func IsDirectory(path string) (bool, error) {
}
return fileInfo.IsDir(), nil
}
type ServiceContext struct {
Service string `json:"service"`
Version string `json:"version"`
}
type Message struct {
Message string `json:"message"`
ServiceContext `json:"serviceContext"`
}
func ReportError(err error, url string) error {
errMsg, err := FormatError(err)
if err != nil {
return errors.Wrap(err, "")
}
jsonErrorMsg, err := MarshallError(errMsg, "default", version.GetVersion())
if err != nil {
return errors.Wrap(err, "")
}
if err != nil {
return errors.Wrap(err, "")
}
err = UploadError(jsonErrorMsg, url)
if err != nil {
return errors.Wrap(err, "")
}
return nil
}
func FormatError(err error) (string, error) {
if err == nil {
return "", errors.New("Error: ReportError was called with nil error value")
}
// Extract the stacktrace from the error messages in their orig format
errMsg := fmt.Sprintf("%+v\n", err)
errArray := strings.Split(errMsg, "\n")
errOutput := []string{}
//Error message must have at least 1 message w/ 1 stack trace(2 lines) -> 3 lines, 2 index
if len(errArray) <= 2 {
return "", errors.New("Error msg with no stack trace cannot be reported")
}
// This code is to format the error stacktraces so that StackDriver will accept them
errOutput = append(errOutput, errArray[0])
for i := 1; i < len(errArray)-1; i += 2 {
errOutput = append(errOutput, fmt.Sprintf("\tat %s (%s)", errArray[i],
filepath.Base(errArray[i+1])))
}
return strings.Join(errOutput, "\n") + "\n", nil
}
func MarshallError(errMsg, service, version string) ([]byte, error) {
m := Message{errMsg, ServiceContext{service, version}}
b, err := json.Marshal(m)
if err != nil {
return nil, errors.Wrap(err, "")
}
return b, nil
}
func UploadError(b []byte, url string) error {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
if err != nil {
return errors.Wrap(err, "")
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return errors.Wrap(err, "")
} else if resp.StatusCode != 200 {
return errors.Errorf("Error sending error report to %s, got response code %s", url, resp.StatusCode)
}
return nil
}
func MaybeReportErrorAndExit(err error) {
if viper.GetBool(config.WantReportError) {
ReportError(err, reportingURL)
}
os.Exit(1)
}

View File

@ -17,14 +17,10 @@ limitations under the License.
package util
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/version"
)
// Returns a function that will return n errors, then return successfully forever.
@ -112,58 +108,3 @@ Error 2`
t.Fatalf("Unexpected error: %s", err)
}
}
func TestFormatError(t *testing.T) {
var testErr error
if _, err := FormatError(testErr); err == nil {
t.Fatalf("FormatError should have errored with a nil error input")
}
testErr = fmt.Errorf("Not a valid error to format as there is no stacktrace")
if out, err := FormatError(testErr); err == nil {
t.Fatalf("FormatError should have errored with a non pkg/errors error (no stacktrace info): %s", out)
}
testErr = errors.New("TestFormatError 1")
errors.Wrap(testErr, "TestFormatError 2")
errors.Wrap(testErr, "TestFormatError 3")
_, err := FormatError(testErr)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
}
func TestMarshallError(t *testing.T) {
testErr := errors.New("TestMarshallError 1")
errors.Wrap(testErr, "TestMarshallError 2")
errors.Wrap(testErr, "TestMarshallError 3")
errMsg, _ := FormatError(testErr)
if _, err := MarshallError(errMsg, "default", version.GetVersion()); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
}
func TestUploadError(t *testing.T) {
testErr := errors.New("TestUploadError 1")
errors.Wrap(testErr, "TestUploadError 2")
errors.Wrap(testErr, "TestUploadError 3")
errMsg, _ := FormatError(testErr)
jsonErrMsg, _ := MarshallError(errMsg, "default", version.GetVersion())
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
}))
if err := UploadError(jsonErrMsg, server.URL); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "failed to write report", 400)
}))
if err := UploadError(jsonErrMsg, server.URL); err == nil {
t.Fatalf("UploadError should have errored from a 400 response")
}
}