etcdserver: switch to using etcd.Error
parent
2342402434
commit
e2d01eff35
|
@ -46,6 +46,7 @@ var errors = map[int]string{
|
||||||
EcodeIndexOrValueRequired: "Index or value is required",
|
EcodeIndexOrValueRequired: "Index or value is required",
|
||||||
EcodeIndexValueMutex: "Index and value cannot both be specified",
|
EcodeIndexValueMutex: "Index and value cannot both be specified",
|
||||||
EcodeInvalidField: "Invalid field",
|
EcodeInvalidField: "Invalid field",
|
||||||
|
EcodeInvalidForm: "Invalid POST form",
|
||||||
|
|
||||||
// raft related errors
|
// raft related errors
|
||||||
EcodeRaftInternal: "Raft Internal Error",
|
EcodeRaftInternal: "Raft Internal Error",
|
||||||
|
@ -84,6 +85,7 @@ const (
|
||||||
EcodeIndexOrValueRequired = 207
|
EcodeIndexOrValueRequired = 207
|
||||||
EcodeIndexValueMutex = 208
|
EcodeIndexValueMutex = 208
|
||||||
EcodeInvalidField = 209
|
EcodeInvalidField = 209
|
||||||
|
EcodeInvalidForm = 210
|
||||||
|
|
||||||
EcodeRaftInternal = 300
|
EcodeRaftInternal = 300
|
||||||
EcodeLeaderElect = 301
|
EcodeLeaderElect = 301
|
||||||
|
@ -104,6 +106,10 @@ type Error struct {
|
||||||
Index uint64 `json:"index"`
|
Index uint64 `json:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRequestError(errorCode int, cause string) *Error {
|
||||||
|
return NewError(errorCode, cause, 0)
|
||||||
|
}
|
||||||
|
|
||||||
func NewError(errorCode int, cause string, index uint64) *Error {
|
func NewError(errorCode int, cause string, index uint64) *Error {
|
||||||
return &Error{
|
return &Error{
|
||||||
ErrorCode: errorCode,
|
ErrorCode: errorCode,
|
||||||
|
|
|
@ -180,13 +180,13 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
func (h Handler) serveKeys(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
func (h Handler) serveKeys(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
rr, err := parseRequest(r, genId())
|
rr, err := parseRequest(r, genId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
writeError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := h.Server.Do(ctx, rr)
|
resp, err := h.Server.Do(ctx, rr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeInternalError(w, err)
|
writeError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ func (h Handler) serveKeys(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
writeInternalError(w, errors.New("received response with no Event/Watcher!"))
|
writeError(w, errors.New("received response with no Event/Watcher!"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,11 +257,17 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if err = r.ParseForm(); err != nil {
|
if err = r.ParseForm(); err != nil {
|
||||||
return emptyReq, err
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeInvalidForm,
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(r.URL.Path, keysPrefix) {
|
if !strings.HasPrefix(r.URL.Path, keysPrefix) {
|
||||||
return emptyReq, errors.New("unexpected key prefix!")
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeInvalidForm,
|
||||||
|
"incorrect key prefix",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
path := r.URL.Path[len(keysPrefix):]
|
path := r.URL.Path[len(keysPrefix):]
|
||||||
|
|
||||||
|
@ -269,24 +275,39 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
|
||||||
|
|
||||||
var pIdx, wIdx, ttl uint64
|
var pIdx, wIdx, ttl uint64
|
||||||
if pIdx, err = parseUint64(q.Get("prevIndex")); err != nil {
|
if pIdx, err = parseUint64(q.Get("prevIndex")); err != nil {
|
||||||
return emptyReq, errors.New("invalid value for prevIndex")
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeIndexNaN,
|
||||||
|
"invalid value for prevIndex",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if wIdx, err = parseUint64(q.Get("waitIndex")); err != nil {
|
if wIdx, err = parseUint64(q.Get("waitIndex")); err != nil {
|
||||||
return emptyReq, errors.New("invalid value for waitIndex")
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeIndexNaN,
|
||||||
|
"invalid value for waitIndex",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if ttl, err = parseUint64(q.Get("ttl")); err != nil {
|
if ttl, err = parseUint64(q.Get("ttl")); err != nil {
|
||||||
return emptyReq, errors.New("invalid value for ttl")
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeTTLNaN,
|
||||||
|
"invalid value for ttl",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var rec, sort, wait bool
|
var rec, sort, wait bool
|
||||||
if rec, err = parseBool(q.Get("recursive")); err != nil {
|
if rec, err = parseBool(q.Get("recursive")); err != nil {
|
||||||
return emptyReq, errors.New("invalid value for recursive")
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
"invalid value for recursive")
|
||||||
}
|
}
|
||||||
if sort, err = parseBool(q.Get("sorted")); err != nil {
|
if sort, err = parseBool(q.Get("sorted")); err != nil {
|
||||||
return emptyReq, errors.New("invalid value for sorted")
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
"invalid value for sorted")
|
||||||
}
|
}
|
||||||
if wait, err = parseBool(q.Get("wait")); err != nil {
|
if wait, err = parseBool(q.Get("wait")); err != nil {
|
||||||
return emptyReq, errors.New("invalid value for wait")
|
return emptyReq, etcdErr.NewRequestError(
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
"invalid value for wait")
|
||||||
}
|
}
|
||||||
|
|
||||||
rr := etcdserverpb.Request{
|
rr := etcdserverpb.Request{
|
||||||
|
@ -332,9 +353,10 @@ func parseUint64(s string) (uint64, error) {
|
||||||
return strconv.ParseUint(s, 10, 64)
|
return strconv.ParseUint(s, 10, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeInternalError logs and writes the given Error to the ResponseWriter
|
// writeError logs and writes the given Error to the ResponseWriter
|
||||||
// If Error is an etcdErr, it is rendered to the ResponseWriter
|
// If Error is an etcdErr, it is rendered to the ResponseWriter
|
||||||
func writeInternalError(w http.ResponseWriter, err error) {
|
// Otherwise, it is assumed to be an InternalServerError
|
||||||
|
func writeError(w http.ResponseWriter, err error) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,8 @@ func TestParseUint64(t *testing.T) {
|
||||||
|
|
||||||
func TestBadParseRequest(t *testing.T) {
|
func TestBadParseRequest(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
in *http.Request
|
in *http.Request
|
||||||
|
wcode int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// parseForm failure
|
// parseForm failure
|
||||||
|
@ -64,36 +65,86 @@ func TestBadParseRequest(t *testing.T) {
|
||||||
Body: nil,
|
Body: nil,
|
||||||
Method: "PUT",
|
Method: "PUT",
|
||||||
},
|
},
|
||||||
|
etcdErr.EcodeInvalidForm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// bad key prefix
|
// bad key prefix
|
||||||
&http.Request{
|
&http.Request{
|
||||||
URL: mustNewURL(t, "/badprefix/"),
|
URL: mustNewURL(t, "/badprefix/"),
|
||||||
},
|
},
|
||||||
|
etcdErr.EcodeInvalidForm,
|
||||||
},
|
},
|
||||||
// bad values for prevIndex, waitIndex, ttl
|
// bad values for prevIndex, waitIndex, ttl
|
||||||
{mustNewRequest(t, "?prevIndex=foo")},
|
{
|
||||||
{mustNewRequest(t, "?prevIndex=1.5")},
|
mustNewRequest(t, "?prevIndex=foo"),
|
||||||
{mustNewRequest(t, "?prevIndex=-1")},
|
etcdErr.EcodeIndexNaN,
|
||||||
{mustNewRequest(t, "?waitIndex=garbage")},
|
},
|
||||||
{mustNewRequest(t, "?waitIndex=??")},
|
{
|
||||||
{mustNewRequest(t, "?ttl=-1")},
|
mustNewRequest(t, "?prevIndex=1.5"),
|
||||||
|
etcdErr.EcodeIndexNaN,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?prevIndex=-1"),
|
||||||
|
etcdErr.EcodeIndexNaN,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?waitIndex=garbage"),
|
||||||
|
etcdErr.EcodeIndexNaN,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?waitIndex=??"),
|
||||||
|
etcdErr.EcodeIndexNaN,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?ttl=-1"),
|
||||||
|
etcdErr.EcodeTTLNaN,
|
||||||
|
},
|
||||||
// bad values for recursive, sorted, wait
|
// bad values for recursive, sorted, wait
|
||||||
{mustNewRequest(t, "?recursive=hahaha")},
|
{
|
||||||
{mustNewRequest(t, "?recursive=1234")},
|
mustNewRequest(t, "?recursive=hahaha"),
|
||||||
{mustNewRequest(t, "?recursive=?")},
|
etcdErr.EcodeInvalidField,
|
||||||
{mustNewRequest(t, "?sorted=hahaha")},
|
},
|
||||||
{mustNewRequest(t, "?sorted=!!")},
|
{
|
||||||
{mustNewRequest(t, "?wait=notreally")},
|
mustNewRequest(t, "?recursive=1234"),
|
||||||
{mustNewRequest(t, "?wait=what!")},
|
etcdErr.EcodeInvalidField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?recursive=?"),
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?sorted=hahaha"),
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?sorted=!!"),
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?wait=notreally"),
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewRequest(t, "?wait=what!"),
|
||||||
|
etcdErr.EcodeInvalidField,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
got, err := parseRequest(tt.in, 1234)
|
got, err := parseRequest(tt.in, 1234)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("case %d: unexpected nil error!", i)
|
t.Errorf("#%d: unexpected nil error!", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ee, ok := err.(*etcdErr.Error)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("#%d: err is not etcd.Error!", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ee.ErrorCode != tt.wcode {
|
||||||
|
t.Errorf("#%d: code=%d, want %v", i, ee.ErrorCode, tt.wcode)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, etcdserverpb.Request{}) {
|
if !reflect.DeepEqual(got, etcdserverpb.Request{}) {
|
||||||
t.Errorf("case %d: unexpected non-empty Request: %#v", i, got)
|
t.Errorf("#%d: unexpected non-empty Request: %#v", i, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,10 +256,10 @@ func (w *eventingWatcher) EventChan() chan *store.Event {
|
||||||
|
|
||||||
func (w *eventingWatcher) Remove() {}
|
func (w *eventingWatcher) Remove() {}
|
||||||
|
|
||||||
func TestWriteInternalError(t *testing.T) {
|
func TestWriteError(t *testing.T) {
|
||||||
// nil error should not panic
|
// nil error should not panic
|
||||||
rw := httptest.NewRecorder()
|
rw := httptest.NewRecorder()
|
||||||
writeInternalError(rw, nil)
|
writeError(rw, nil)
|
||||||
h := rw.Header()
|
h := rw.Header()
|
||||||
if len(h) > 0 {
|
if len(h) > 0 {
|
||||||
t.Fatalf("unexpected non-empty headers: %#v", h)
|
t.Fatalf("unexpected non-empty headers: %#v", h)
|
||||||
|
@ -241,7 +292,7 @@ func TestWriteInternalError(t *testing.T) {
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
rw := httptest.NewRecorder()
|
rw := httptest.NewRecorder()
|
||||||
writeInternalError(rw, tt.err)
|
writeError(rw, tt.err)
|
||||||
if code := rw.Code; code != tt.wcode {
|
if code := rw.Code; code != tt.wcode {
|
||||||
t.Errorf("#%d: code=%d, want %d", i, code, tt.wcode)
|
t.Errorf("#%d: code=%d, want %d", i, code, tt.wcode)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue