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("&params.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  }