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 ¬AliveError{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 }