// Copyright 2015 CoreOS, Inc. // // 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. // error package describes errors in etcd project. // When any change happens, Documentation/errorcode.md needs to be updated // correspondingly. package error import ( "encoding/json" "fmt" "net/http" ) var errors = map[int]string{ // command related errors EcodeKeyNotFound: "Key not found", EcodeTestFailed: "Compare failed", //test and set EcodeNotFile: "Not a file", ecodeNoMorePeer: "Reached the max number of peers in the cluster", EcodeNotDir: "Not a directory", EcodeNodeExist: "Key already exists", // create ecodeKeyIsPreserved: "The prefix of given key is a keyword in etcd", EcodeRootROnly: "Root is read only", EcodeDirNotEmpty: "Directory not empty", ecodeExistingPeerAddr: "Peer address has existed", EcodeUnauthorized: "The request requires user authentication", // Post form related errors ecodeValueRequired: "Value is Required in POST form", EcodePrevValueRequired: "PrevValue is Required in POST form", EcodeTTLNaN: "The given TTL in POST form is not a number", EcodeIndexNaN: "The given index in POST form is not a number", ecodeValueOrTTLRequired: "Value or TTL is required in POST form", ecodeTimeoutNaN: "The given timeout in POST form is not a number", ecodeNameRequired: "Name is required in POST form", ecodeIndexOrValueRequired: "Index or value is required", ecodeIndexValueMutex: "Index and value cannot both be specified", EcodeInvalidField: "Invalid field", EcodeInvalidForm: "Invalid POST form", // raft related errors EcodeRaftInternal: "Raft Internal Error", EcodeLeaderElect: "During Leader Election", // etcd related errors EcodeWatcherCleared: "watcher is cleared due to etcd recovery", EcodeEventIndexCleared: "The event in requested index is outdated and cleared", ecodeStandbyInternal: "Standby Internal Error", ecodeInvalidActiveSize: "Invalid active size", ecodeInvalidRemoveDelay: "Standby remove delay", // client related errors ecodeClientInternal: "Client Internal Error", } var errorStatus = map[int]int{ EcodeKeyNotFound: http.StatusNotFound, EcodeNotFile: http.StatusForbidden, EcodeDirNotEmpty: http.StatusForbidden, EcodeUnauthorized: http.StatusUnauthorized, EcodeTestFailed: http.StatusPreconditionFailed, EcodeNodeExist: http.StatusPreconditionFailed, EcodeRaftInternal: http.StatusInternalServerError, EcodeLeaderElect: http.StatusInternalServerError, } const ( EcodeKeyNotFound = 100 EcodeTestFailed = 101 EcodeNotFile = 102 ecodeNoMorePeer = 103 EcodeNotDir = 104 EcodeNodeExist = 105 ecodeKeyIsPreserved = 106 EcodeRootROnly = 107 EcodeDirNotEmpty = 108 ecodeExistingPeerAddr = 109 EcodeUnauthorized = 110 ecodeValueRequired = 200 EcodePrevValueRequired = 201 EcodeTTLNaN = 202 EcodeIndexNaN = 203 ecodeValueOrTTLRequired = 204 ecodeTimeoutNaN = 205 ecodeNameRequired = 206 ecodeIndexOrValueRequired = 207 ecodeIndexValueMutex = 208 EcodeInvalidField = 209 EcodeInvalidForm = 210 EcodeRaftInternal = 300 EcodeLeaderElect = 301 EcodeWatcherCleared = 400 EcodeEventIndexCleared = 401 ecodeStandbyInternal = 402 ecodeInvalidActiveSize = 403 ecodeInvalidRemoveDelay = 404 ecodeClientInternal = 500 ) type Error struct { ErrorCode int `json:"errorCode"` Message string `json:"message"` Cause string `json:"cause,omitempty"` 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 { return &Error{ ErrorCode: errorCode, Message: errors[errorCode], Cause: cause, Index: index, } } // Only for error interface func (e Error) Error() string { return e.Message + " (" + e.Cause + ")" } func (e Error) toJsonString() string { b, _ := json.Marshal(e) return string(b) } func (e Error) statusCode() int { status, ok := errorStatus[e.ErrorCode] if !ok { status = http.StatusBadRequest } return status } func (e Error) WriteTo(w http.ResponseWriter) { w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index)) w.Header().Set("Content-Type", "application/json") w.WriteHeader(e.statusCode()) fmt.Fprintln(w, e.toJsonString()) }