blob: b541a628b87f6c760b734d1f5307e9d08874f5c4 [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// 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.
17package error
18
19import (
20 "encoding/json"
21 "fmt"
22 "net/http"
23)
24
25var 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
69var 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
80const (
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
119type 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
126func NewRequestError(errorCode int, cause string) *Error {
127 return NewError(errorCode, cause, 0)
128}
129
130func 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
140func (e Error) Error() string {
141 return e.Message + " (" + e.Cause + ")"
142}
143
144func (e Error) toJsonString() string {
145 b, _ := json.Marshal(e)
146 return string(b)
147}
148
149func (e Error) StatusCode() int {
150 status, ok := errorStatus[e.ErrorCode]
151 if !ok {
152 status = http.StatusBadRequest
153 }
154 return status
155}
156
157func (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}