zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/extensions/sync/references/referrers_tag.go (about) 1 //go:build sync 2 // +build sync 3 4 package references 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "net/http" 11 "strings" 12 13 godigest "github.com/opencontainers/go-digest" 14 ispec "github.com/opencontainers/image-spec/specs-go/v1" 15 16 zerr "zotregistry.dev/zot/errors" 17 "zotregistry.dev/zot/pkg/common" 18 "zotregistry.dev/zot/pkg/extensions/sync/constants" 19 client "zotregistry.dev/zot/pkg/extensions/sync/httpclient" 20 "zotregistry.dev/zot/pkg/log" 21 "zotregistry.dev/zot/pkg/meta" 22 mTypes "zotregistry.dev/zot/pkg/meta/types" 23 "zotregistry.dev/zot/pkg/storage" 24 ) 25 26 type TagReferences struct { 27 client *client.Client 28 storeController storage.StoreController 29 metaDB mTypes.MetaDB 30 log log.Logger 31 } 32 33 func NewTagReferences(httpClient *client.Client, storeController storage.StoreController, 34 metaDB mTypes.MetaDB, log log.Logger, 35 ) TagReferences { 36 return TagReferences{ 37 client: httpClient, 38 storeController: storeController, 39 metaDB: metaDB, 40 log: log, 41 } 42 } 43 44 func (ref TagReferences) Name() string { 45 return constants.Tag 46 } 47 48 func (ref TagReferences) IsSigned(ctx context.Context, remoteRepo, subjectDigestStr string) bool { 49 return false 50 } 51 52 func (ref TagReferences) canSkipReferences(localRepo, subjectDigestStr, digest string) (bool, error) { 53 imageStore := ref.storeController.GetImageStore(localRepo) 54 55 _, localDigest, _, err := imageStore.GetImageManifest(localRepo, getReferrersTagFromSubjectDigest(subjectDigestStr)) 56 if err != nil { 57 if errors.Is(err, zerr.ErrManifestNotFound) { 58 return false, nil 59 } 60 61 ref.log.Error().Str("errorType", common.TypeOf(err)). 62 Str("repository", localRepo).Str("subject", subjectDigestStr). 63 Err(err).Msg("couldn't get local index with referrers tag for image") 64 65 return false, err 66 } 67 68 if localDigest.String() != digest { 69 return false, nil 70 } 71 72 ref.log.Info().Str("repository", localRepo).Str("reference", subjectDigestStr). 73 Msg("skipping index with referrers tag for image, already synced") 74 75 return true, nil 76 } 77 78 func (ref TagReferences) SyncReferences(ctx context.Context, localRepo, remoteRepo, subjectDigestStr string) ( 79 []godigest.Digest, error, 80 ) { 81 refsDigests := make([]godigest.Digest, 0, 10) 82 83 index, indexContent, err := ref.getIndex(ctx, remoteRepo, subjectDigestStr) 84 if err != nil { 85 return refsDigests, err 86 } 87 88 skipTagRefs, err := ref.canSkipReferences(localRepo, subjectDigestStr, string(godigest.FromBytes(indexContent))) 89 if err != nil { 90 ref.log.Error().Err(err).Str("repository", localRepo).Str("subject", subjectDigestStr). 91 Msg("couldn't check if the upstream index with referrers tag for image can be skipped") 92 } 93 94 if skipTagRefs { 95 return refsDigests, nil 96 } 97 98 imageStore := ref.storeController.GetImageStore(localRepo) 99 100 ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). 101 Msg("syncing oci references for image") 102 103 for _, referrer := range index.Manifests { 104 referenceBuf, referenceDigest, err := syncManifest(ctx, ref.client, imageStore, localRepo, remoteRepo, 105 referrer, subjectDigestStr, ref.log) 106 if err != nil { 107 return refsDigests, err 108 } 109 110 refsDigests = append(refsDigests, referenceDigest) 111 112 if ref.metaDB != nil { 113 ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr).Str("component", "metadb"). 114 Msg("trying to add oci references for image") 115 116 err = meta.SetImageMetaFromInput(ctx, localRepo, referenceDigest.String(), referrer.MediaType, 117 referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo), 118 ref.metaDB, ref.log) 119 if err != nil { 120 return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w", 121 localRepo, subjectDigestStr, err) 122 } 123 124 ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr).Str("component", "metadb"). 125 Msg("successfully added oci references to MetaDB for image") 126 } 127 } 128 129 ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). 130 Msg("syncing index with referrers tag for image") 131 132 referrersTag := getReferrersTagFromSubjectDigest(subjectDigestStr) 133 134 _, _, err = imageStore.PutImageManifest(localRepo, referrersTag, index.MediaType, indexContent) 135 if err != nil { 136 ref.log.Error().Str("errorType", common.TypeOf(err)). 137 Str("repository", localRepo).Str("subject", subjectDigestStr). 138 Err(err).Msg("couldn't upload index with referrers tag for image") 139 140 return refsDigests, err 141 } 142 143 ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). 144 Msg("successfully synced index with referrers tag for image") 145 146 return refsDigests, nil 147 } 148 149 func (ref TagReferences) getIndex( 150 ctx context.Context, repo, subjectDigestStr string, 151 ) (ispec.Index, []byte, error) { 152 var index ispec.Index 153 154 content, _, statusCode, err := ref.client.MakeGetRequest(ctx, &index, ispec.MediaTypeImageIndex, 155 "v2", repo, "manifests", getReferrersTagFromSubjectDigest(subjectDigestStr)) 156 if err != nil { 157 if statusCode == http.StatusNotFound { 158 ref.log.Debug().Str("repository", repo).Str("subject", subjectDigestStr). 159 Msg("couldn't find any index with referrers tag for image, skipping") 160 161 return index, []byte{}, zerr.ErrSyncReferrerNotFound 162 } 163 164 return index, []byte{}, err 165 } 166 167 return index, content, nil 168 } 169 170 func getReferrersTagFromSubjectDigest(digestStr string) string { 171 return strings.Replace(digestStr, ":", "-", 1) 172 }