Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-5.23] 5.23 backports #1696

Merged
merged 4 commits into from Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .cirrus.yml
Expand Up @@ -6,9 +6,9 @@ env:
#### Global variables used for all tasks
####
# Name of the ultimate destination branch for this CI run
DEST_BRANCH: "main"
DEST_BRANCH: "release-5.22"
# CI container image tag (c/skopeo branch name)
SKOPEO_CI_TAG: "main"
SKOPEO_CI_TAG: "release-1.10"
# Use GO module mirror (reason unknown, travis did it this way)
GOPROXY: https://proxy.golang.org
# Overrides default location (/tmp/cirrus) for repo clone
Expand Down
25 changes: 18 additions & 7 deletions docker/docker_client.go
@@ -1,6 +1,7 @@
package docker

import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
Expand Down Expand Up @@ -983,15 +984,25 @@ func (c *dockerClient) getOCIDescriptorContents(ctx context.Context, ref dockerR
// isManifestUnknownError returns true iff err from fetchManifest is a “manifest unknown” error.
func isManifestUnknownError(err error) bool {
var errs errcode.Errors
if !errors.As(err, &errs) || len(errs) == 0 {
return false
if errors.As(err, &errs) && len(errs) != 0 {
firstErr := errs[0]
// docker/distribution, and as defined in the spec
var ec errcode.ErrorCoder
if errors.As(firstErr, &ec) && ec.ErrorCode() == v2.ErrorCodeManifestUnknown {
return true
}
// registry.redhat.io as of October 2022
var e errcode.Error
if errors.As(firstErr, &e) && e.ErrorCode() == errcode.ErrorCodeUnknown && e.Message == "Not Found" {
return true
}
}
err = errs[0]
ec, ok := err.(errcode.ErrorCoder)
if !ok {
return false
// ALSO registry.redhat.io as of October 2022
var unexpected *unexpectedHTTPResponseError
if errors.As(err, &unexpected) && unexpected.StatusCode == http.StatusNotFound && bytes.Contains(unexpected.Response, []byte("Not found")) {
return true
}
return ec.ErrorCode() == v2.ErrorCodeManifestUnknown
return false
}

// getSigstoreAttachmentManifest loads and parses the manifest for sigstore attachments for
Expand Down
58 changes: 58 additions & 0 deletions docker/docker_client_test.go
@@ -1,6 +1,8 @@
package docker

import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -328,3 +330,59 @@ func TestNeedsNoRetry(t *testing.T) {
t.Fatal("Got the need to retry, but none should be required")
}
}

func TestIsManifestUnknownError(t *testing.T) {
// Mostly a smoke test; we can add more registries here if they need special handling.

for _, c := range []struct{ name, response string }{
{
name: "docker.io when a tag in an _existing repo_ is not found",
response: "HTTP/1.1 404 Not Found\r\n" +
"Connection: close\r\n" +
"Content-Length: 109\r\n" +
"Content-Type: application/json\r\n" +
"Date: Thu, 12 Aug 2021 20:51:32 GMT\r\n" +
"Docker-Distribution-Api-Version: registry/2.0\r\n" +
"Ratelimit-Limit: 100;w=21600\r\n" +
"Ratelimit-Remaining: 100;w=21600\r\n" +
"Strict-Transport-Security: max-age=31536000\r\n" +
"\r\n" +
"{\"errors\":[{\"code\":\"MANIFEST_UNKNOWN\",\"message\":\"manifest unknown\",\"detail\":{\"Tag\":\"this-does-not-exist\"}}]}\n",
},
{
name: "registry.redhat.io/v2/this-does-not-exist/manifests/latest",
response: "HTTP/1.1 404 Not Found\r\n" +
"Connection: close\r\n" +
"Content-Length: 53\r\n" +
"Cache-Control: max-age=0, no-cache, no-store\r\n" +
"Content-Type: application/json\r\n" +
"Date: Thu, 13 Oct 2022 18:15:15 GMT\r\n" +
"Expires: Thu, 13 Oct 2022 18:15:15 GMT\r\n" +
"Pragma: no-cache\r\n" +
"Server: Apache\r\n" +
"Strict-Transport-Security: max-age=63072000; includeSubdomains; preload\r\n" +
"X-Hostname: crane-tbr06.cran-001.prod.iad2.dc.redhat.com\r\n" +
"\r\n" +
"{\"errors\": [{\"code\": \"404\", \"message\": \"Not Found\"}]}\r\n",
},
{
name: "registry.redhat.io/v2/rhosp15-rhel8/openstack-cron/manifests/sha256-8df5e60c42668706ac108b59c559b9187fa2de7e4e262e2967e3e9da35d5a8d7.sig",
response: "HTTP/1.1 404 Not Found\r\n" +
"Connection: close\r\n" +
"Content-Length: 10\r\n" +
"Accept-Ranges: bytes\r\n" +
"Date: Thu, 13 Oct 2022 18:13:53 GMT\r\n" +
"Server: AkamaiNetStorage\r\n" +
"X-Docker-Size: -1\r\n" +
"\r\n" +
"Not found\r\n",
},
} {
resp, err := http.ReadResponse(bufio.NewReader(bytes.NewReader([]byte(c.response))), nil)
require.NoError(t, err, c.name)
err = fmt.Errorf("wrapped: %w", registryHTTPResponseToError(resp))

res := isManifestUnknownError(err)
assert.True(t, res, "%#v", err, c.name)
}
}
1 change: 1 addition & 0 deletions docker/docker_image_dest.go
Expand Up @@ -653,6 +653,7 @@ func (d *dockerImageDestination) putSignaturesToSigstoreAttachments(ctx context.
Digest: "", // We will fill this in later.
Size: 0,
}, nil)
ociConfig.RootFS.Type = "layers"
} else {
logrus.Debugf("Fetching sigstore attachment config %s", ociManifest.Config.Digest.String())
// We don’t benefit from a real BlobInfoCache here because we never try to reuse/mount configs.
Expand Down
3 changes: 2 additions & 1 deletion docker/errors.go
Expand Up @@ -52,7 +52,8 @@ func registryHTTPResponseToError(res *http.Response) error {
if len(response) > 50 {
response = response[:50] + "..."
}
err = fmt.Errorf("StatusCode: %d, %s", e.StatusCode, response)
// %.0w makes e visible to error.Unwrap() without including any text
err = fmt.Errorf("StatusCode: %d, %s%.0w", e.StatusCode, response, e)
}
return err
}