diff --git a/go.mod b/go.mod index 2bc474886..636e146fc 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.27.27 github.com/compose-spec/compose-go/v2 v2.7.2-0.20250703132301-891fce532a51 // main github.com/containerd/console v1.0.5 - github.com/containerd/containerd/v2 v2.1.1 + github.com/containerd/containerd/v2 v2.1.3 github.com/containerd/continuity v0.4.5 github.com/containerd/errdefs v1.0.0 github.com/containerd/log v0.1.0 diff --git a/go.sum b/go.sum index aac2cd025..ff1f48583 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/q github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0= github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI= -github.com/containerd/containerd/v2 v2.1.1 h1:znnkm7Ajz8lg8BcIPMhc/9yjBRN3B+OkNKqKisKfwwM= -github.com/containerd/containerd/v2 v2.1.1/go.mod h1:zIfkQj4RIodclYQkX7GSSswSwgP8d/XxDOtOAoSDIGU= +github.com/containerd/containerd/v2 v2.1.3 h1:eMD2SLcIQPdMlnlNF6fatlrlRLAeDaiGPGwmRKLZKNs= +github.com/containerd/containerd/v2 v2.1.3/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= diff --git a/vendor/github.com/containerd/containerd/v2/core/content/helpers.go b/vendor/github.com/containerd/containerd/v2/core/content/helpers.go index 74cb566b0..749e65311 100644 --- a/vendor/github.com/containerd/containerd/v2/core/content/helpers.go +++ b/vendor/github.com/containerd/containerd/v2/core/content/helpers.go @@ -200,7 +200,7 @@ func Copy(ctx context.Context, cw Writer, or io.Reader, size int64, expected dig } if size != 0 && copied < size-ws.Offset { // Short writes would return its own error, this indicates a read failure - return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF) + return fmt.Errorf("short read: expected %d bytes but got %d: %w", size-ws.Offset, copied, io.ErrUnexpectedEOF) } if err := cw.Commit(ctx, size, expected, opts...); err != nil { if errors.Is(err, ErrReset) { diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errcode.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errcode.go index 8c623bcbe..b62256f82 100644 --- a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errcode.go +++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errcode.go @@ -18,8 +18,12 @@ package docker import ( "encoding/json" + "errors" "fmt" + "net/http" "strings" + + remoteerrors "github.com/containerd/containerd/v2/core/remotes/errors" ) // ErrorCoder is the base interface for ErrorCode and Error allowing @@ -281,3 +285,21 @@ func (errs *Errors) UnmarshalJSON(data []byte) error { *errs = newErrs return nil } + +func unexpectedResponseErr(resp *http.Response) (retErr error) { + retErr = remoteerrors.NewUnexpectedStatusErr(resp) + + // Decode registry error if provided + if rerr := retErr.(remoteerrors.ErrUnexpectedStatus); len(rerr.Body) > 0 { + var registryErr Errors + if err := json.Unmarshal(rerr.Body, ®istryErr); err == nil && registryErr.Len() > 0 { + // Join the unexpected error with the typed errors, when printed it will + // show the unexpected error message and the registry errors. The body + // is always excluded from the unexpected error message. This also allows + // clients to decode into either type. + retErr = errors.Join(rerr, registryErr) + } + } + + return +} diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go index 9388d8479..3e74df8cc 100644 --- a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go +++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go @@ -442,7 +442,7 @@ func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, chunkSize := int64(r.performances.ConcurrentLayerFetchBuffer) parallelism := int64(r.performances.MaxConcurrentDownloads) - if chunkSize < minChunkSize { + if chunkSize < minChunkSize || req.body != nil { parallelism = 1 } log.G(ctx).WithField("initial_parallelism", r.performances.MaxConcurrentDownloads). @@ -452,7 +452,9 @@ func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, Debug("fetching layer") req.setMediaType(mediatype) req.header.Set("Accept-Encoding", "zstd;q=1.0, gzip;q=0.8, deflate;q=0.5") - req.setOffset(offset) + if parallelism > 1 || offset > 0 { + req.setOffset(offset) + } if err := r.Acquire(ctx, 1); err != nil { return nil, err @@ -478,7 +480,11 @@ func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, }) remaining, _ := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 0) - if parallelism > 1 && req.body == nil { + if remaining <= chunkSize { + parallelism = 1 + } + + if parallelism > 1 { // If we have a content length, we can use multiple requests to fetch // the content in parallel. This will make download of bigger bodies // faster, at the cost of parallelism more requests and max diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/pusher.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/pusher.go index eac7b56c1..956e83cbb 100644 --- a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/pusher.go +++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/pusher.go @@ -36,7 +36,6 @@ import ( "github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/images" "github.com/containerd/containerd/v2/core/remotes" - remoteserrors "github.com/containerd/containerd/v2/core/remotes/errors" ) type dockerPusher struct { @@ -149,8 +148,8 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str return nil, fmt.Errorf("content %v on remote: %w", desc.Digest, errdefs.ErrAlreadyExists) } } else if resp.StatusCode != http.StatusNotFound { - err := remoteserrors.NewUnexpectedStatusErr(resp) - log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") + err := unexpectedResponseErr(resp) + log.G(ctx).WithError(err).Debug("unexpected response") resp.Body.Close() return nil, err } @@ -224,8 +223,8 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str }) return nil, fmt.Errorf("content %v on remote: %w", desc.Digest, errdefs.ErrAlreadyExists) default: - err := remoteserrors.NewUnexpectedStatusErr(resp) - log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") + err := unexpectedResponseErr(resp) + log.G(ctx).WithError(err).Debug("unexpected response") return nil, err } @@ -299,8 +298,8 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str switch resp.StatusCode { case http.StatusOK, http.StatusCreated, http.StatusNoContent: default: - err := remoteserrors.NewUnexpectedStatusErr(resp) - log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") + err := unexpectedResponseErr(resp) + log.G(ctx).WithError(err).Debug("unexpected response") pushw.setError(err) return } @@ -513,7 +512,7 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di switch resp.StatusCode { case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: default: - return remoteserrors.NewUnexpectedStatusErr(resp) + return unexpectedResponseErr(resp) } status, err := pw.tracker.GetStatus(pw.ref) diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver.go index 386270ddb..1c0f7c484 100644 --- a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver.go +++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver.go @@ -19,7 +19,6 @@ package docker import ( "context" "crypto/tls" - "encoding/json" "errors" "fmt" "io" @@ -39,7 +38,6 @@ import ( "github.com/containerd/containerd/v2/core/images" "github.com/containerd/containerd/v2/core/remotes" - remoteerrors "github.com/containerd/containerd/v2/core/remotes/errors" "github.com/containerd/containerd/v2/core/transfer" "github.com/containerd/containerd/v2/pkg/reference" "github.com/containerd/containerd/v2/pkg/tracing" @@ -332,13 +330,13 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp } if resp.StatusCode > 399 { if firstErrPriority < 3 { - firstErr = remoteerrors.NewUnexpectedStatusErr(resp) + firstErr = unexpectedResponseErr(resp) firstErrPriority = 3 } log.G(ctx).Infof("%s after status: %s", nextHostOrFail(i), resp.Status) continue // try another host } - return "", ocispec.Descriptor{}, remoteerrors.NewUnexpectedStatusErr(resp) + return "", ocispec.Descriptor{}, unexpectedResponseErr(resp) } size := resp.ContentLength contentType := getManifestMediaType(resp) @@ -653,11 +651,8 @@ func withErrorCheck(r *request, resp *http.Response) error { if resp.StatusCode == http.StatusNotFound { return fmt.Errorf("content at %v not found: %w", r.String(), errdefs.ErrNotFound) } - var registryErr Errors - if err := json.NewDecoder(resp.Body).Decode(®istryErr); err != nil || registryErr.Len() < 1 { - return fmt.Errorf("unexpected status code %v: %v", r.String(), resp.Status) - } - return fmt.Errorf("unexpected status code %v: %s - Server message: %s", r.String(), resp.Status, registryErr.Error()) + + return unexpectedResponseErr(resp) } return nil } diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/errors/errors.go b/vendor/github.com/containerd/containerd/v2/core/remotes/errors/errors.go index f60ff0fc2..d07d17408 100644 --- a/vendor/github.com/containerd/containerd/v2/core/remotes/errors/errors.go +++ b/vendor/github.com/containerd/containerd/v2/core/remotes/errors/errors.go @@ -20,16 +20,23 @@ import ( "fmt" "io" "net/http" + + "github.com/containerd/typeurl/v2" ) var _ error = ErrUnexpectedStatus{} +func init() { + typeurl.Register(&ErrUnexpectedStatus{}, "github.com/containerd/containerd/v2/core/remotes/errors", "ErrUnexpectedStatus") +} + // ErrUnexpectedStatus is returned if a registry API request returned with unexpected HTTP status type ErrUnexpectedStatus struct { - Status string - StatusCode int - Body []byte - RequestURL, RequestMethod string + Status string `json:"status"` + StatusCode int `json:"statusCode"` + Body []byte `json:"body,omitempty"` + RequestURL string `json:"requestURL,omitempty"` + RequestMethod string `json:"requestMethod,omitempty"` } func (e ErrUnexpectedStatus) Error() string { diff --git a/vendor/github.com/containerd/containerd/v2/version/version.go b/vendor/github.com/containerd/containerd/v2/version/version.go index a1f3ae4fb..709cbe947 100644 --- a/vendor/github.com/containerd/containerd/v2/version/version.go +++ b/vendor/github.com/containerd/containerd/v2/version/version.go @@ -24,7 +24,7 @@ var ( Package = "github.com/containerd/containerd/v2" // Version holds the complete version number. Filled in at linking time. - Version = "2.1.1+unknown" + Version = "2.1.3+unknown" // Revision is filled with the VCS (e.g. git) revision being used to build // the program at linking time. diff --git a/vendor/modules.txt b/vendor/modules.txt index 291c6c9a3..e17d1a21d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -144,7 +144,7 @@ github.com/containerd/console # github.com/containerd/containerd/api v1.9.0 ## explicit; go 1.23.0 github.com/containerd/containerd/api/services/content/v1 -# github.com/containerd/containerd/v2 v2.1.1 +# github.com/containerd/containerd/v2 v2.1.3 ## explicit; go 1.23.0 github.com/containerd/containerd/v2/core/content github.com/containerd/containerd/v2/core/content/proxy