Make kubectl errors even more user-friendly

Omit glog prefix when v < 2, show multiline errors for configuration
problems, add new generic messages for server errors that hide some
complexity that is not relevant for users.
This commit is contained in:
Clayton Coleman
2015-04-01 23:20:09 -04:00
parent 9b5b27a12e
commit 323a44e54a
4 changed files with 86 additions and 66 deletions

View File

@@ -17,11 +17,13 @@ limitations under the License.
package util
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"strconv"
"strings"
@@ -30,7 +32,9 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
utilerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
"github.com/evanphx/json-patch"
"github.com/golang/glog"
@@ -38,21 +42,69 @@ import (
"github.com/spf13/pflag"
)
type debugError interface {
DebugError() (msg string, args []interface{})
}
func CheckErr(err error) {
if err != nil {
if errors.IsStatusError(err) {
glog.FatalDepth(1, fmt.Sprintf("Error received from API: %s", err.Error()))
if debugErr, ok := err.(debugError); ok {
glog.V(4).Infof(debugErr.DebugError())
}
if errors.IsUnexpectedObjectError(err) {
glog.FatalDepth(1, fmt.Sprintf("Unexpected object received from server: %s", err.Error()))
_, isStatus := err.(client.APIStatus)
switch {
case clientcmd.IsConfigurationInvalid(err):
fatal(MultilineError("Error in configuration: ", err))
case isStatus:
fatal(fmt.Sprintf("Error from server: %s", err.Error()))
case errors.IsUnexpectedObjectError(err):
fatal(fmt.Sprintf("Server returned an unexpected response: %s", err.Error()))
}
if client.IsUnexpectedStatusError(err) {
glog.FatalDepth(1, fmt.Sprintf("Unexpected status received from server: %s", err.Error()))
switch t := err.(type) {
case *url.Error:
glog.V(4).Infof("Connection error: %s %s: %v", t.Op, t.URL, t.Err)
switch {
case strings.Contains(t.Err.Error(), "connection refused"):
host := t.URL
if server, err := url.Parse(t.URL); err == nil {
host = server.Host
}
fatal(fmt.Sprintf("The connection to the server %s was refused - did you specify the right host or port?", host))
}
fatal(fmt.Sprintf("Unable to connect to the server: %v", t.Err))
}
glog.FatalDepth(1, fmt.Sprintf("Client error: %s", err.Error()))
fatal(fmt.Sprintf("Error: %s", err.Error()))
}
}
func MultilineError(prefix string, err error) string {
if agg, ok := err.(utilerrors.Aggregate); ok {
errs := agg.Errors()
buf := &bytes.Buffer{}
switch len(errs) {
case 0:
return fmt.Sprintf("%s%v", prefix, err)
case 1:
return fmt.Sprintf("%s%v", prefix, errs[0])
default:
fmt.Fprintln(buf, prefix)
for _, err := range errs {
fmt.Fprintf(buf, "* %v\n", err)
}
return buf.String()
}
}
return fmt.Sprintf("%s%s", prefix, err)
}
func fatal(msg string) {
if glog.V(2) {
glog.FatalDepth(2, msg)
}
fmt.Fprintln(os.Stderr, msg)
os.Exit(1)
}
func UsageError(cmd *cobra.Command, format string, args ...interface{}) error {
msg := fmt.Sprintf(format, args...)
return fmt.Errorf("%s\nsee '%s -h' for help.", msg, cmd.CommandPath())