Skip to content

Commit aed5c43

Browse files
authored
feat: index referrers on manifest delete (#350)
Signed-off-by: Lixia (Sylvia) Lei <lixlei@microsoft.com>
1 parent 05fb30a commit aed5c43

File tree

2 files changed

+564
-12
lines changed

2 files changed

+564
-12
lines changed

registry/remote/repository.go

+101-8
Original file line numberDiff line numberDiff line change
@@ -928,11 +928,103 @@ func (s *manifestStore) Exists(ctx context.Context, target ocispec.Descriptor) (
928928
return false, err
929929
}
930930

931-
// Delete removes the content identified by the descriptor.
931+
// Delete removes the manifest content identified by the descriptor.
932932
func (s *manifestStore) Delete(ctx context.Context, target ocispec.Descriptor) error {
933+
return s.deleteWithIndexing(ctx, target)
934+
}
935+
936+
// deleteWithIndexing removes the manifest content identified by the descriptor,
937+
// and indexes referrers for the manifest when needed.
938+
func (s *manifestStore) deleteWithIndexing(ctx context.Context, target ocispec.Descriptor) error {
939+
if target.MediaType == ocispec.MediaTypeArtifactManifest || target.MediaType == ocispec.MediaTypeImageManifest {
940+
if state := s.repo.loadReferrersState(); state == referrersStateSupported {
941+
// referrers API is available, no client-side indexing needed
942+
return s.repo.delete(ctx, target, true)
943+
}
944+
945+
if err := limitSize(target, s.repo.MaxMetadataBytes); err != nil {
946+
return err
947+
}
948+
manifestJSON, err := content.FetchAll(ctx, s, target)
949+
if err != nil {
950+
return err
951+
}
952+
if err := s.indexReferrersForDelete(ctx, target, manifestJSON); err != nil {
953+
return err
954+
}
955+
}
956+
933957
return s.repo.delete(ctx, target, true)
934958
}
935959

960+
// indexReferrersForDelete indexes referrers for image or artifact manifest with
961+
// the subject field on manifest delete.
962+
// Reference: https://github.com/opencontainers/distribution-spec/blob/main/spec.md#deleting-manifests
963+
func (s *manifestStore) indexReferrersForDelete(ctx context.Context, desc ocispec.Descriptor, manifestJSON []byte) error {
964+
var manifest struct {
965+
Subject *ocispec.Descriptor `json:"subject"`
966+
}
967+
if err := json.Unmarshal(manifestJSON, &manifest); err != nil {
968+
return fmt.Errorf("failed to decode manifest: %s: %s: %w", desc.Digest, desc.MediaType, err)
969+
}
970+
if manifest.Subject == nil {
971+
// no subject, no indexing needed
972+
return nil
973+
}
974+
975+
subject := *manifest.Subject
976+
yes, err := s.repo.isReferrersAPIAvailable(ctx, subject)
977+
if err != nil {
978+
return err
979+
}
980+
if yes {
981+
// referrers API is available, no client-side indexing needed
982+
return nil
983+
}
984+
return s.updateReferrersIndexForDelete(ctx, desc, subject)
985+
}
986+
987+
// updateReferrersIndexForDelete updates the referrers index for desc referencing
988+
// subject on manifest delete.
989+
func (s *manifestStore) updateReferrersIndexForDelete(ctx context.Context, desc, subject ocispec.Descriptor) error {
990+
// there can be multiple go-routines updating the referrers tag concurrently
991+
referrersTag := buildReferrersTag(subject)
992+
s.repo.lockReferrersTag(referrersTag)
993+
defer s.repo.unlockReferrersTag(referrersTag)
994+
995+
oldIndexDesc, referrers, err := s.repo.referrersFromIndex(ctx, referrersTag)
996+
if err != nil {
997+
if errors.Is(err, errdef.ErrNotFound) {
998+
// inconsistent indexing state: no old index found, skip update
999+
return nil
1000+
}
1001+
return err
1002+
}
1003+
if len(referrers) == 0 {
1004+
// inconsistent indexing state: no referrers to the subject, skip update
1005+
return nil
1006+
}
1007+
1008+
var updatedReferrers []ocispec.Descriptor
1009+
for _, r := range referrers {
1010+
// remove the current entry
1011+
if !content.Equal(r, desc) {
1012+
updatedReferrers = append(updatedReferrers, r)
1013+
}
1014+
}
1015+
if len(updatedReferrers) > 0 {
1016+
newIndexDesc, newIndex, err := generateIndex(updatedReferrers)
1017+
if err != nil {
1018+
return fmt.Errorf("failed to generate referrers index for referrers tag %s: %w", referrersTag, err)
1019+
}
1020+
if err := s.push(ctx, newIndexDesc, bytes.NewReader(newIndex), referrersTag); err != nil {
1021+
return fmt.Errorf("failed to push referrers index tagged by %s: %w", referrersTag, err)
1022+
}
1023+
}
1024+
1025+
return s.repo.delete(ctx, oldIndexDesc, true)
1026+
}
1027+
9361028
// Resolve resolves a reference to a descriptor.
9371029
// See also `ManifestMediaTypes`.
9381030
func (s *manifestStore) Resolve(ctx context.Context, reference string) (ocispec.Descriptor, error) {
@@ -1106,16 +1198,16 @@ func (s *manifestStore) pushWithIndexing(ctx context.Context, expected ocispec.D
11061198
if err := s.push(ctx, expected, bytes.NewReader(manifestJSON), reference); err != nil {
11071199
return err
11081200
}
1109-
return s.indexReferrers(ctx, expected, manifestJSON)
1201+
return s.indexReferrersForPush(ctx, expected, manifestJSON)
11101202
default:
11111203
return s.push(ctx, expected, r, reference)
11121204
}
11131205
}
11141206

1115-
// indexReferrers indexes referrers for image or artifact manifest with
1116-
// the subject field.
1207+
// indexReferrersForPush indexes referrers for image or artifact manifest with
1208+
// the subject field on manifest push.
11171209
// Reference: https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pushing-manifests-with-subject
1118-
func (s *manifestStore) indexReferrers(ctx context.Context, desc ocispec.Descriptor, manifestJSON []byte) error {
1210+
func (s *manifestStore) indexReferrersForPush(ctx context.Context, desc ocispec.Descriptor, manifestJSON []byte) error {
11191211
var subject ocispec.Descriptor
11201212
switch desc.MediaType {
11211213
case ocispec.MediaTypeArtifactManifest:
@@ -1154,11 +1246,12 @@ func (s *manifestStore) indexReferrers(ctx context.Context, desc ocispec.Descrip
11541246
// referrers API is available, no client-side indexing needed
11551247
return nil
11561248
}
1157-
return s.updateReferrersIndex(ctx, desc, subject)
1249+
return s.updateReferrersIndexForPush(ctx, desc, subject)
11581250
}
11591251

1160-
// updateReferrersIndex updates the referrers index for desc referencing subject.
1161-
func (s *manifestStore) updateReferrersIndex(ctx context.Context, desc, subject ocispec.Descriptor) error {
1252+
// updateReferrersIndexForPush updates the referrers index for desc referencing
1253+
// subject on manifest push.
1254+
func (s *manifestStore) updateReferrersIndexForPush(ctx context.Context, desc, subject ocispec.Descriptor) error {
11621255
// there can be multiple go-routines updating the referrers tag concurrently
11631256
referrersTag := buildReferrersTag(subject)
11641257
s.repo.lockReferrersTag(referrersTag)

0 commit comments

Comments
 (0)