github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/common/errors.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"net/http"
     8  
     9  	"github.com/juju/collections/set"
    10  	"github.com/juju/errors"
    11  
    12  	"github.com/juju/juju/environs/context"
    13  )
    14  
    15  // ZoneIndependentError wraps the given error such that it
    16  // satisfies environs.IsAvailabilityZoneIndependent.
    17  func ZoneIndependentError(err error) error {
    18  	if err == nil {
    19  		return nil
    20  	}
    21  	wrapped := errors.Wrap(err, zoneIndependentError{err})
    22  	wrapped.(*errors.Err).SetLocation(1)
    23  	return wrapped
    24  }
    25  
    26  type zoneIndependentError struct {
    27  	error
    28  }
    29  
    30  // AvailabilityZoneIndependent is part of the
    31  // environs.AvailabilityZoneError interface.
    32  func (zoneIndependentError) AvailabilityZoneIndependent() bool {
    33  	return true
    34  }
    35  
    36  // credentialNotValid represents an error when a provider credential is not valid.
    37  // Realistically, this is not a transient error. Without a valid credential we
    38  // cannot do much on the provider. This is fatal.
    39  type credentialNotValid struct {
    40  	error
    41  }
    42  
    43  // CredentialNotValid returns an error which wraps err and satisfies
    44  // IsCredentialNotValid().
    45  func CredentialNotValid(err error) error {
    46  	if err == nil {
    47  		return nil
    48  	}
    49  	wrapped := errors.Wrap(err, &credentialNotValid{err})
    50  	wrapped.(*errors.Err).SetLocation(1)
    51  	return wrapped
    52  }
    53  
    54  // NewCredentialNotValid returns an error with given message and satisfies
    55  // IsCredentialNotValid().
    56  func NewCredentialNotValid(message string) error {
    57  	err := errors.New("credential not valid: " + message)
    58  	wrapped := errors.Wrap(err, &credentialNotValid{err})
    59  	wrapped.(*errors.Err).SetLocation(1)
    60  	return wrapped
    61  }
    62  
    63  // CredentialNotValidf returns a wrapped error with given message and satisfies
    64  // IsCredentialNotValid().
    65  func CredentialNotValidf(err error, message string) error {
    66  	wrapped := errors.Wrapf(err, &credentialNotValid{err}, message)
    67  	wrapped.(*errors.Err).SetLocation(1)
    68  	return wrapped
    69  }
    70  
    71  // IsCredentialNotValid reports whether err was created with CredentialNotValid().
    72  func IsCredentialNotValid(err error) bool {
    73  	err = errors.Cause(err)
    74  	_, ok := err.(*credentialNotValid)
    75  	return ok
    76  }
    77  
    78  // AuthorisationFailureStatusCodes contains http status code that signify authorisation difficulties.
    79  var AuthorisationFailureStatusCodes = set.NewInts(
    80  	http.StatusUnauthorized,
    81  	http.StatusPaymentRequired,
    82  	http.StatusForbidden,
    83  	http.StatusProxyAuthRequired,
    84  )
    85  
    86  // MaybeHandleCredentialError determines if a given error relates to an invalid credential.
    87  // If it is, the credential is invalidated and the return bool is true.
    88  func MaybeHandleCredentialError(isAuthError func(error) bool, err error, ctx context.ProviderCallContext) bool {
    89  	denied := isAuthError(errors.Cause(err))
    90  	if ctx != nil && denied {
    91  		invalidateErr := ctx.InvalidateCredential("cloud denied access")
    92  		if invalidateErr != nil {
    93  			logger.Warningf("could not invalidate stored cloud credential on the controller: %v", invalidateErr)
    94  		}
    95  	}
    96  	return denied
    97  }
    98  
    99  // HandleCredentialError determines if a given error relates to an invalid credential.
   100  func HandleCredentialError(isAuthError func(error) bool, err error, ctx context.ProviderCallContext) {
   101  	MaybeHandleCredentialError(isAuthError, err, ctx)
   102  }