mirror of
https://github.com/containers/skopeo.git
synced 2025-04-28 03:10:18 +00:00
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: Miloslav Trmač <mitr@redhat.com>
444 lines
11 KiB
Go
444 lines
11 KiB
Go
/*
|
|
Copyright The containerd Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
// Package errdefs defines the common errors used throughout containerd
|
|
// packages.
|
|
//
|
|
// Use with fmt.Errorf to add context to an error.
|
|
//
|
|
// To detect an error class, use the IsXXX functions to tell whether an error
|
|
// is of a certain type.
|
|
package errdefs
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
)
|
|
|
|
// Definitions of common error types used throughout containerd. All containerd
|
|
// errors returned by most packages will map into one of these errors classes.
|
|
// Packages should return errors of these types when they want to instruct a
|
|
// client to take a particular action.
|
|
//
|
|
// These errors map closely to grpc errors.
|
|
var (
|
|
ErrUnknown = errUnknown{}
|
|
ErrInvalidArgument = errInvalidArgument{}
|
|
ErrNotFound = errNotFound{}
|
|
ErrAlreadyExists = errAlreadyExists{}
|
|
ErrPermissionDenied = errPermissionDenied{}
|
|
ErrResourceExhausted = errResourceExhausted{}
|
|
ErrFailedPrecondition = errFailedPrecondition{}
|
|
ErrConflict = errConflict{}
|
|
ErrNotModified = errNotModified{}
|
|
ErrAborted = errAborted{}
|
|
ErrOutOfRange = errOutOfRange{}
|
|
ErrNotImplemented = errNotImplemented{}
|
|
ErrInternal = errInternal{}
|
|
ErrUnavailable = errUnavailable{}
|
|
ErrDataLoss = errDataLoss{}
|
|
ErrUnauthenticated = errUnauthorized{}
|
|
)
|
|
|
|
// cancelled maps to Moby's "ErrCancelled"
|
|
type cancelled interface {
|
|
Cancelled()
|
|
}
|
|
|
|
// IsCanceled returns true if the error is due to `context.Canceled`.
|
|
func IsCanceled(err error) bool {
|
|
return errors.Is(err, context.Canceled) || isInterface[cancelled](err)
|
|
}
|
|
|
|
type errUnknown struct{}
|
|
|
|
func (errUnknown) Error() string { return "unknown" }
|
|
|
|
func (errUnknown) Unknown() {}
|
|
|
|
func (e errUnknown) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// unknown maps to Moby's "ErrUnknown"
|
|
type unknown interface {
|
|
Unknown()
|
|
}
|
|
|
|
// IsUnknown returns true if the error is due to an unknown error,
|
|
// unhandled condition or unexpected response.
|
|
func IsUnknown(err error) bool {
|
|
return errors.Is(err, errUnknown{}) || isInterface[unknown](err)
|
|
}
|
|
|
|
type errInvalidArgument struct{}
|
|
|
|
func (errInvalidArgument) Error() string { return "invalid argument" }
|
|
|
|
func (errInvalidArgument) InvalidParameter() {}
|
|
|
|
func (e errInvalidArgument) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// invalidParameter maps to Moby's "ErrInvalidParameter"
|
|
type invalidParameter interface {
|
|
InvalidParameter()
|
|
}
|
|
|
|
// IsInvalidArgument returns true if the error is due to an invalid argument
|
|
func IsInvalidArgument(err error) bool {
|
|
return errors.Is(err, ErrInvalidArgument) || isInterface[invalidParameter](err)
|
|
}
|
|
|
|
// deadlineExceed maps to Moby's "ErrDeadline"
|
|
type deadlineExceeded interface {
|
|
DeadlineExceeded()
|
|
}
|
|
|
|
// IsDeadlineExceeded returns true if the error is due to
|
|
// `context.DeadlineExceeded`.
|
|
func IsDeadlineExceeded(err error) bool {
|
|
return errors.Is(err, context.DeadlineExceeded) || isInterface[deadlineExceeded](err)
|
|
}
|
|
|
|
type errNotFound struct{}
|
|
|
|
func (errNotFound) Error() string { return "not found" }
|
|
|
|
func (errNotFound) NotFound() {}
|
|
|
|
func (e errNotFound) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// notFound maps to Moby's "ErrNotFound"
|
|
type notFound interface {
|
|
NotFound()
|
|
}
|
|
|
|
// IsNotFound returns true if the error is due to a missing object
|
|
func IsNotFound(err error) bool {
|
|
return errors.Is(err, ErrNotFound) || isInterface[notFound](err)
|
|
}
|
|
|
|
type errAlreadyExists struct{}
|
|
|
|
func (errAlreadyExists) Error() string { return "already exists" }
|
|
|
|
func (errAlreadyExists) AlreadyExists() {}
|
|
|
|
func (e errAlreadyExists) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
type alreadyExists interface {
|
|
AlreadyExists()
|
|
}
|
|
|
|
// IsAlreadyExists returns true if the error is due to an already existing
|
|
// metadata item
|
|
func IsAlreadyExists(err error) bool {
|
|
return errors.Is(err, ErrAlreadyExists) || isInterface[alreadyExists](err)
|
|
}
|
|
|
|
type errPermissionDenied struct{}
|
|
|
|
func (errPermissionDenied) Error() string { return "permission denied" }
|
|
|
|
func (errPermissionDenied) Forbidden() {}
|
|
|
|
func (e errPermissionDenied) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// forbidden maps to Moby's "ErrForbidden"
|
|
type forbidden interface {
|
|
Forbidden()
|
|
}
|
|
|
|
// IsPermissionDenied returns true if the error is due to permission denied
|
|
// or forbidden (403) response
|
|
func IsPermissionDenied(err error) bool {
|
|
return errors.Is(err, ErrPermissionDenied) || isInterface[forbidden](err)
|
|
}
|
|
|
|
type errResourceExhausted struct{}
|
|
|
|
func (errResourceExhausted) Error() string { return "resource exhausted" }
|
|
|
|
func (errResourceExhausted) ResourceExhausted() {}
|
|
|
|
func (e errResourceExhausted) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
type resourceExhausted interface {
|
|
ResourceExhausted()
|
|
}
|
|
|
|
// IsResourceExhausted returns true if the error is due to
|
|
// a lack of resources or too many attempts.
|
|
func IsResourceExhausted(err error) bool {
|
|
return errors.Is(err, errResourceExhausted{}) || isInterface[resourceExhausted](err)
|
|
}
|
|
|
|
type errFailedPrecondition struct{}
|
|
|
|
func (e errFailedPrecondition) Error() string { return "failed precondition" }
|
|
|
|
func (errFailedPrecondition) FailedPrecondition() {}
|
|
|
|
func (e errFailedPrecondition) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
type failedPrecondition interface {
|
|
FailedPrecondition()
|
|
}
|
|
|
|
// IsFailedPrecondition returns true if an operation could not proceed due to
|
|
// the lack of a particular condition
|
|
func IsFailedPrecondition(err error) bool {
|
|
return errors.Is(err, errFailedPrecondition{}) || isInterface[failedPrecondition](err)
|
|
}
|
|
|
|
type errConflict struct{}
|
|
|
|
func (errConflict) Error() string { return "conflict" }
|
|
|
|
func (errConflict) Conflict() {}
|
|
|
|
func (e errConflict) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// conflict maps to Moby's "ErrConflict"
|
|
type conflict interface {
|
|
Conflict()
|
|
}
|
|
|
|
// IsConflict returns true if an operation could not proceed due to
|
|
// a conflict.
|
|
func IsConflict(err error) bool {
|
|
return errors.Is(err, errConflict{}) || isInterface[conflict](err)
|
|
}
|
|
|
|
type errNotModified struct{}
|
|
|
|
func (errNotModified) Error() string { return "not modified" }
|
|
|
|
func (errNotModified) NotModified() {}
|
|
|
|
func (e errNotModified) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// notModified maps to Moby's "ErrNotModified"
|
|
type notModified interface {
|
|
NotModified()
|
|
}
|
|
|
|
// IsNotModified returns true if an operation could not proceed due
|
|
// to an object not modified from a previous state.
|
|
func IsNotModified(err error) bool {
|
|
return errors.Is(err, errNotModified{}) || isInterface[notModified](err)
|
|
}
|
|
|
|
type errAborted struct{}
|
|
|
|
func (errAborted) Error() string { return "aborted" }
|
|
|
|
func (errAborted) Aborted() {}
|
|
|
|
func (e errAborted) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
type aborted interface {
|
|
Aborted()
|
|
}
|
|
|
|
// IsAborted returns true if an operation was aborted.
|
|
func IsAborted(err error) bool {
|
|
return errors.Is(err, errAborted{}) || isInterface[aborted](err)
|
|
}
|
|
|
|
type errOutOfRange struct{}
|
|
|
|
func (errOutOfRange) Error() string { return "out of range" }
|
|
|
|
func (errOutOfRange) OutOfRange() {}
|
|
|
|
func (e errOutOfRange) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
type outOfRange interface {
|
|
OutOfRange()
|
|
}
|
|
|
|
// IsOutOfRange returns true if an operation could not proceed due
|
|
// to data being out of the expected range.
|
|
func IsOutOfRange(err error) bool {
|
|
return errors.Is(err, errOutOfRange{}) || isInterface[outOfRange](err)
|
|
}
|
|
|
|
type errNotImplemented struct{}
|
|
|
|
func (errNotImplemented) Error() string { return "not implemented" }
|
|
|
|
func (errNotImplemented) NotImplemented() {}
|
|
|
|
func (e errNotImplemented) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// notImplemented maps to Moby's "ErrNotImplemented"
|
|
type notImplemented interface {
|
|
NotImplemented()
|
|
}
|
|
|
|
// IsNotImplemented returns true if the error is due to not being implemented
|
|
func IsNotImplemented(err error) bool {
|
|
return errors.Is(err, errNotImplemented{}) || isInterface[notImplemented](err)
|
|
}
|
|
|
|
type errInternal struct{}
|
|
|
|
func (errInternal) Error() string { return "internal" }
|
|
|
|
func (errInternal) System() {}
|
|
|
|
func (e errInternal) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// system maps to Moby's "ErrSystem"
|
|
type system interface {
|
|
System()
|
|
}
|
|
|
|
// IsInternal returns true if the error returns to an internal or system error
|
|
func IsInternal(err error) bool {
|
|
return errors.Is(err, errInternal{}) || isInterface[system](err)
|
|
}
|
|
|
|
type errUnavailable struct{}
|
|
|
|
func (errUnavailable) Error() string { return "unavailable" }
|
|
|
|
func (errUnavailable) Unavailable() {}
|
|
|
|
func (e errUnavailable) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// unavailable maps to Moby's "ErrUnavailable"
|
|
type unavailable interface {
|
|
Unavailable()
|
|
}
|
|
|
|
// IsUnavailable returns true if the error is due to a resource being unavailable
|
|
func IsUnavailable(err error) bool {
|
|
return errors.Is(err, errUnavailable{}) || isInterface[unavailable](err)
|
|
}
|
|
|
|
type errDataLoss struct{}
|
|
|
|
func (errDataLoss) Error() string { return "data loss" }
|
|
|
|
func (errDataLoss) DataLoss() {}
|
|
|
|
func (e errDataLoss) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// dataLoss maps to Moby's "ErrDataLoss"
|
|
type dataLoss interface {
|
|
DataLoss()
|
|
}
|
|
|
|
// IsDataLoss returns true if data during an operation was lost or corrupted
|
|
func IsDataLoss(err error) bool {
|
|
return errors.Is(err, errDataLoss{}) || isInterface[dataLoss](err)
|
|
}
|
|
|
|
type errUnauthorized struct{}
|
|
|
|
func (errUnauthorized) Error() string { return "unauthorized" }
|
|
|
|
func (errUnauthorized) Unauthorized() {}
|
|
|
|
func (e errUnauthorized) WithMessage(msg string) error {
|
|
return customMessage{e, msg}
|
|
}
|
|
|
|
// unauthorized maps to Moby's "ErrUnauthorized"
|
|
type unauthorized interface {
|
|
Unauthorized()
|
|
}
|
|
|
|
// IsUnauthorized returns true if the error indicates that the user was
|
|
// unauthenticated or unauthorized.
|
|
func IsUnauthorized(err error) bool {
|
|
return errors.Is(err, errUnauthorized{}) || isInterface[unauthorized](err)
|
|
}
|
|
|
|
func isInterface[T any](err error) bool {
|
|
for {
|
|
switch x := err.(type) {
|
|
case T:
|
|
return true
|
|
case customMessage:
|
|
err = x.err
|
|
case interface{ Unwrap() error }:
|
|
err = x.Unwrap()
|
|
if err == nil {
|
|
return false
|
|
}
|
|
case interface{ Unwrap() []error }:
|
|
for _, err := range x.Unwrap() {
|
|
if isInterface[T](err) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
// customMessage is used to provide a defined error with a custom message.
|
|
// The message is not wrapped but can be compared by the `Is(error) bool` interface.
|
|
type customMessage struct {
|
|
err error
|
|
msg string
|
|
}
|
|
|
|
func (c customMessage) Is(err error) bool {
|
|
return c.err == err
|
|
}
|
|
|
|
func (c customMessage) As(target any) bool {
|
|
return errors.As(c.err, target)
|
|
}
|
|
|
|
func (c customMessage) Error() string {
|
|
return c.msg
|
|
}
|