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 &notSupportedError{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 &params.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 &params.Error{
   155  		Message: msg,
   156  		Code:    code,
   157  	}
   158  }