func()

in registry/datastore/importer.go [386:475]


func (imp *Importer) importManifestList(ctx context.Context, fsRepo distribution.Repository, dbRepo *models.Repository, ml *manifestlist.DeserializedManifestList, dgst digest.Digest) (*models.Manifest, error) {
	if mlcompat.LikelyBuildxCache(ml) {
		_, payload, err := ml.Payload()
		if err != nil {
			return nil, err
		}

		// convert to OCI manifest and process as if it was one
		m, err := mlcompat.OCIManifestFromBuildkitIndex(ml)
		if err != nil {
			return nil, fmt.Errorf("converting buildkit index to manifest: %w", err)
		}

		// Note that `payload` is not the deserialized manifest list (`ml`) payload but rather the index payload, untouched.
		manifestV2, err := imp.importManifestV2(ctx, fsRepo, dbRepo, m, dgst, payload, true)
		if err != nil {
			return nil, err
		}

		return manifestV2, nil
	}

	_, payload, err := ml.Payload()
	if err != nil {
		return nil, fmt.Errorf("parsing payload: %w", err)
	}

	// Media type can be either Docker (`application/vnd.docker.distribution.manifest.list.v2+json`) or OCI (empty).
	// We need to make it explicit if empty, otherwise we're not able to distinguish between media types.
	mediaType := ml.MediaType
	if mediaType == "" {
		mediaType = v1.MediaTypeImageIndex
	}

	// create manifest list on DB
	dbManifestList, err := imp.findOrCreateDBManifest(ctx, dbRepo, &models.Manifest{
		NamespaceID:   dbRepo.NamespaceID,
		RepositoryID:  dbRepo.ID,
		SchemaVersion: ml.SchemaVersion,
		MediaType:     mediaType,
		Digest:        dgst,
		Payload:       payload,
	})
	if err != nil {
		return nil, fmt.Errorf("creating manifest list in database: %w", err)
	}

	manifestService, err := fsRepo.Manifests(ctx)
	if err != nil {
		return nil, fmt.Errorf("constructing manifest service: %w", err)
	}

	// import manifests in list
	total := len(ml.Manifests)
	for i, m := range ml.Manifests {
		l := log.GetLogger(log.WithContext(ctx)).WithFields(log.Fields{
			"repository": dbRepo.Path,
			"digest":     m.Digest.String(),
			"count":      i + 1,
			"total":      total,
		})
		fsManifest, err := getFsManifest(ctx, manifestService, m.Digest, l)
		if err != nil {
			if errors.Is(err, errManifestSkip) {
				// Skipping the import of this broken referenced manifest will lead to a partially broken list. We could
				// skip the import of the referencing list as well, but it's already broken on the old registry
				// (filesystem metadata) so it's preferable to keep the pull behavior consistent across old and new.
				continue
			}
			return nil, fmt.Errorf("retrieving referenced manifest %q from filesystem: %w", m.Digest, err)
		}

		l.WithFields(log.Fields{"type": fmt.Sprintf("%T", fsManifest)}).Info("importing manifest referenced in list")

		dbManifest, err := imp.importManifest(ctx, fsRepo, dbRepo, fsManifest, m.Digest)
		if err != nil {
			if errors.Is(err, distribution.ErrSchemaV1Unsupported) {
				l.WithError(err).Warn("skipping v1 manifest")
				continue
			}
			return nil, err
		}

		if err := imp.manifestStore.AssociateManifest(ctx, dbManifestList, dbManifest); err != nil {
			return nil, err
		}
	}

	return dbManifestList, nil
}