func dbPutManifestV2()

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
}