Improve command-line client error output (#122)
Motivation: The output when an error occurs shows an integer error code, which isn't very helpful. And in the case of an error when creating a resource, you also get a redundant log message from the controller client. Modifications: * the controller client no longer logs errors * the generated String() allows for the enum name to be displayed in the error output * each errorCode enum member has a hand-generated description * the format of the error message from the CLI client was modified to display the error description with the error message Related to #112
This commit is contained in:
committed by
Soam Vasani
parent
eae5150bff
commit
ab6e2e8021
@@ -26,8 +26,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/fission/fission"
|
"github.com/fission/fission"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -104,10 +102,6 @@ func (c *Client) FunctionCreate(f *fission.Function) (*fission.Metadata, error)
|
|||||||
|
|
||||||
body, err := c.handleResponse(resp)
|
body, err := c.handleResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"name": f.Metadata.Name,
|
|
||||||
"err": err,
|
|
||||||
}).Error("Failed to create function")
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,10 +234,6 @@ func (c *Client) HTTPTriggerCreate(t *fission.HTTPTrigger) (*fission.Metadata, e
|
|||||||
|
|
||||||
body, err := c.handleResponse(resp)
|
body, err := c.handleResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"name": t.Metadata.Name,
|
|
||||||
"err": err,
|
|
||||||
}).Error("Failed to create http trigger")
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,10 +341,6 @@ func (c *Client) EnvironmentCreate(env *fission.Environment) (*fission.Metadata,
|
|||||||
|
|
||||||
body, err := c.handleResponse(resp)
|
body, err := c.handleResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"name": env.Metadata.Name,
|
|
||||||
"err": err,
|
|
||||||
}).Error("Failed to create environment")
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-19
@@ -18,7 +18,9 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
@@ -26,7 +28,6 @@ import (
|
|||||||
"github.com/satori/go.uuid"
|
"github.com/satori/go.uuid"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"github.com/fission/fission"
|
"github.com/fission/fission"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ func (rs *ResourceStore) create(r resource) error {
|
|||||||
|
|
||||||
_, err = rs.KeysAPI.Set(context.Background(), key, string(serialized),
|
_, err = rs.KeysAPI.Set(context.Background(), key, string(serialized),
|
||||||
&client.SetOptions{PrevExist: client.PrevNoExist})
|
&client.SetOptions{PrevExist: client.PrevNoExist})
|
||||||
return handleEtcdError(err)
|
return handleEtcdErrorForResource(err, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *ResourceStore) read(rkey string, res resource) error {
|
func (rs *ResourceStore) read(rkey string, res resource) error {
|
||||||
@@ -108,7 +109,7 @@ func (rs *ResourceStore) read(rkey string, res resource) error {
|
|||||||
|
|
||||||
resp, err := rs.KeysAPI.Get(context.Background(), key, nil)
|
resp, err := rs.KeysAPI.Get(context.Background(), key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, typName, rkey)
|
||||||
}
|
}
|
||||||
return rs.serializer.deserialize([]byte(resp.Node.Value), res)
|
return rs.serializer.deserialize([]byte(resp.Node.Value), res)
|
||||||
}
|
}
|
||||||
@@ -126,13 +127,13 @@ func (rs *ResourceStore) update(r resource) error {
|
|||||||
|
|
||||||
_, err = rs.KeysAPI.Set(context.Background(), key, string(serialized),
|
_, err = rs.KeysAPI.Set(context.Background(), key, string(serialized),
|
||||||
&client.SetOptions{PrevExist: client.PrevExist})
|
&client.SetOptions{PrevExist: client.PrevExist})
|
||||||
return handleEtcdError(err)
|
return handleEtcdErrorForResource(err, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *ResourceStore) delete(typename, rkey string) error {
|
func (rs *ResourceStore) delete(typename, rkey string) error {
|
||||||
key := typename + "/" + rkey
|
key := typename + "/" + rkey
|
||||||
_, err := rs.KeysAPI.Delete(context.Background(), key, nil) // ignore response
|
_, err := rs.KeysAPI.Delete(context.Background(), key, nil) // ignore response
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, typename, rkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAll finds all entries under key. If none or found or key
|
// getAll finds all entries under key. If none or found or key
|
||||||
@@ -143,7 +144,7 @@ func (rs *ResourceStore) getAll(key string) ([]string, error) {
|
|||||||
if client.IsKeyNotFound(err) {
|
if client.IsKeyNotFound(err) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
return nil, handleEtcdError(err)
|
return nil, handleEtcdError(err, "", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]string, 0, len(resp.Node.Nodes))
|
res := make([]string, 0, len(resp.Node.Nodes))
|
||||||
@@ -165,7 +166,7 @@ func (rs *ResourceStore) writeFile(parentKey string, contents []byte) (string, s
|
|||||||
resp, err := rs.KeysAPI.CreateInOrder(context.Background(), parentKey, uid, nil)
|
resp, err := rs.KeysAPI.CreateInOrder(context.Background(), parentKey, uid, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = rs.FileStore.delete(uid)
|
_ = rs.FileStore.delete(uid)
|
||||||
return "", "", handleEtcdError(err)
|
return "", "", handleEtcdError(err, "file", parentKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.Node.Key, uid, nil
|
return resp.Node.Key, uid, nil
|
||||||
@@ -175,7 +176,7 @@ func (rs *ResourceStore) readFile(key string, uid *string) ([]byte, error) {
|
|||||||
key = "file/" + key
|
key = "file/" + key
|
||||||
resp, err := rs.KeysAPI.Get(context.Background(), key, &client.GetOptions{Sort: true})
|
resp, err := rs.KeysAPI.Get(context.Background(), key, &client.GetOptions{Sort: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleEtcdError(err)
|
return nil, handleEtcdError(err, "file", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if uid == nil {
|
if uid == nil {
|
||||||
@@ -197,14 +198,14 @@ func (rs *ResourceStore) readFile(key string, uid *string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contents, err := rs.FileStore.read(*uid)
|
contents, err := rs.FileStore.read(*uid)
|
||||||
return contents, handleEtcdError(err)
|
return contents, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *ResourceStore) deleteFile(key string, uid string) error {
|
func (rs *ResourceStore) deleteFile(key string, uid string) error {
|
||||||
key = "file/" + key
|
key = "file/" + key
|
||||||
resp, err := rs.KeysAPI.Get(context.Background(), key, &client.GetOptions{Sort: true})
|
resp, err := rs.KeysAPI.Get(context.Background(), key, &client.GetOptions{Sort: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, "file", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
var node *client.Node
|
var node *client.Node
|
||||||
@@ -225,12 +226,12 @@ func (rs *ResourceStore) deleteFile(key string, uid string) error {
|
|||||||
|
|
||||||
_, err = rs.KeysAPI.Delete(context.Background(), node.Key, nil)
|
_, err = rs.KeysAPI.Delete(context.Background(), node.Key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, "", node.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resp.Node.Nodes) == 1 {
|
if len(resp.Node.Nodes) == 1 {
|
||||||
_, err = rs.KeysAPI.Delete(context.Background(), key, &client.DeleteOptions{Dir: true})
|
_, err = rs.KeysAPI.Delete(context.Background(), key, &client.DeleteOptions{Dir: true})
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, "file", key)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -239,7 +240,7 @@ func (rs *ResourceStore) deleteAllFiles(key string) error {
|
|||||||
key = "file/" + key
|
key = "file/" + key
|
||||||
resp, err := rs.KeysAPI.Get(context.Background(), key, &client.GetOptions{Sort: true})
|
resp, err := rs.KeysAPI.Get(context.Background(), key, &client.GetOptions{Sort: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, "file", key)
|
||||||
}
|
}
|
||||||
for _, u := range resp.Node.Nodes {
|
for _, u := range resp.Node.Nodes {
|
||||||
err = rs.FileStore.delete(u.Value)
|
err = rs.FileStore.delete(u.Value)
|
||||||
@@ -249,30 +250,38 @@ func (rs *ResourceStore) deleteAllFiles(key string) error {
|
|||||||
|
|
||||||
_, err = rs.KeysAPI.Delete(context.Background(), u.Key, nil)
|
_, err = rs.KeysAPI.Delete(context.Background(), u.Key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, "", u.Key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err = rs.KeysAPI.Delete(context.Background(), key, &client.DeleteOptions{Dir: true})
|
_, err = rs.KeysAPI.Delete(context.Background(), key, &client.DeleteOptions{Dir: true})
|
||||||
return handleEtcdError(err)
|
return handleEtcdError(err, "file", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleEtcdError(e error) error {
|
func handleEtcdErrorForResource(e error, r resource) error {
|
||||||
|
resourceType, _ := getTypeName(r)
|
||||||
|
return handleEtcdError(e, resourceType, r.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleEtcdError(e error, resourceType string, resourceKey string) error {
|
||||||
ee, ok := e.(client.Error)
|
ee, ok := e.(client.Error)
|
||||||
if !ok {
|
if !ok {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
code := fission.ErrorInternal
|
code := fission.ErrorInternal
|
||||||
msg := ee.Error()
|
msg := ee.Error()
|
||||||
simpleMsg := fmt.Sprintf("%v (%v)", ee.Message, ee.Cause)
|
|
||||||
|
if len(resourceType) > 0 {
|
||||||
|
resourceType = strings.ToLower(resourceType) + " "
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: handle any other etcd error codes we care about
|
//TODO: handle any other etcd error codes we care about
|
||||||
switch ee.Code {
|
switch ee.Code {
|
||||||
case client.ErrorCodeNodeExist:
|
case client.ErrorCodeNodeExist:
|
||||||
code = fission.ErrorNameExists
|
code = fission.ErrorNameExists
|
||||||
msg = simpleMsg
|
msg = fmt.Sprintf("%s'%s' already exists", resourceType, resourceKey)
|
||||||
case client.ErrorCodeKeyNotFound:
|
case client.ErrorCodeKeyNotFound:
|
||||||
code = fission.ErrorNotFound
|
code = fission.ErrorNotFound
|
||||||
msg = simpleMsg
|
msg = fmt.Sprintf("%s'%s' does not exist", resourceType, resourceKey)
|
||||||
}
|
}
|
||||||
return fission.MakeError(code, msg)
|
return fission.MakeError(code, msg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e Error) Error() string {
|
func (err Error) Error() string {
|
||||||
return fmt.Sprintf("(Error %v) %v", e.Code, e.Message)
|
return fmt.Sprintf("%v - %v", err.Description(), err.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeError(code int, msg string) Error {
|
func MakeError(code int, msg string) Error {
|
||||||
@@ -90,3 +90,11 @@ func GetHTTPError(err error) (int, string) {
|
|||||||
}
|
}
|
||||||
return code, msg
|
return code, msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (err Error) Description() string {
|
||||||
|
idx := int(err.Code)
|
||||||
|
if idx < 0 || idx > len(errorDescriptions)-1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return errorDescriptions[idx]
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ type (
|
|||||||
Code errorCode `json:"code"`
|
Code errorCode `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
errorCode int
|
errorCode int
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -85,3 +86,14 @@ const (
|
|||||||
ErrorNoSpace
|
ErrorNoSpace
|
||||||
ErrorNotImplmented
|
ErrorNotImplmented
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// must match order and len of the above const
|
||||||
|
var errorDescriptions = []string{
|
||||||
|
"Internal error",
|
||||||
|
"Not authorized",
|
||||||
|
"Resource not found",
|
||||||
|
"Resource exists",
|
||||||
|
"Invalid argument",
|
||||||
|
"No space",
|
||||||
|
"Not implemented",
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user