in registry/handlers/manifests.go [944:1072]
func dbPutManifestV2(imh *manifestHandler, mfst distribution.ManifestV2, payload []byte, nonConformant bool) error {
repoPath := imh.Repository.Named().Name()
l := log.GetLogger(log.WithContext(imh)).WithFields(log.Fields{
"repository": repoPath,
"manifest_digest": imh.Digest,
"schema_version": mfst.Version().SchemaVersion,
})
// create or find target repository
var opts []datastore.RepositoryStoreOption
if imh.GetRepoCache() != nil {
opts = append(opts, datastore.WithRepositoryCache(imh.GetRepoCache()))
}
rStore := datastore.NewRepositoryStore(imh.App.db.Primary(), opts...)
dbRepo, err := rStore.CreateOrFindByPath(imh, repoPath)
if err != nil {
return err
}
l.Info("putting manifest")
// Find the config now to ensure that the config's blob is associated with the repository.
dbCfgBlob, err := dbFindRepositoryBlob(imh.Context, rStore, mfst.Config(), dbRepo.Path)
if err != nil {
return err
}
dbManifest, err := rStore.FindManifestByDigest(imh.Context, dbRepo, imh.Digest)
if err != nil {
return err
}
if dbManifest == nil {
l.Debug("manifest not found in database")
cfg := &models.Configuration{
MediaType: mfst.Config().MediaType,
Digest: dbCfgBlob.Digest,
}
// skip retrieval and caching of config payload if its size is over the limit
if dbCfgBlob.Size <= datastore.ConfigSizeLimit {
// Since filesystem writes may be optional, We cannot be sure that the
// repository scoped filesystem blob service will have a link to the
// configuration blob; however, since we check for repository scoped access
// via the database above, we may retrieve the blob directly common storage.
cfgPayload, err := imh.blobProvider.Get(imh, dbCfgBlob.Digest)
if err != nil {
return err
}
cfg.Payload = cfgPayload
}
m := &models.Manifest{
NamespaceID: dbRepo.NamespaceID,
RepositoryID: dbRepo.ID,
TotalSize: mfst.TotalSize(),
SchemaVersion: mfst.Version().SchemaVersion,
MediaType: mfst.Version().MediaType,
Digest: imh.Digest,
Payload: payload,
Configuration: cfg,
NonConformant: nonConformant,
}
// if Subject present in mfst, set SubjectID in model
ocim, ok := mfst.(distribution.ManifestOCI)
if ok {
subject := ocim.Subject()
if subject.Digest.String() != "" {
// Fetch subject_id from digest
dbSubject, err := rStore.FindManifestByDigest(imh.Context, dbRepo, subject.Digest)
// nolint: revive // max-control-nesting
if err != nil {
return err
}
// nolint: revive // max-control-nesting
if dbSubject == nil {
// in case something happened to the referenced manifest after validation
return distribution.ErrManifestBlobUnknown{Digest: subject.Digest}
}
m.SubjectID.Int64 = dbSubject.ID
m.SubjectID.Valid = true
}
if ocim.ArtifactType() != "" {
m.ArtifactType.String = ocim.ArtifactType()
m.ArtifactType.Valid = true
}
}
// check if the manifest references non-distributable layers and mark it as such on the DB
ll := mfst.DistributableLayers()
m.NonDistributableLayers = len(ll) < len(mfst.Layers())
mStore := datastore.NewManifestStore(imh.App.db.Primary())
// Use CreateOrFind to prevent race conditions while pushing the same manifest with digest for different tags
if err := mStore.CreateOrFind(imh, m); err != nil {
return err
}
dbManifest = m
// find and associate distributable manifest layer blobs
for _, reqLayer := range mfst.DistributableLayers() {
dbBlob, err := dbFindRepositoryBlob(imh.Context, rStore, reqLayer, dbRepo.Path)
if err != nil {
return err
}
// Overwrite the media type from common blob storage with the one
// specified in the manifest json for the layer entity. The layer entity
// has a 1-1 relationship with with the manifest, so we want to reflect
// the manifest's description of the layer. Multiple manifest can reference
// the same blob, so the common blob storage should remain generic.
ok := layerMediaTypeExists(imh, reqLayer.MediaType)
if ok || feature.DynamicMediaTypes.Enabled() {
dbBlob.MediaType = reqLayer.MediaType
}
if err := mStore.AssociateLayerBlob(imh.Context, dbManifest, dbBlob); err != nil {
return err
}
}
}
return nil
}