launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/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  	"fmt"
     8  	"github.com/loggo/loggo"
     9  	errgo "launchpad.net/errgo/errors"
    10  
    11  	"launchpad.net/juju-core/errors"
    12  	"launchpad.net/juju-core/state"
    13  	"launchpad.net/juju-core/state/api/params"
    14  )
    15  
    16  var logger = loggo.GetLogger("juju.state.apiserver.common")
    17  
    18  var mask = errgo.Mask
    19  
    20  type notSupportedError struct {
    21  	entity    string
    22  	operation string
    23  }
    24  
    25  func (e *notSupportedError) Error() string {
    26  	return fmt.Sprintf("entity %q does not support %s", e.entity, e.operation)
    27  }
    28  
    29  func NotSupportedError(entity, operation string) error {
    30  	return &notSupportedError{entity, operation}
    31  }
    32  
    33  type noAddressSetError struct {
    34  	unitTag     string
    35  	addressName string
    36  }
    37  
    38  func (e *noAddressSetError) Error() string {
    39  	return fmt.Sprintf("%q has no %s address set", e.unitTag, e.addressName)
    40  }
    41  
    42  func NoAddressSetError(unitTag, addressName string) error {
    43  	return &noAddressSetError{unitTag, addressName}
    44  }
    45  
    46  func IsNoAddressSetError(err error) bool {
    47  	_, ok := err.(*noAddressSetError)
    48  	return ok
    49  }
    50  
    51  var (
    52  	ErrBadId          = errgo.New("id not found")
    53  	ErrBadCreds       = errgo.New("invalid entity name or password")
    54  	ErrPerm           = errgo.New("permission denied")
    55  	ErrNotLoggedIn    = errgo.New("not logged in")
    56  	ErrUnknownWatcher = errgo.New("unknown watcher id")
    57  	ErrUnknownPinger  = errgo.New("unknown pinger id")
    58  	ErrStoppedWatcher = errgo.New("watcher has been stopped")
    59  	ErrBadRequest     = errgo.New("invalid request")
    60  )
    61  
    62  var singletonErrorCodes = map[error]params.ErrorCode{
    63  	state.ErrCannotEnterScopeYet: params.CodeCannotEnterScopeYet,
    64  	state.ErrCannotEnterScope:    params.CodeCannotEnterScope,
    65  	state.ErrExcessiveContention: params.CodeExcessiveContention,
    66  	state.ErrUnitHasSubordinates: params.CodeUnitHasSubordinates,
    67  	ErrBadId:                     params.CodeNotFound,
    68  	ErrBadCreds:                  params.CodeUnauthorized,
    69  	ErrPerm:                      params.CodeUnauthorized,
    70  	ErrNotLoggedIn:               params.CodeUnauthorized,
    71  	ErrUnknownWatcher:            params.CodeNotFound,
    72  	ErrStoppedWatcher:            params.CodeStopped,
    73  }
    74  
    75  func singletonCode(err error) (params.ErrorCode, bool) {
    76  	err = errgo.Cause(err)
    77  	// All error types may not be hashable; deal with
    78  	// that by catching the panic if we try to look up
    79  	// a non-hashable type.
    80  	defer func() {
    81  		recover()
    82  	}()
    83  	code, ok := singletonErrorCodes[err]
    84  	return code, ok
    85  }
    86  
    87  // ServerError returns an error suitable for returning to an API
    88  // client, with an error code suitable for various kinds of errors
    89  // generated in packages outside the API.
    90  func ServerError0(err error) *params.Error {
    91  	if err == nil {
    92  		return nil
    93  	}
    94  	code, ok := singletonCode(err)
    95  	switch {
    96  	case ok:
    97  	case errors.IsUnauthorizedError(err):
    98  		code = params.CodeUnauthorized
    99  	case errors.IsNotFoundError(err):
   100  		code = params.CodeNotFound
   101  	case state.IsNotAssigned(err):
   102  		code = params.CodeNotAssigned
   103  	case state.IsHasAssignedUnitsError(err):
   104  		code = params.CodeHasAssignedUnits
   105  	case IsNoAddressSetError(err):
   106  		code = params.CodeNoAddressSet
   107  	case state.IsNotProvisionedError(err):
   108  		code = params.CodeNotProvisioned
   109  	default:
   110  		code, _ = errgo.Cause(err).(params.ErrorCode)
   111  	}
   112  	return &params.Error{
   113  		Message: err.Error(),
   114  		Code:    code,
   115  	}
   116  }
   117  
   118  func ServerError(err error) *params.Error {
   119  	err1 := ServerError0(err)
   120  	logger.Infof("ServerError %#v -> %#v", err, err1)
   121  	return err1
   122  }