launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/api/params/apierror.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package params 5 6 import ( 7 "fmt" 8 "io" 9 10 "launchpad.net/errgo/errors" 11 12 "launchpad.net/juju-core/rpc" 13 ) 14 15 var mask = errors.Mask 16 17 // Error is the type of error returned by any call to the state API 18 type Error struct { 19 Message string 20 Code ErrorCode 21 } 22 23 func (e *Error) Error() string { 24 return e.Message 25 } 26 27 func (e *Error) Cause() error { 28 if e.Code == "" { 29 return nil 30 } 31 return e.Code 32 } 33 34 func (e *Error) ErrorCode() string { 35 return string(e.Code) 36 } 37 38 // GoString implements fmt.GoStringer. It means that a *Error shows its 39 // contents correctly when printed with %#v. 40 func (e Error) GoString() string { 41 return fmt.Sprintf("¶ms.Error{%q, %q}", e.Code, e.Message) 42 } 43 44 type ErrorCode string 45 46 func (code ErrorCode) Error() string { 47 return string(code) 48 } 49 50 // The Code constants hold error codes for some kinds of error. 51 const ( 52 CodeNotFound ErrorCode = "not found" 53 CodeUnauthorized ErrorCode = "unauthorized access" 54 CodeCannotEnterScope ErrorCode = "cannot enter scope" 55 CodeCannotEnterScopeYet ErrorCode = "cannot enter scope yet" 56 CodeExcessiveContention ErrorCode = "excessive contention" 57 CodeUnitHasSubordinates ErrorCode = "unit has subordinates" 58 CodeNotAssigned ErrorCode = "not assigned" 59 CodeStopped ErrorCode = "stopped" 60 CodeHasAssignedUnits ErrorCode = "machine has assigned units" 61 CodeNotProvisioned ErrorCode = "not provisioned" 62 CodeNoAddressSet ErrorCode = "no address set" 63 CodeNotImplemented ErrorCode = ErrorCode(rpc.CodeNotImplemented) 64 CodeServerShutdown ErrorCode = "server connection shut down" 65 ) 66 67 // clientError maps errors returned from an RPC call into local errors with 68 // appropriate values. 69 func ClientError(err error) error { 70 if err == nil { 71 return nil 72 } 73 if rerr, ok := err.(*rpc.RequestError); ok { 74 // We use our own error type rather than rpc.ServerError 75 // because we don't want the code or the "server error" prefix 76 // within the error message. Also, it's best not to make clients 77 // know that we're using the rpc package. 78 return &Error{ 79 Message: rerr.Message, 80 Code: ErrorCode(rerr.Code), 81 } 82 } 83 if err == io.ErrUnexpectedEOF || err == rpc.ErrShutdown { 84 return &Error{ 85 Message: err.Error(), 86 Code: CodeServerShutdown, 87 } 88 } 89 return mask(err, errors.Any) 90 } 91 92 // HasErrorCode reports whether the given error has a 93 // non-empty error code. 94 func HasErrorCode(err error) bool { 95 _, ok := errors.Cause(err).(ErrorCode) 96 return ok 97 } 98 99 func IsCodeNotFound(err error) bool { 100 return errors.Cause(err) == CodeNotFound 101 } 102 103 func IsCodeUnauthorized(err error) bool { 104 return errors.Cause(err) == CodeUnauthorized 105 } 106 107 // IsCodeNotFoundOrCodeUnauthorized is used in API clients which, pre-API, used 108 // IsNotFoundErr; this is because an API client is not necessarily privileged to 109 // know about the existence or otherwise of a particular entity, and the server 110 // may hence convert NotFound to Unauthorized at its discretion. 111 func IsCodeNotFoundOrCodeUnauthorized(err error) bool { 112 return IsCodeNotFound(err) || IsCodeUnauthorized(err) 113 } 114 115 func IsCodeCannotEnterScope(err error) bool { 116 return errors.Cause(err) == CodeCannotEnterScope 117 } 118 119 func IsCodeCannotEnterScopeYet(err error) bool { 120 return errors.Cause(err) == CodeCannotEnterScopeYet 121 } 122 123 func IsCodeExcessiveContention(err error) bool { 124 return errors.Cause(err) == CodeExcessiveContention 125 } 126 127 func IsCodeUnitHasSubordinates(err error) bool { 128 return errors.Cause(err) == CodeUnitHasSubordinates 129 } 130 131 func IsCodeNotAssigned(err error) bool { 132 return errors.Cause(err) == CodeNotAssigned 133 } 134 135 func IsCodeStopped(err error) bool { 136 return errors.Cause(err) == CodeStopped 137 } 138 139 func IsCodeHasAssignedUnits(err error) bool { 140 return errors.Cause(err) == CodeHasAssignedUnits 141 } 142 143 func IsCodeNotProvisioned(err error) bool { 144 return errors.Cause(err) == CodeNotProvisioned 145 } 146 147 func IsCodeNoAddressSet(err error) bool { 148 return errors.Cause(err) == CodeNoAddressSet 149 } 150 151 func IsCodeNotImplemented(err error) bool { 152 return errors.Cause(err) == CodeNotImplemented 153 }