github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/common/errors.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 stderrors "errors" 8 "fmt" 9 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 "github.com/juju/txn" 13 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/leadership" 16 "github.com/juju/juju/state" 17 ) 18 19 type notSupportedError struct { 20 tag names.Tag 21 operation string 22 } 23 24 func (e *notSupportedError) Error() string { 25 return fmt.Sprintf("entity %q does not support %s", e.tag, e.operation) 26 } 27 28 func NotSupportedError(tag names.Tag, operation string) error { 29 return ¬SupportedError{tag, operation} 30 } 31 32 type noAddressSetError struct { 33 unitTag names.UnitTag 34 addressName string 35 } 36 37 func (e *noAddressSetError) Error() string { 38 return fmt.Sprintf("%q has no %s address set", e.unitTag, e.addressName) 39 } 40 41 func NoAddressSetError(unitTag names.UnitTag, addressName string) error { 42 return &noAddressSetError{unitTag, addressName} 43 } 44 45 func IsNoAddressSetError(err error) bool { 46 _, ok := err.(*noAddressSetError) 47 return ok 48 } 49 50 type unknownEnvironmentError struct { 51 uuid string 52 } 53 54 func (e *unknownEnvironmentError) Error() string { 55 return fmt.Sprintf("unknown environment: %q", e.uuid) 56 } 57 58 func UnknownEnvironmentError(uuid string) error { 59 return &unknownEnvironmentError{uuid: uuid} 60 } 61 62 func IsUnknownEnviromentError(err error) bool { 63 _, ok := err.(*unknownEnvironmentError) 64 return ok 65 } 66 67 var ( 68 ErrBadId = stderrors.New("id not found") 69 ErrBadCreds = stderrors.New("invalid entity name or password") 70 ErrPerm = stderrors.New("permission denied") 71 ErrNotLoggedIn = stderrors.New("not logged in") 72 ErrUnknownWatcher = stderrors.New("unknown watcher id") 73 ErrUnknownPinger = stderrors.New("unknown pinger id") 74 ErrStoppedWatcher = stderrors.New("watcher has been stopped") 75 ErrBadRequest = stderrors.New("invalid request") 76 ErrTryAgain = stderrors.New("try again") 77 ErrActionNotAvailable = stderrors.New("action no longer available") 78 79 ErrOperationBlocked = func(msg string) *params.Error { 80 if msg == "" { 81 msg = "The operation has been blocked." 82 } 83 return ¶ms.Error{ 84 Code: params.CodeOperationBlocked, 85 Message: msg, 86 } 87 } 88 ) 89 90 var singletonErrorCodes = map[error]string{ 91 state.ErrCannotEnterScopeYet: params.CodeCannotEnterScopeYet, 92 state.ErrCannotEnterScope: params.CodeCannotEnterScope, 93 state.ErrUnitHasSubordinates: params.CodeUnitHasSubordinates, 94 state.ErrDead: params.CodeDead, 95 txn.ErrExcessiveContention: params.CodeExcessiveContention, 96 leadership.ErrClaimDenied: params.CodeLeadershipClaimDenied, 97 ErrBadId: params.CodeNotFound, 98 ErrBadCreds: params.CodeUnauthorized, 99 ErrPerm: params.CodeUnauthorized, 100 ErrNotLoggedIn: params.CodeUnauthorized, 101 ErrUnknownWatcher: params.CodeNotFound, 102 ErrStoppedWatcher: params.CodeStopped, 103 ErrTryAgain: params.CodeTryAgain, 104 ErrActionNotAvailable: params.CodeActionNotAvailable, 105 } 106 107 func singletonCode(err error) (string, bool) { 108 // All error types may not be hashable; deal with 109 // that by catching the panic if we try to look up 110 // a non-hashable type. 111 defer func() { 112 recover() 113 }() 114 code, ok := singletonErrorCodes[err] 115 return code, ok 116 } 117 118 // ServerError returns an error suitable for returning to an API 119 // client, with an error code suitable for various kinds of errors 120 // generated in packages outside the API. 121 func ServerError(err error) *params.Error { 122 if err == nil { 123 return nil 124 } 125 msg := err.Error() 126 // Skip past annotations when looking for the code. 127 err = errors.Cause(err) 128 code, ok := singletonCode(err) 129 switch { 130 case ok: 131 case errors.IsUnauthorized(err): 132 code = params.CodeUnauthorized 133 case errors.IsNotFound(err): 134 code = params.CodeNotFound 135 case errors.IsAlreadyExists(err): 136 code = params.CodeAlreadyExists 137 case errors.IsNotAssigned(err): 138 code = params.CodeNotAssigned 139 case state.IsHasAssignedUnitsError(err): 140 code = params.CodeHasAssignedUnits 141 case IsNoAddressSetError(err): 142 code = params.CodeNoAddressSet 143 case errors.IsNotProvisioned(err): 144 code = params.CodeNotProvisioned 145 case state.IsUpgradeInProgressError(err): 146 code = params.CodeUpgradeInProgress 147 case state.IsHasAttachmentsError(err): 148 code = params.CodeMachineHasAttachedStorage 149 case IsUnknownEnviromentError(err): 150 code = params.CodeNotFound 151 default: 152 code = params.ErrCode(err) 153 } 154 return ¶ms.Error{ 155 Message: msg, 156 Code: code, 157 } 158 }