github.com/macb/etcd@v0.3.1-0.20140227003422-a60481c6b1a0/error/error.go (about)

     1  /*
     2  Copyright 2013 CoreOS Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package error
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"net/http"
    23  )
    24  
    25  var errors map[int]string
    26  
    27  const (
    28  	EcodeKeyNotFound    = 100
    29  	EcodeTestFailed     = 101
    30  	EcodeNotFile        = 102
    31  	EcodeNoMorePeer     = 103
    32  	EcodeNotDir         = 104
    33  	EcodeNodeExist      = 105
    34  	EcodeKeyIsPreserved = 106
    35  	EcodeRootROnly      = 107
    36  	EcodeDirNotEmpty    = 108
    37  
    38  	EcodeValueRequired        = 200
    39  	EcodePrevValueRequired    = 201
    40  	EcodeTTLNaN               = 202
    41  	EcodeIndexNaN             = 203
    42  	EcodeValueOrTTLRequired   = 204
    43  	EcodeTimeoutNaN           = 205
    44  	EcodeNameRequired         = 206
    45  	EcodeIndexOrValueRequired = 207
    46  	EcodeIndexValueMutex      = 208
    47  	EcodeInvalidField         = 209
    48  
    49  	EcodeRaftInternal = 300
    50  	EcodeLeaderElect  = 301
    51  
    52  	EcodeWatcherCleared    = 400
    53  	EcodeEventIndexCleared = 401
    54  )
    55  
    56  func init() {
    57  	errors = make(map[int]string)
    58  
    59  	// command related errors
    60  	errors[EcodeKeyNotFound] = "Key not found"
    61  	errors[EcodeTestFailed] = "Compare failed" //test and set
    62  	errors[EcodeNotFile] = "Not a file"
    63  	errors[EcodeNoMorePeer] = "Reached the max number of peers in the cluster"
    64  	errors[EcodeNotDir] = "Not a directory"
    65  	errors[EcodeNodeExist] = "Key already exists" // create
    66  	errors[EcodeRootROnly] = "Root is read only"
    67  	errors[EcodeKeyIsPreserved] = "The prefix of given key is a keyword in etcd"
    68  	errors[EcodeDirNotEmpty] = "Directory not empty"
    69  
    70  	// Post form related errors
    71  	errors[EcodeValueRequired] = "Value is Required in POST form"
    72  	errors[EcodePrevValueRequired] = "PrevValue is Required in POST form"
    73  	errors[EcodeTTLNaN] = "The given TTL in POST form is not a number"
    74  	errors[EcodeIndexNaN] = "The given index in POST form is not a number"
    75  	errors[EcodeValueOrTTLRequired] = "Value or TTL is required in POST form"
    76  	errors[EcodeTimeoutNaN] = "The given timeout in POST form is not a number"
    77  	errors[EcodeNameRequired] = "Name is required in POST form"
    78  	errors[EcodeIndexOrValueRequired] = "Index or value is required"
    79  	errors[EcodeIndexValueMutex] = "Index and value cannot both be specified"
    80  	errors[EcodeInvalidField] = "Invalid field"
    81  
    82  	// raft related errors
    83  	errors[EcodeRaftInternal] = "Raft Internal Error"
    84  	errors[EcodeLeaderElect] = "During Leader Election"
    85  
    86  	// etcd related errors
    87  	errors[EcodeWatcherCleared] = "watcher is cleared due to etcd recovery"
    88  	errors[EcodeEventIndexCleared] = "The event in requested index is outdated and cleared"
    89  
    90  }
    91  
    92  type Error struct {
    93  	ErrorCode int    `json:"errorCode"`
    94  	Message   string `json:"message"`
    95  	Cause     string `json:"cause,omitempty"`
    96  	Index     uint64 `json:"index"`
    97  }
    98  
    99  func NewError(errorCode int, cause string, index uint64) *Error {
   100  	return &Error{
   101  		ErrorCode: errorCode,
   102  		Message:   errors[errorCode],
   103  		Cause:     cause,
   104  		Index:     index,
   105  	}
   106  }
   107  
   108  func Message(code int) string {
   109  	return errors[code]
   110  }
   111  
   112  // Only for error interface
   113  func (e Error) Error() string {
   114  	return e.Message
   115  }
   116  
   117  func (e Error) toJsonString() string {
   118  	b, _ := json.Marshal(e)
   119  	return string(b)
   120  }
   121  
   122  func (e Error) Write(w http.ResponseWriter) {
   123  	w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index))
   124  	// 3xx is raft internal error
   125  	status := http.StatusBadRequest
   126  	switch e.ErrorCode {
   127  	case EcodeKeyNotFound:
   128  		status = http.StatusNotFound
   129  	case EcodeNotFile, EcodeDirNotEmpty:
   130  		status = http.StatusForbidden
   131  	case EcodeTestFailed, EcodeNodeExist:
   132  		status = http.StatusPreconditionFailed
   133  	default:
   134  		if e.ErrorCode/100 == 3 {
   135  			status = http.StatusInternalServerError
   136  		}
   137  	}
   138  	http.Error(w, e.toJsonString(), status)
   139  }