go.etcd.io/etcd@v3.3.27+incompatible/error/error.go (about)

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package error describes errors in etcd project. When any change happens,
    16  // Documentation/v2/errorcode.md needs to be updated correspondingly.
    17  package error
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"net/http"
    23  )
    24  
    25  var errors = map[int]string{
    26  	// command related errors
    27  	EcodeKeyNotFound:      "Key not found",
    28  	EcodeTestFailed:       "Compare failed", //test and set
    29  	EcodeNotFile:          "Not a file",
    30  	ecodeNoMorePeer:       "Reached the max number of peers in the cluster",
    31  	EcodeNotDir:           "Not a directory",
    32  	EcodeNodeExist:        "Key already exists", // create
    33  	ecodeKeyIsPreserved:   "The prefix of given key is a keyword in etcd",
    34  	EcodeRootROnly:        "Root is read only",
    35  	EcodeDirNotEmpty:      "Directory not empty",
    36  	ecodeExistingPeerAddr: "Peer address has existed",
    37  	EcodeUnauthorized:     "The request requires user authentication",
    38  
    39  	// Post form related errors
    40  	ecodeValueRequired:        "Value is Required in POST form",
    41  	EcodePrevValueRequired:    "PrevValue is Required in POST form",
    42  	EcodeTTLNaN:               "The given TTL in POST form is not a number",
    43  	EcodeIndexNaN:             "The given index in POST form is not a number",
    44  	ecodeValueOrTTLRequired:   "Value or TTL is required in POST form",
    45  	ecodeTimeoutNaN:           "The given timeout in POST form is not a number",
    46  	ecodeNameRequired:         "Name is required in POST form",
    47  	ecodeIndexOrValueRequired: "Index or value is required",
    48  	ecodeIndexValueMutex:      "Index and value cannot both be specified",
    49  	EcodeInvalidField:         "Invalid field",
    50  	EcodeInvalidForm:          "Invalid POST form",
    51  	EcodeRefreshValue:         "Value provided on refresh",
    52  	EcodeRefreshTTLRequired:   "A TTL must be provided on refresh",
    53  
    54  	// raft related errors
    55  	EcodeRaftInternal: "Raft Internal Error",
    56  	EcodeLeaderElect:  "During Leader Election",
    57  
    58  	// etcd related errors
    59  	EcodeWatcherCleared:     "watcher is cleared due to etcd recovery",
    60  	EcodeEventIndexCleared:  "The event in requested index is outdated and cleared",
    61  	ecodeStandbyInternal:    "Standby Internal Error",
    62  	ecodeInvalidActiveSize:  "Invalid active size",
    63  	ecodeInvalidRemoveDelay: "Standby remove delay",
    64  
    65  	// client related errors
    66  	ecodeClientInternal: "Client Internal Error",
    67  }
    68  
    69  var errorStatus = map[int]int{
    70  	EcodeKeyNotFound:  http.StatusNotFound,
    71  	EcodeNotFile:      http.StatusForbidden,
    72  	EcodeDirNotEmpty:  http.StatusForbidden,
    73  	EcodeUnauthorized: http.StatusUnauthorized,
    74  	EcodeTestFailed:   http.StatusPreconditionFailed,
    75  	EcodeNodeExist:    http.StatusPreconditionFailed,
    76  	EcodeRaftInternal: http.StatusInternalServerError,
    77  	EcodeLeaderElect:  http.StatusInternalServerError,
    78  }
    79  
    80  const (
    81  	EcodeKeyNotFound      = 100
    82  	EcodeTestFailed       = 101
    83  	EcodeNotFile          = 102
    84  	ecodeNoMorePeer       = 103
    85  	EcodeNotDir           = 104
    86  	EcodeNodeExist        = 105
    87  	ecodeKeyIsPreserved   = 106
    88  	EcodeRootROnly        = 107
    89  	EcodeDirNotEmpty      = 108
    90  	ecodeExistingPeerAddr = 109
    91  	EcodeUnauthorized     = 110
    92  
    93  	ecodeValueRequired        = 200
    94  	EcodePrevValueRequired    = 201
    95  	EcodeTTLNaN               = 202
    96  	EcodeIndexNaN             = 203
    97  	ecodeValueOrTTLRequired   = 204
    98  	ecodeTimeoutNaN           = 205
    99  	ecodeNameRequired         = 206
   100  	ecodeIndexOrValueRequired = 207
   101  	ecodeIndexValueMutex      = 208
   102  	EcodeInvalidField         = 209
   103  	EcodeInvalidForm          = 210
   104  	EcodeRefreshValue         = 211
   105  	EcodeRefreshTTLRequired   = 212
   106  
   107  	EcodeRaftInternal = 300
   108  	EcodeLeaderElect  = 301
   109  
   110  	EcodeWatcherCleared     = 400
   111  	EcodeEventIndexCleared  = 401
   112  	ecodeStandbyInternal    = 402
   113  	ecodeInvalidActiveSize  = 403
   114  	ecodeInvalidRemoveDelay = 404
   115  
   116  	ecodeClientInternal = 500
   117  )
   118  
   119  type Error struct {
   120  	ErrorCode int    `json:"errorCode"`
   121  	Message   string `json:"message"`
   122  	Cause     string `json:"cause,omitempty"`
   123  	Index     uint64 `json:"index"`
   124  }
   125  
   126  func NewRequestError(errorCode int, cause string) *Error {
   127  	return NewError(errorCode, cause, 0)
   128  }
   129  
   130  func NewError(errorCode int, cause string, index uint64) *Error {
   131  	return &Error{
   132  		ErrorCode: errorCode,
   133  		Message:   errors[errorCode],
   134  		Cause:     cause,
   135  		Index:     index,
   136  	}
   137  }
   138  
   139  // Error is for the error interface
   140  func (e Error) Error() string {
   141  	return e.Message + " (" + e.Cause + ")"
   142  }
   143  
   144  func (e Error) toJsonString() string {
   145  	b, _ := json.Marshal(e)
   146  	return string(b)
   147  }
   148  
   149  func (e Error) StatusCode() int {
   150  	status, ok := errorStatus[e.ErrorCode]
   151  	if !ok {
   152  		status = http.StatusBadRequest
   153  	}
   154  	return status
   155  }
   156  
   157  func (e Error) WriteTo(w http.ResponseWriter) error {
   158  	w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index))
   159  	w.Header().Set("Content-Type", "application/json")
   160  	w.WriteHeader(e.StatusCode())
   161  	_, err := w.Write([]byte(e.toJsonString() + "\n"))
   162  	return err
   163  }