Skip to content

Commit

Permalink
feat: add type for failure during deleting dangling referrer index (#482
Browse files Browse the repository at this point in the history
)

Resolves #479
Signed-off-by: Billy Zha <jinzha1@microsoft.com>
  • Loading branch information
qweeah authored Apr 27, 2023
1 parent e8225cb commit b74a2a1
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 9 deletions.
69 changes: 61 additions & 8 deletions registry/remote/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
Expand All @@ -38,14 +39,18 @@ import (
)

const (
exampleRepositoryName = "example"
exampleTag = "latest"
exampleConfig = "Example config content"
exampleLayer = "Example layer content"
exampleUploadUUid = "0bc84d80-837c-41d9-824e-1907463c53b3"
ManifestDigest = "sha256:0b696106ecd0654e031f19e0a8cbd1aee4ad457d7c9cea881f07b12a930cd307"
ReferenceManifestDigest = "sha256:6983f495f7ee70d43e571657ae8b39ca3d3ca1b0e77270fd4fbddfb19832a1cf"
_ = ExampleUnplayable
exampleRepositoryName = "example"
exampleTag = "latest"
exampleConfig = "Example config content"
exampleLayer = "Example layer content"
exampleUploadUUid = "0bc84d80-837c-41d9-824e-1907463c53b3"
ManifestDigest = "sha256:0b696106ecd0654e031f19e0a8cbd1aee4ad457d7c9cea881f07b12a930cd307"
ReferenceManifestDigest = "sha256:6983f495f7ee70d43e571657ae8b39ca3d3ca1b0e77270fd4fbddfb19832a1cf"
referrersAPIUnavailableRepositoryName = "no-referrers-api"
referrerDigest = "sha256:21c623eb8ccd273f2702efd74a0abb455dd06a99987f413c2114fb00961ebfe7"
referrersTag = "sha256-c824a9aa7d2e3471306648c6d4baa1abbcb97ff0276181ab4722ca27127cdba0"
referrerIndexDigest = "sha256:7baac5147dd58d56fdbaad5a888fa919235a3a90cb71aaa8b56ee5d19f4cd838"
_ = ExampleUnplayable
)

var (
Expand Down Expand Up @@ -99,6 +104,15 @@ var (
ArtifactType: "example/manifest",
Digest: digest.FromBytes(exampleManifestWithBlobs),
Size: int64(len(exampleManifestWithBlobs))}
subjectDescriptor = content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, []byte(`{"layers":[]}`))
referrerManifestContent, _ = json.Marshal(ocispec.Manifest{
MediaType: ocispec.MediaTypeImageManifest,
Subject: &subjectDescriptor,
})
referrerDescriptor = content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, referrerManifestContent)
referrerIndex, _ = json.Marshal(ocispec.Index{
Manifests: []ocispec.Descriptor{},
})
)

var host string
Expand Down Expand Up @@ -205,6 +219,20 @@ func TestMain(m *testing.M) {
if m == "GET" {
w.Write([]byte(resultBlob))
}
case p == fmt.Sprintf("/v2/%s/referrers/%s", referrersAPIUnavailableRepositoryName, "sha256:0000000000000000000000000000000000000000000000000000000000000000"):
w.WriteHeader(http.StatusNotFound)
case p == fmt.Sprintf("/v2/%s/manifests/%s", referrersAPIUnavailableRepositoryName, referrerDigest) && m == http.MethodPut:
w.WriteHeader(http.StatusCreated)
case p == fmt.Sprintf("/v2/%s/manifests/%s", referrersAPIUnavailableRepositoryName, referrersTag) && m == http.MethodGet:
w.Write(referrerIndex)
w.Header().Set("Content-Type", ocispec.MediaTypeImageIndex)
w.Header().Set("Content-Length", strconv.Itoa(len(referrerIndex)))
w.Header().Set("Docker-Content-Digest", digest.Digest(string(referrerIndex)).String())
w.WriteHeader(http.StatusCreated)
case p == fmt.Sprintf("/v2/%s/manifests/%s", referrersAPIUnavailableRepositoryName, referrersTag) && m == http.MethodPut:
w.WriteHeader(http.StatusCreated)
case p == fmt.Sprintf("/v2/%s/manifests/%s", referrersAPIUnavailableRepositoryName, referrerIndexDigest) && m == http.MethodDelete:
w.WriteHeader(http.StatusMethodNotAllowed)
}

}))
Expand Down Expand Up @@ -785,3 +813,28 @@ func Example_tagReference() {
// Output:
// Tagged sha256:b53dc03a49f383ba230d8ac2b78a9c4aec132e4a9f36cc96524df98163202cc7 as latest
}

// Example_pushAndIgnoreReferrersIndexError gives example snippets on how to
// ignore referrer index deletion error during push a referrer manifest.
func Example_pushAndIgnoreReferrersIndexError() {
repo, err := remote.NewRepository(fmt.Sprintf("%s/%s", host, referrersAPIUnavailableRepositoryName))
if err != nil {
panic(err)
}
ctx := context.Background()

// push a referrer manifest and ignore cleaning up error
err = repo.Push(ctx, referrerDescriptor, bytes.NewReader(referrerManifestContent))
if err != nil {
var re *remote.ReferrersError
if !errors.As(err, &re) || !re.IsReferrersIndexDelete() {
panic(err)
}
fmt.Println("ignoring error occurred during cleaning obsolete referrers index")
}
fmt.Println("Push finished")

// Output:
// ignoring error occurred during cleaning obsolete referrers index
// Push finished
}
32 changes: 32 additions & 0 deletions registry/remote/referrers.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,38 @@ var (
errNoReferrerUpdate = errors.New("no referrer update")
)

const (
// opDeleteReferrersIndex represents the operation for deleting a
// referrers index.
opDeleteReferrersIndex = "DeleteReferrersIndex"
)

// ReferrersError records an error and the operation and the subject descriptor.
type ReferrersError struct {
// Op represents the failing operation.
Op string
// Subject is the descriptor of referenced artifact.
Subject ocispec.Descriptor
// Err is the entity of referrers error.
Err error
}

// Error returns error msg of IgnorableError.
func (e *ReferrersError) Error() string {
return e.Err.Error()
}

// Unwrap returns the inner error of IgnorableError.
func (e *ReferrersError) Unwrap() error {
return errors.Unwrap(e.Err)
}

// IsIndexDelete tells if e is kind of error related to referrers
// index deletion.
func (e *ReferrersError) IsReferrersIndexDelete() bool {
return e.Op == opDeleteReferrersIndex
}

// buildReferrersTag builds the referrers tag for the given manifest descriptor.
// Format: <algorithm>-<digest>
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#unavailable-referrers-api
Expand Down
6 changes: 5 additions & 1 deletion registry/remote/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,11 @@ func (s *manifestStore) updateReferrersIndex(ctx context.Context, subject ocispe
// 4. delete the dangling original referrers index
if !skipDelete {
if err := s.repo.delete(ctx, oldIndexDesc, true); err != nil {
return fmt.Errorf("failed to delete dangling referrers index %s for referrers tag %s: %w", oldIndexDesc.Digest.String(), referrersTag, err)
return &ReferrersError{
Op: opDeleteReferrersIndex,
Err: fmt.Errorf("failed to delete dangling referrers index %s for referrers tag %s: %w", oldIndexDesc.Digest.String(), referrersTag, err),
Subject: subject,
}
}
}
return nil
Expand Down

0 comments on commit b74a2a1

Please sign in to comment.