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
}