mirror of
https://github.com/distribution/distribution.git
synced 2025-09-22 03:28:05 +00:00
Split OCI Image Index from Docker Manifest List
Move implementation of the index from the manifestlist package to the ocischema package so that other modules making empty imports support the manifest types their authors would expect. This is a breaking change to distribution as a library but not the registry. As OCI 1.0 released the manifest and index together, that is a good package from which to initialise both manifests. The docker manifest and manifest list remain in separate packages because one was released later. The image index and manifest list still share common code in many functions not intended for import by other modules. Signed-off-by: Bracken Dawson <abdawson@gmail.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/distribution/distribution/v3"
|
||||
dcontext "github.com/distribution/distribution/v3/context"
|
||||
"github.com/distribution/distribution/v3/manifest/manifestlist"
|
||||
"github.com/distribution/distribution/v3/manifest/ocischema"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
@@ -33,16 +34,24 @@ func (ms *manifestListHandler) Unmarshal(ctx context.Context, dgst digest.Digest
|
||||
func (ms *manifestListHandler) Put(ctx context.Context, manifestList distribution.Manifest, skipDependencyVerification bool) (digest.Digest, error) {
|
||||
dcontext.GetLogger(ms.ctx).Debug("(*manifestListHandler).Put")
|
||||
|
||||
m, ok := manifestList.(*manifestlist.DeserializedManifestList)
|
||||
if !ok {
|
||||
var schemaVersion int
|
||||
switch m := manifestList.(type) {
|
||||
case *manifestlist.DeserializedManifestList:
|
||||
schemaVersion = m.SchemaVersion
|
||||
case *ocischema.DeserializedImageIndex:
|
||||
schemaVersion = m.SchemaVersion
|
||||
default:
|
||||
return "", fmt.Errorf("wrong type put to manifestListHandler: %T", manifestList)
|
||||
}
|
||||
if schemaVersion != 2 {
|
||||
return "", fmt.Errorf("unrecognized manifest list schema version %d", schemaVersion)
|
||||
}
|
||||
|
||||
if err := ms.verifyManifest(ms.ctx, *m, skipDependencyVerification); err != nil {
|
||||
if err := ms.verifyManifest(ms.ctx, manifestList, skipDependencyVerification); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
mt, payload, err := m.Payload()
|
||||
mt, payload, err := manifestList.Payload()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -60,13 +69,9 @@ func (ms *manifestListHandler) Put(ctx context.Context, manifestList distributio
|
||||
// perspective of the registry. As a policy, the registry only tries to
|
||||
// store valid content, leaving trust policies of that content up to
|
||||
// consumers.
|
||||
func (ms *manifestListHandler) verifyManifest(ctx context.Context, mnfst manifestlist.DeserializedManifestList, skipDependencyVerification bool) error {
|
||||
func (ms *manifestListHandler) verifyManifest(ctx context.Context, mnfst distribution.Manifest, skipDependencyVerification bool) error {
|
||||
var errs distribution.ErrManifestVerification
|
||||
|
||||
if mnfst.SchemaVersion != 2 {
|
||||
return fmt.Errorf("unrecognized manifest list schema version %d", mnfst.SchemaVersion)
|
||||
}
|
||||
|
||||
if !skipDependencyVerification {
|
||||
// This manifest service is different from the blob service
|
||||
// returned by Blob. It uses a linked blob store to ensure that
|
||||
|
@@ -48,10 +48,11 @@ type manifestStore struct {
|
||||
|
||||
skipDependencyVerification bool
|
||||
|
||||
schema1Handler ManifestHandler
|
||||
schema2Handler ManifestHandler
|
||||
ocischemaHandler ManifestHandler
|
||||
manifestListHandler ManifestHandler
|
||||
schema1Handler ManifestHandler
|
||||
schema2Handler ManifestHandler
|
||||
manifestListHandler ManifestHandler
|
||||
ocischemaHandler ManifestHandler
|
||||
ocischemaIndexHandler ManifestHandler
|
||||
}
|
||||
|
||||
var _ distribution.ManifestService = &manifestStore{}
|
||||
@@ -104,14 +105,16 @@ func (ms *manifestStore) Get(ctx context.Context, dgst digest.Digest, options ..
|
||||
return ms.schema2Handler.Unmarshal(ctx, dgst, content)
|
||||
case v1.MediaTypeImageManifest:
|
||||
return ms.ocischemaHandler.Unmarshal(ctx, dgst, content)
|
||||
case manifestlist.MediaTypeManifestList, v1.MediaTypeImageIndex:
|
||||
case manifestlist.MediaTypeManifestList:
|
||||
return ms.manifestListHandler.Unmarshal(ctx, dgst, content)
|
||||
case v1.MediaTypeImageIndex:
|
||||
return ms.ocischemaIndexHandler.Unmarshal(ctx, dgst, content)
|
||||
case "":
|
||||
// OCI image or image index - no media type in the content
|
||||
|
||||
// First see if it looks like an image index
|
||||
res, err := ms.manifestListHandler.Unmarshal(ctx, dgst, content)
|
||||
resIndex := res.(*manifestlist.DeserializedManifestList)
|
||||
res, err := ms.ocischemaIndexHandler.Unmarshal(ctx, dgst, content)
|
||||
resIndex := res.(*ocischema.DeserializedImageIndex)
|
||||
if err == nil && resIndex.Manifests != nil {
|
||||
return resIndex, nil
|
||||
}
|
||||
@@ -138,6 +141,8 @@ func (ms *manifestStore) Put(ctx context.Context, manifest distribution.Manifest
|
||||
return ms.ocischemaHandler.Put(ctx, manifest, ms.skipDependencyVerification)
|
||||
case *manifestlist.DeserializedManifestList:
|
||||
return ms.manifestListHandler.Put(ctx, manifest, ms.skipDependencyVerification)
|
||||
case *ocischema.DeserializedImageIndex:
|
||||
return ms.ocischemaIndexHandler.Put(ctx, manifest, ms.skipDependencyVerification)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unrecognized manifest type %T", manifest)
|
||||
|
@@ -3,13 +3,13 @@ package storage
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/distribution/distribution/v3"
|
||||
"github.com/distribution/distribution/v3/manifest"
|
||||
"github.com/distribution/distribution/v3/manifest/manifestlist"
|
||||
"github.com/distribution/distribution/v3/manifest/ocischema"
|
||||
"github.com/distribution/distribution/v3/manifest/schema1"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
@@ -465,19 +465,19 @@ func testOCIManifestStorage(t *testing.T, testname string, includeMediaTypes boo
|
||||
}
|
||||
descriptor.MediaType = v1.MediaTypeImageManifest
|
||||
|
||||
platformSpec := manifestlist.PlatformSpec{
|
||||
platformSpec := v1.Platform{
|
||||
Architecture: "atari2600",
|
||||
OS: "CP/M",
|
||||
}
|
||||
|
||||
manifestDescriptors := []manifestlist.ManifestDescriptor{
|
||||
manifestDescriptors := []ocischema.ManifestDescriptor{
|
||||
{
|
||||
Descriptor: descriptor,
|
||||
Platform: platformSpec,
|
||||
Platform: &platformSpec,
|
||||
},
|
||||
}
|
||||
|
||||
imageIndex, err := manifestlist.FromDescriptorsWithMediaType(manifestDescriptors, indexMediaType)
|
||||
imageIndex, err := ociIndexFromDesriptorsWithMediaType(manifestDescriptors, indexMediaType)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error creating image index: %v", testname, err)
|
||||
}
|
||||
@@ -523,7 +523,7 @@ func testOCIManifestStorage(t *testing.T, testname string, includeMediaTypes boo
|
||||
t.Fatalf("%s: unexpected error fetching image index: %v", testname, err)
|
||||
}
|
||||
|
||||
fetchedIndex, ok := fromStore.(*manifestlist.DeserializedManifestList)
|
||||
fetchedIndex, ok := fromStore.(*ocischema.DeserializedImageIndex)
|
||||
if !ok {
|
||||
t.Fatalf("%s: unexpected type for fetched manifest", testname)
|
||||
}
|
||||
@@ -574,3 +574,23 @@ func TestLinkPathFuncs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ociIndexFromDesriptorsWithMediaType(descriptors []ocischema.ManifestDescriptor, mediaType string) (*ocischema.DeserializedImageIndex, error) {
|
||||
manifest, err := ocischema.FromDescriptors(descriptors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
manifest.ImageIndex.MediaType = mediaType
|
||||
|
||||
rawManifest, err := json.Marshal(manifest.ImageIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var d ocischema.DeserializedImageIndex
|
||||
if err := d.UnmarshalJSON(rawManifest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
}
|
||||
|
28
registry/storage/ociindexhandler.go
Normal file
28
registry/storage/ociindexhandler.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/distribution/distribution/v3"
|
||||
dcontext "github.com/distribution/distribution/v3/context"
|
||||
"github.com/distribution/distribution/v3/manifest/ocischema"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
// ocischemaIndexHandler is a ManifestHandler that covers the OCI Image Index.
|
||||
type ocischemaIndexHandler struct {
|
||||
*manifestListHandler
|
||||
}
|
||||
|
||||
var _ ManifestHandler = &manifestListHandler{}
|
||||
|
||||
func (ms *ocischemaIndexHandler) Unmarshal(ctx context.Context, dgst digest.Digest, content []byte) (distribution.Manifest, error) {
|
||||
dcontext.GetLogger(ms.ctx).Debug("(*ociIndexHandler).Unmarshal")
|
||||
|
||||
m := &ocischema.DeserializedImageIndex{}
|
||||
if err := m.UnmarshalJSON(content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
@@ -259,6 +259,12 @@ func (repo *repository) Manifests(ctx context.Context, options ...distribution.M
|
||||
}
|
||||
}
|
||||
|
||||
manifestListHandler := &manifestListHandler{
|
||||
ctx: ctx,
|
||||
repository: repo,
|
||||
blobStore: blobStore,
|
||||
}
|
||||
|
||||
ms := &manifestStore{
|
||||
ctx: ctx,
|
||||
repository: repo,
|
||||
@@ -270,17 +276,16 @@ func (repo *repository) Manifests(ctx context.Context, options ...distribution.M
|
||||
blobStore: blobStore,
|
||||
manifestURLs: repo.registry.manifestURLs,
|
||||
},
|
||||
manifestListHandler: &manifestListHandler{
|
||||
ctx: ctx,
|
||||
repository: repo,
|
||||
blobStore: blobStore,
|
||||
},
|
||||
manifestListHandler: manifestListHandler,
|
||||
ocischemaHandler: &ocischemaManifestHandler{
|
||||
ctx: ctx,
|
||||
repository: repo,
|
||||
blobStore: blobStore,
|
||||
manifestURLs: repo.registry.manifestURLs,
|
||||
},
|
||||
ocischemaIndexHandler: &ocischemaIndexHandler{
|
||||
manifestListHandler: manifestListHandler,
|
||||
},
|
||||
}
|
||||
|
||||
// Apply options
|
||||
|
Reference in New Issue
Block a user