github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/apperrors/errors.go (about) 1 package apperrors 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 "strings" 8 9 "github.com/kyma-incubator/compass/components/director/pkg/resource" 10 ) 11 12 // Error missing godoc 13 type Error struct { 14 errorCode ErrorType 15 Message string 16 arguments map[string]string 17 parentErr error 18 } 19 20 // Error missing godoc 21 func (e Error) Error() string { 22 builder := strings.Builder{} 23 builder.WriteString(e.Message) 24 25 var i = 0 26 if len(e.arguments) != 0 { 27 builder.WriteString(" [") 28 keys := sortMapKey(e.arguments) 29 for _, key := range keys { 30 builder.WriteString(fmt.Sprintf("%s=%s", key, e.arguments[key])) 31 i++ 32 if len(e.arguments) != i { 33 builder.WriteString("; ") 34 } 35 } 36 builder.WriteString("]") 37 } 38 if e.errorCode == InternalError && e.parentErr != nil { 39 builder.WriteString(": ") 40 builder.WriteString(e.parentErr.Error()) 41 } 42 43 return builder.String() 44 } 45 46 // Is missing godoc 47 func (e Error) Is(err error) bool { 48 if customErr, ok := err.(Error); ok { 49 return e.errorCode == customErr.errorCode 50 } 51 return false 52 } 53 54 // ErrorCode missing godoc 55 func ErrorCode(err error) ErrorType { 56 var customErr Error 57 found := errors.As(err, &customErr) 58 if found { 59 return customErr.errorCode 60 } 61 return UnknownError 62 } 63 64 // NewNotNullViolationError missing godoc 65 func NewNotNullViolationError(resourceType resource.Type) error { 66 return Error{ 67 errorCode: EmptyData, 68 Message: EmptyDataMsg, 69 arguments: map[string]string{"object": string(resourceType)}, 70 } 71 } 72 73 // NewCheckViolationError missing godoc 74 func NewCheckViolationError(resourceType resource.Type) error { 75 return Error{ 76 errorCode: InconsistentData, 77 Message: InconsistentDataMsg, 78 arguments: map[string]string{"object": string(resourceType)}, 79 } 80 } 81 82 // NewOperationTimeoutError missing godoc 83 func NewOperationTimeoutError() error { 84 return Error{ 85 errorCode: OperationTimeout, 86 Message: OperationTimeoutMsg, 87 } 88 } 89 90 // NewNotUniqueError missing godoc 91 func NewNotUniqueError(resourceType resource.Type) error { 92 return Error{ 93 errorCode: NotUnique, 94 Message: NotUniqueMsg, 95 arguments: map[string]string{"object": string(resourceType)}, 96 } 97 } 98 99 // NewNotUniqueErrorWithMessage constructs a new NotUniqueError with a custom message 100 func NewNotUniqueErrorWithMessage(resourceType resource.Type, message string) error { 101 return Error{ 102 errorCode: NotUnique, 103 Message: fmt.Sprintf(NotUniqueMsgF, message), 104 arguments: map[string]string{"object": string(resourceType)}, 105 } 106 } 107 108 // NewNotUniqueNameError missing godoc 109 func NewNotUniqueNameError(resourceType resource.Type) error { 110 return Error{ 111 errorCode: NotUniqueName, 112 Message: NotUniqueNameMsg, 113 arguments: map[string]string{"object": string(resourceType)}, 114 } 115 } 116 117 // NewNotFoundError missing godoc 118 func NewNotFoundError(resourceType resource.Type, objectID string) error { 119 return Error{ 120 errorCode: NotFound, 121 Message: NotFoundMsg, 122 arguments: map[string]string{"object": string(resourceType), "ID": objectID}, 123 parentErr: nil, 124 } 125 } 126 127 // NewNotFoundErrorWithMessage missing godoc 128 func NewNotFoundErrorWithMessage(resourceType resource.Type, objectID string, message string) error { 129 return Error{ 130 errorCode: NotFound, 131 Message: fmt.Sprintf(NotFoundMsgF, message), 132 arguments: map[string]string{"object": string(resourceType), "ID": objectID}, 133 parentErr: nil, 134 } 135 } 136 137 // NewNotFoundErrorWithType missing godoc 138 func NewNotFoundErrorWithType(resourceType resource.Type) error { 139 return Error{ 140 errorCode: NotFound, 141 Message: NotFoundMsg, 142 arguments: map[string]string{"object": string(resourceType)}, 143 parentErr: nil, 144 } 145 } 146 147 // NewInvalidDataError missing godoc 148 func NewInvalidDataError(msg string, args ...interface{}) error { 149 return Error{ 150 errorCode: InvalidData, 151 Message: InvalidDataMsg, 152 arguments: map[string]string{"reason": fmt.Sprintf(msg, args...)}, 153 } 154 } 155 156 // NewInvalidDataErrorWithFields missing godoc 157 func NewInvalidDataErrorWithFields(fields map[string]error, objType string) error { 158 if len(fields) == 0 { 159 return nil 160 } 161 162 err := Error{ 163 errorCode: InvalidData, 164 Message: fmt.Sprintf("%s %s", InvalidDataMsg, objType), 165 arguments: map[string]string{}, 166 } 167 168 for k, v := range fields { 169 err.arguments[k] = v.Error() 170 } 171 return err 172 } 173 174 // NewInternalError missing godoc 175 func NewInternalError(msg string, args ...interface{}) error { 176 errMsg := fmt.Sprintf(msg, args...) 177 return Error{ 178 errorCode: InternalError, 179 Message: fmt.Sprintf(InternalServerErrMsgF, errMsg), 180 arguments: map[string]string{}, 181 } 182 } 183 184 // InternalErrorFrom missing godoc 185 func InternalErrorFrom(err error, msg string, args ...interface{}) error { 186 errMsg := fmt.Sprintf(msg, args...) 187 return Error{ 188 errorCode: InternalError, 189 Message: fmt.Sprintf(InternalServerErrMsgF, errMsg), 190 arguments: map[string]string{}, 191 parentErr: err, 192 } 193 } 194 195 // NewTenantNotFoundError missing godoc 196 func NewTenantNotFoundError(externalTenant string) error { 197 return Error{ 198 errorCode: TenantNotFound, 199 Message: TenantNotFoundMsg, 200 arguments: map[string]string{"externalTenant": externalTenant}, 201 } 202 } 203 204 // NewTenantRequiredError missing godoc 205 func NewTenantRequiredError() error { 206 return Error{ 207 errorCode: TenantRequired, 208 Message: TenantRequiredMsg, 209 arguments: map[string]string{}, 210 } 211 } 212 213 // NewInvalidOperationError missing godoc 214 func NewInvalidOperationError(reason string) error { 215 return Error{ 216 errorCode: InvalidOperation, 217 Message: InvalidOperationMsg, 218 arguments: map[string]string{"reason": reason}, 219 } 220 } 221 222 // NewForeignKeyInvalidOperationError missing godoc 223 func NewForeignKeyInvalidOperationError(sqlOperation resource.SQLOperation, resourceType resource.Type) error { 224 var reason string 225 switch sqlOperation { 226 case resource.Create, resource.Update, resource.Upsert: 227 reason = "The referenced entity does not exists" 228 case resource.Delete: 229 reason = "The record cannot be deleted because another record refers to it" 230 } 231 232 return Error{ 233 errorCode: InvalidOperation, 234 Message: InvalidOperationMsg, 235 arguments: map[string]string{"reason": reason, "object": string(resourceType)}, 236 } 237 } 238 239 const valueNotFoundInConfigMsg = "value under specified path not found in configuration" 240 241 // NewValueNotFoundInConfigurationError missing godoc 242 func NewValueNotFoundInConfigurationError() error { 243 return Error{ 244 errorCode: NotFound, 245 Message: valueNotFoundInConfigMsg, 246 arguments: map[string]string{}, 247 } 248 } 249 250 // NewNoScopesInContextError missing godoc 251 func NewNoScopesInContextError() error { 252 return Error{ 253 errorCode: NotFound, 254 Message: NoScopesInContextMsg, 255 arguments: map[string]string{}, 256 } 257 } 258 259 // NewRequiredScopesNotDefinedError missing godoc 260 func NewRequiredScopesNotDefinedError() error { 261 return Error{ 262 errorCode: InsufficientScopes, 263 Message: NoRequiredScopesInContextMsg, 264 arguments: map[string]string{}, 265 } 266 } 267 268 // NewKeyDoesNotExistError missing godoc 269 func NewKeyDoesNotExistError(key string) error { 270 return Error{ 271 errorCode: NotFound, 272 Message: KeyDoesNotExistMsg, 273 arguments: map[string]string{"key": key}, 274 } 275 } 276 277 // NewInsufficientScopesError missing godoc 278 func NewInsufficientScopesError(requiredScopes, actualScopes []string) error { 279 return Error{ 280 errorCode: InsufficientScopes, 281 Message: InsufficientScopesMsg, 282 arguments: map[string]string{"required": strings.Join(requiredScopes, ";"), 283 "actual": strings.Join(actualScopes, ";")}, 284 parentErr: nil, 285 } 286 } 287 288 // NewCannotReadTenantError missing godoc 289 func NewCannotReadTenantError() error { 290 return Error{ 291 errorCode: InternalError, 292 Message: CannotReadTenantMsg, 293 arguments: map[string]string{}, 294 } 295 } 296 297 // NewCannotReadClientUserError missing godoc 298 func NewCannotReadClientUserError() error { 299 return Error{ 300 errorCode: InternalError, 301 Message: CannotReadClientUserMsg, 302 arguments: map[string]string{}, 303 } 304 } 305 306 // NewUnauthorizedError missing godoc 307 func NewUnauthorizedError(msg string) error { 308 return Error{ 309 errorCode: Unauthorized, 310 Message: UnauthorizedMsg, 311 arguments: map[string]string{"reason": msg}, 312 } 313 } 314 315 // NewConcurrentOperationInProgressError missing godoc 316 func NewConcurrentOperationInProgressError(msg string) error { 317 return Error{ 318 errorCode: ConcurrentOperation, 319 Message: ConcurrentOperationMsg, 320 arguments: map[string]string{"reason": msg}, 321 } 322 } 323 324 // NewInvalidStatusCondition missing godoc 325 func NewInvalidStatusCondition(resourceType resource.Type) error { 326 return Error{ 327 errorCode: InvalidStatusCondition, 328 Message: InvalidStatusConditionMsg, 329 arguments: map[string]string{"object": string(resourceType)}, 330 } 331 } 332 333 // NewCannotUpdateObjectInManyBundles missing godoc 334 func NewCannotUpdateObjectInManyBundles() error { 335 return Error{ 336 errorCode: CannotUpdateObjectInManyBundles, 337 Message: CannotUpdateObjectInManyBundlesMsg, 338 arguments: map[string]string{}, 339 } 340 } 341 342 // NewConcurrentUpdate returns ConcurrentUpdate error 343 func NewConcurrentUpdate() error { 344 return Error{ 345 errorCode: ConcurrentUpdate, 346 Message: ConcurrentUpdateMsg, 347 arguments: map[string]string{}, 348 } 349 } 350 351 // NewCustomErrorWithCode returns Error with a given code and message 352 func NewCustomErrorWithCode(code int, msg string) error { 353 return Error{ 354 errorCode: ErrorType(code), 355 Message: msg, 356 arguments: map[string]string{}, 357 } 358 } 359 360 // NewCannotUnassignObjectComingFromASAError returns CannotUnassignRuntimeContextComingFromASAError error 361 func NewCannotUnassignObjectComingFromASAError(objectID string) error { 362 return Error{ 363 errorCode: InvalidOperation, 364 Message: CannotUnassignObjectFromASA, 365 arguments: map[string]string{"ID": objectID}, 366 } 367 } 368 369 // IsValueNotFoundInConfiguration missing godoc 370 func IsValueNotFoundInConfiguration(err error) bool { 371 if customErr, ok := err.(Error); ok { 372 return customErr.errorCode == NotFound && customErr.Message == valueNotFoundInConfigMsg 373 } 374 return false 375 } 376 377 // IsKeyDoesNotExist missing godoc 378 func IsKeyDoesNotExist(err error) bool { 379 if customErr, ok := err.(Error); ok { 380 return customErr.errorCode == NotFound && customErr.Message == KeyDoesNotExistMsg 381 } 382 return false 383 } 384 385 // IsCannotReadTenant missing godoc 386 func IsCannotReadTenant(err error) bool { 387 if customErr, ok := err.(Error); ok { 388 return customErr.errorCode == InternalError && customErr.Message == CannotReadTenantMsg 389 } 390 return false 391 } 392 393 // IsConcurrentUpdate indicates if the provided error is thrown in case of concurrent update 394 func IsConcurrentUpdate(err error) bool { 395 if customErr, ok := err.(Error); ok { 396 return customErr.errorCode == Unauthorized && strings.Contains(customErr.Message, UnauthorizedMsg) 397 } 398 return false 399 } 400 401 // IsNewInvalidOperationError missing godoc 402 func IsNewInvalidOperationError(err error) bool { 403 return ErrorCode(err) == InvalidOperation 404 } 405 406 // IsNotFoundError missing godoc 407 func IsNotFoundError(err error) bool { 408 return ErrorCode(err) == NotFound 409 } 410 411 // IsTenantRequired missing godoc 412 func IsTenantRequired(err error) bool { 413 return ErrorCode(err) == TenantRequired 414 } 415 416 // IsTenantNotFoundError missing godoc 417 func IsTenantNotFoundError(err error) bool { 418 return ErrorCode(err) == TenantNotFound 419 } 420 421 // IsNotUniqueError missing godoc 422 func IsNotUniqueError(err error) bool { 423 return ErrorCode(err) == NotUnique 424 } 425 426 // IsNewNotNullViolationError missing godoc 427 func IsNewNotNullViolationError(err error) bool { 428 return ErrorCode(err) == EmptyData 429 } 430 431 // IsNewCheckViolationError missing godoc 432 func IsNewCheckViolationError(err error) bool { 433 return ErrorCode(err) == InconsistentData 434 } 435 436 // IsInvalidStatusCondition missing godoc 437 func IsInvalidStatusCondition(err error) bool { 438 return ErrorCode(err) == InvalidStatusCondition 439 } 440 441 // IsCannotUpdateObjectInManyBundlesError missing godoc 442 func IsCannotUpdateObjectInManyBundlesError(err error) bool { 443 return ErrorCode(err) == CannotUpdateObjectInManyBundles 444 } 445 446 // IsCannotUnassignObjectComingFromASAError missing godoc 447 func IsCannotUnassignObjectComingFromASAError(err error) bool { 448 if customErr, ok := err.(Error); ok { 449 return customErr.errorCode == InvalidOperation && customErr.Message == CannotUnassignObjectFromASA 450 } 451 return false 452 } 453 454 func sortMapKey(m map[string]string) []string { 455 keys := make([]string, 0, len(m)) 456 for k := range m { 457 keys = append(keys, k) 458 } 459 460 sort.Strings(keys) 461 return keys 462 }