github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/errors/common.go (about)

     1  // Copyright 2020 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package errors
     5  
     6  import (
     7  	"fmt"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/juju/collections/transform"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/version/v2"
    14  
    15  	"github.com/juju/juju/core/base"
    16  	"github.com/juju/juju/core/network"
    17  )
    18  
    19  const (
    20  	// ErrCannotEnterScope indicates that a relation unit failed to enter its scope
    21  	// due to either the unit or the relation not being Alive.
    22  	ErrCannotEnterScope = errors.ConstError("cannot enter scope")
    23  
    24  	// ErrCannotEnterScopeYet indicates that a relation unit failed to enter its
    25  	// scope due to a required and pre-existing subordinate unit that is not Alive.
    26  	// Once that subordinate has been removed, a new one can be created.
    27  	ErrCannotEnterScopeYet = errors.ConstError("cannot enter scope yet")
    28  
    29  	// ErrCharmRevisionAlreadyModified is returned when a pending or
    30  	// placeholder charm is no longer pending or a placeholder, signaling
    31  	// the charm is available in state with its full information.
    32  	ErrCharmRevisionAlreadyModified = errors.ConstError("charm revision already modified")
    33  
    34  	ErrDead = errors.ConstError("not found or dead")
    35  
    36  	ErrUpgradeInProgress = errors.ConstError("upgrade in progress")
    37  
    38  	// IncompatibleBaseError indicates the base selected is not supported by
    39  	// the charm.
    40  	IncompatibleBaseError = errors.ConstError("incompatible base for charm")
    41  )
    42  
    43  // errCharmAlreadyUploaded is returned by UpdateUploadedCharm() when
    44  // the given charm is already uploaded and marked as not pending in
    45  // state.
    46  type errCharmAlreadyUploaded struct {
    47  	curl string
    48  }
    49  
    50  func NewErrCharmAlreadyUploaded(curl string) error {
    51  	return &errCharmAlreadyUploaded{curl: curl}
    52  }
    53  
    54  func (e *errCharmAlreadyUploaded) Error() string {
    55  	return fmt.Sprintf("charm %q already uploaded", e.curl)
    56  }
    57  
    58  // IsCharmAlreadyUploadedError returns if the given error is
    59  // errCharmAlreadyUploaded.
    60  func IsCharmAlreadyUploadedError(err interface{}) bool {
    61  	if err == nil {
    62  		return false
    63  	}
    64  	// In case of a wrapped error, check the cause first.
    65  	value := err
    66  	cause := errors.Cause(err.(error))
    67  	if cause != nil {
    68  		value = cause
    69  	}
    70  	_, ok := value.(*errCharmAlreadyUploaded)
    71  	return ok
    72  }
    73  
    74  type notAliveError struct {
    75  	entity string
    76  }
    77  
    78  func NewNotAliveError(entity string) error {
    79  	return &notAliveError{entity: entity}
    80  }
    81  
    82  func (e notAliveError) Error() string {
    83  	if e.entity == "" {
    84  		return "not found or not alive"
    85  	}
    86  	return fmt.Sprintf("%v is not found or not alive", e.entity)
    87  }
    88  
    89  // IsNotAlive returns true if err is cause by a not alive error.
    90  func IsNotAlive(err error) bool {
    91  	_, ok := errors.Cause(err).(*notAliveError)
    92  	return ok
    93  }
    94  
    95  // errProviderIDNotUnique is a standard error to indicate the value specified
    96  // for a ProviderID field is not unique within the current model.
    97  type errProviderIDNotUnique struct {
    98  	duplicateIDs []string
    99  }
   100  
   101  func (e *errProviderIDNotUnique) Error() string {
   102  	idList := strings.Join(e.duplicateIDs, ", ")
   103  	return fmt.Sprintf("provider IDs not unique: %s", idList)
   104  }
   105  
   106  // NewProviderIDNotUniqueError returns an instance of errProviderIDNotUnique
   107  // initialized with the given duplicate provider IDs.
   108  func NewProviderIDNotUniqueError(providerIDs ...network.Id) error {
   109  	stringIDs := make([]string, len(providerIDs))
   110  	for i, providerID := range providerIDs {
   111  		stringIDs[i] = string(providerID)
   112  	}
   113  	return newProviderIDNotUniqueErrorFromStrings(stringIDs)
   114  }
   115  
   116  func newProviderIDNotUniqueErrorFromStrings(providerIDs []string) error {
   117  	return &errProviderIDNotUnique{
   118  		duplicateIDs: providerIDs,
   119  	}
   120  }
   121  
   122  // IsProviderIDNotUniqueError returns if the given error or its cause is
   123  // errProviderIDNotUnique.
   124  func IsProviderIDNotUniqueError(err interface{}) bool {
   125  	if err == nil {
   126  		return false
   127  	}
   128  	// In case of a wrapped error, check the cause first.
   129  	value := err
   130  	cause := errors.Cause(err.(error))
   131  	if cause != nil {
   132  		value = cause
   133  	}
   134  	_, ok := value.(*errProviderIDNotUnique)
   135  	return ok
   136  }
   137  
   138  // errParentDeviceHasChildren is a standard error to indicate a network
   139  // link-layer device cannot be removed because other existing devices refer to
   140  // it as their parent.
   141  type errParentDeviceHasChildren struct {
   142  	parentName  string
   143  	numChildren int
   144  }
   145  
   146  func (e *errParentDeviceHasChildren) Error() string {
   147  	return fmt.Sprintf("parent device %q has %d children", e.parentName, e.numChildren)
   148  }
   149  
   150  func NewParentDeviceHasChildrenError(parentName string, numChildren int) error {
   151  	return &errParentDeviceHasChildren{
   152  		parentName:  parentName,
   153  		numChildren: numChildren,
   154  	}
   155  }
   156  
   157  // IsParentDeviceHasChildrenError returns if the given error or its cause is
   158  // errParentDeviceHasChildren.
   159  func IsParentDeviceHasChildrenError(err interface{}) bool {
   160  	if err == nil {
   161  		return false
   162  	}
   163  	// In case of a wrapped error, check the cause first.
   164  	value := err
   165  	cause := errors.Cause(err.(error))
   166  	if cause != nil {
   167  		value = cause
   168  	}
   169  	_, ok := value.(*errParentDeviceHasChildren)
   170  	return ok
   171  }
   172  
   173  func NewErrIncompatibleBase(supportedBases []base.Base, b base.Base, charmName string) error {
   174  	return errors.WithType(
   175  		fmt.Errorf("base %q not supported by charm %q, supported bases are: %s",
   176  			b.DisplayString(),
   177  			charmName,
   178  			strings.Join(transform.Slice(supportedBases, func(b base.Base) string { return b.DisplayString() }), ", ")),
   179  		IncompatibleBaseError,
   180  	)
   181  }
   182  
   183  // versionInconsistentError indicates one or more agents have a
   184  // different version from the current one (even empty, when not yet
   185  // set).
   186  type versionInconsistentError struct {
   187  	currentVersion version.Number
   188  	agents         []string
   189  }
   190  
   191  // NewVersionInconsistentError returns a new instance of
   192  // versionInconsistentError.
   193  func NewVersionInconsistentError(currentVersion version.Number, agents []string) *versionInconsistentError {
   194  	return &versionInconsistentError{currentVersion: currentVersion, agents: agents}
   195  }
   196  
   197  func (e *versionInconsistentError) Error() string {
   198  	sort.Strings(e.agents)
   199  	return fmt.Sprintf("some agents have not upgraded to the current model version %s: %s", e.currentVersion, strings.Join(e.agents, ", "))
   200  }
   201  
   202  // IsVersionInconsistentError returns if the given error is
   203  // versionInconsistentError.
   204  func IsVersionInconsistentError(e interface{}) bool {
   205  	value := e
   206  	// In case of a wrapped error, check the cause first.
   207  	cause := errors.Cause(e.(error))
   208  	if cause != nil {
   209  		value = cause
   210  	}
   211  	_, ok := value.(*versionInconsistentError)
   212  	return ok
   213  }