From c94f28805e1b653204cc4cec2d76a12398e4524a Mon Sep 17 00:00:00 2001 From: Mike Brown Date: Tue, 11 Jul 2017 14:19:47 -0500 Subject: [PATCH] OCI media types; annotation support; oci index Signed-off-by: Mike Brown --- blobs.go | 8 ++++ manifest/manifestlist/manifestlist.go | 12 ++--- manifest/manifestlist/manifestlist_test.go | 13 +++--- manifest/ocischema/builder.go | 7 +-- manifest/ocischema/builder_test.go | 9 ++-- manifest/ocischema/manifest.go | 33 ++++--------- manifest/ocischema/manifest_test.go | 13 +++--- registry/handlers/manifests.go | 51 ++++++++++++--------- registry/storage/manifeststore.go | 5 +- registry/storage/ocimanifesthandler.go | 6 ++- registry/storage/ocimanifesthandler_test.go | 35 +++++++------- 11 files changed, 102 insertions(+), 90 deletions(-) diff --git a/blobs.go b/blobs.go index 145b07853..42a437738 100644 --- a/blobs.go +++ b/blobs.go @@ -10,6 +10,7 @@ import ( "github.com/docker/distribution/reference" "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" ) var ( @@ -72,6 +73,13 @@ type Descriptor struct { // URLs contains the source URLs of this content. URLs []string `json:"urls,omitempty"` + // Annotations contains arbitrary metadata relating to the targeted content. + Annotations map[string]string `json:"annotations,omitempty"` + + // Platform describes the platform which the image in the manifest runs on. + // This should only be used when referring to a manifest. + Platform *v1.Platform `json:"platform,omitempty"` + // NOTE: Before adding a field here, please ensure that all // other options have been exhausted. Much of the type relationships // depend on the simplicity of this type. diff --git a/manifest/manifestlist/manifestlist.go b/manifest/manifestlist/manifestlist.go index 56f6aa61d..3303c6be2 100644 --- a/manifest/manifestlist/manifestlist.go +++ b/manifest/manifestlist/manifestlist.go @@ -7,16 +7,13 @@ import ( "github.com/docker/distribution" "github.com/docker/distribution/manifest" - "github.com/docker/distribution/manifest/ocischema" "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" ) const ( // MediaTypeManifestList specifies the mediaType for manifest lists. MediaTypeManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" - // MediaTypeOCIManifestList specifies the mediaType for OCI compliant manifest - // lists. - MediaTypeOCIManifestList = "application/vnd.oci.image.manifest.list.v1+json" ) // SchemaVersion provides a pre-initialized version structure for this @@ -30,7 +27,7 @@ var SchemaVersion = manifest.Versioned{ // packages OCIschema version of the manifest. var OCISchemaVersion = manifest.Versioned{ SchemaVersion: 2, - MediaType: MediaTypeOCIManifestList, + MediaType: v1.MediaTypeImageIndex, } func init() { @@ -92,6 +89,9 @@ type ManifestList struct { // Config references the image configuration as a blob. Manifests []ManifestDescriptor `json:"manifests"` + + // Annotations contains arbitrary metadata for the image index. + Annotations map[string]string `json:"annotations,omitempty"` } // References returns the distribution descriptors for the referenced image @@ -119,7 +119,7 @@ type DeserializedManifestList struct { // and its JSON representation. func FromDescriptors(descriptors []ManifestDescriptor) (*DeserializedManifestList, error) { var m ManifestList - if len(descriptors) > 0 && descriptors[0].Descriptor.MediaType == ocischema.MediaTypeManifest { + if len(descriptors) > 0 && descriptors[0].Descriptor.MediaType == v1.MediaTypeImageManifest { m = ManifestList{ Versioned: OCISchemaVersion, } diff --git a/manifest/manifestlist/manifestlist_test.go b/manifest/manifestlist/manifestlist_test.go index 1d24aef26..5ab328dd8 100644 --- a/manifest/manifestlist/manifestlist_test.go +++ b/manifest/manifestlist/manifestlist_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/docker/distribution" + "github.com/opencontainers/image-spec/specs-go/v1" ) var expectedManifestListSerialization = []byte(`{ @@ -110,9 +111,9 @@ func TestManifestList(t *testing.T) { } } -var expectedOCIManifestListSerialization = []byte(`{ +var expectedOCIImageIndexSerialization = []byte(`{ "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.list.v1+json", + "mediaType": "application/vnd.oci.image.index.v1+json", "manifests": [ { "mediaType": "application/vnd.oci.image.manifest.v1+json", @@ -138,7 +139,7 @@ var expectedOCIManifestListSerialization = []byte(`{ ] }`) -func TestOCIManifestList(t *testing.T) { +func TestOCIImageIndex(t *testing.T) { manifestDescriptors := []ManifestDescriptor{ { Descriptor: distribution.Descriptor{ @@ -172,7 +173,7 @@ func TestOCIManifestList(t *testing.T) { mediaType, canonical, _ := deserialized.Payload() - if mediaType != MediaTypeOCIManifestList { + if mediaType != v1.MediaTypeImageIndex { t.Fatalf("unexpected media type: %s", mediaType) } @@ -187,8 +188,8 @@ func TestOCIManifestList(t *testing.T) { } // Check that the canonical field has the expected value. - if !bytes.Equal(expectedOCIManifestListSerialization, canonical) { - t.Fatalf("manifest bytes not equal: %q != %q", string(canonical), string(expectedOCIManifestListSerialization)) + if !bytes.Equal(expectedOCIImageIndexSerialization, canonical) { + t.Fatalf("manifest bytes not equal: %q != %q", string(canonical), string(expectedOCIImageIndexSerialization)) } var unmarshalled DeserializedManifestList diff --git a/manifest/ocischema/builder.go b/manifest/ocischema/builder.go index 5318c1398..a6d6633a8 100644 --- a/manifest/ocischema/builder.go +++ b/manifest/ocischema/builder.go @@ -4,6 +4,7 @@ import ( "github.com/docker/distribution" "github.com/docker/distribution/context" "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" ) // builder is a type for constructing manifests. @@ -48,7 +49,7 @@ func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) { case nil: // Override MediaType, since Put always replaces the specified media // type with application/octet-stream in the descriptor it returns. - m.Config.MediaType = MediaTypeConfig + m.Config.MediaType = v1.MediaTypeImageConfig return FromStruct(m) case distribution.ErrBlobUnknown: // nop @@ -57,10 +58,10 @@ func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) { } // Add config to the blob store - m.Config, err = mb.bs.Put(ctx, MediaTypeConfig, mb.configJSON) + m.Config, err = mb.bs.Put(ctx, v1.MediaTypeImageConfig, mb.configJSON) // Override MediaType, since Put always replaces the specified media // type with application/octet-stream in the descriptor it returns. - m.Config.MediaType = MediaTypeConfig + m.Config.MediaType = v1.MediaTypeImageConfig if err != nil { return nil, err } diff --git a/manifest/ocischema/builder_test.go b/manifest/ocischema/builder_test.go index 7192ac59b..33e9164f5 100644 --- a/manifest/ocischema/builder_test.go +++ b/manifest/ocischema/builder_test.go @@ -7,6 +7,7 @@ import ( "github.com/docker/distribution" "github.com/docker/distribution/context" "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" ) type mockBlobService struct { @@ -151,17 +152,17 @@ func TestBuilder(t *testing.T) { { Digest: digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"), Size: 5312, - MediaType: MediaTypeLayer, + MediaType: v1.MediaTypeImageLayerGzip, }, { Digest: digest.Digest("sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa"), Size: 235231, - MediaType: MediaTypeLayer, + MediaType: v1.MediaTypeImageLayerGzip, }, { Digest: digest.Digest("sha256:b4ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"), Size: 639152, - MediaType: MediaTypeLayer, + MediaType: v1.MediaTypeImageLayerGzip, }, } @@ -195,7 +196,7 @@ func TestBuilder(t *testing.T) { if target.Digest != configDigest { t.Fatalf("unexpected digest in target: %s", target.Digest.String()) } - if target.MediaType != MediaTypeConfig { + if target.MediaType != v1.MediaTypeImageConfig { t.Fatalf("unexpected media type in target: %s", target.MediaType) } if target.Size != 3153 { diff --git a/manifest/ocischema/manifest.go b/manifest/ocischema/manifest.go index 52f64678b..f1a05f0a9 100644 --- a/manifest/ocischema/manifest.go +++ b/manifest/ocischema/manifest.go @@ -8,32 +8,15 @@ import ( "github.com/docker/distribution" "github.com/docker/distribution/manifest" "github.com/opencontainers/go-digest" -) - -const ( - // MediaTypeManifest specifies the mediaType for the current version. - MediaTypeManifest = "application/vnd.oci.image.manifest.v1+json" - - // MediaTypeConfig specifies the mediaType for the image configuration. - MediaTypeConfig = "application/vnd.oci.image.config.v1+json" - - // MediaTypePluginConfig specifies the mediaType for plugin configuration. - MediaTypePluginConfig = "application/vnd.docker.plugin.v1+json" - - // MediaTypeLayer is the mediaType used for layers referenced by the manifest. - MediaTypeLayer = "application/vnd.oci.image.layer.v1.tar+gzip" - - // MediaTypeForeignLayer is the mediaType used for layers that must be - // downloaded from foreign URLs. - MediaTypeForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip" + "github.com/opencontainers/image-spec/specs-go/v1" ) var ( // SchemaVersion provides a pre-initialized version structure for this // packages version of the manifest. SchemaVersion = manifest.Versioned{ - SchemaVersion: 2, // Mike: todo this could confusing cause oci version 1 is closer to docker 2 than 1 - MediaType: MediaTypeManifest, + SchemaVersion: 2, // TODO: (mikebrow/stevvooe) this could be confusing cause oci version 1 is closer to docker 2 than 1 + MediaType: v1.MediaTypeImageManifest, } ) @@ -46,15 +29,15 @@ func init() { } dgst := digest.FromBytes(b) - return m, distribution.Descriptor{Digest: dgst, Size: int64(len(b)), MediaType: MediaTypeManifest}, err + return m, distribution.Descriptor{Digest: dgst, Size: int64(len(b)), MediaType: v1.MediaTypeImageManifest}, err } - err := distribution.RegisterManifestSchema(MediaTypeManifest, ocischemaFunc) + err := distribution.RegisterManifestSchema(v1.MediaTypeImageManifest, ocischemaFunc) if err != nil { panic(fmt.Sprintf("Unable to register manifest: %s", err)) } } -// Manifest defines a schema2 manifest. +// Manifest defines a ocischema manifest. type Manifest struct { manifest.Versioned @@ -64,6 +47,9 @@ type Manifest struct { // Layers lists descriptors for the layers referenced by the // configuration. Layers []distribution.Descriptor `json:"layers"` + + // Annotations contains arbitrary metadata for the image manifest. + Annotations map[string]string `json:"annotations,omitempty"` } // References returnes the descriptors of this manifests references. @@ -71,6 +57,7 @@ func (m Manifest) References() []distribution.Descriptor { references := make([]distribution.Descriptor, 0, 1+len(m.Layers)) references = append(references, m.Config) references = append(references, m.Layers...) + // TODO: (mikebrow/stevvooe) should we return annotations as references return references } diff --git a/manifest/ocischema/manifest_test.go b/manifest/ocischema/manifest_test.go index 9f439dcd5..55dc0306e 100644 --- a/manifest/ocischema/manifest_test.go +++ b/manifest/ocischema/manifest_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/docker/distribution" + "github.com/opencontainers/image-spec/specs-go/v1" ) var expectedManifestSerialization = []byte(`{ @@ -32,13 +33,13 @@ func TestManifest(t *testing.T) { Config: distribution.Descriptor{ Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b", Size: 985, - MediaType: MediaTypeConfig, + MediaType: v1.MediaTypeImageConfig, }, Layers: []distribution.Descriptor{ { Digest: "sha256:62d8908bee94c202b2d35224a221aaa2058318bfa9879fa541efaecba272331b", Size: 153263, - MediaType: MediaTypeLayer, + MediaType: v1.MediaTypeImageLayerGzip, }, }, } @@ -48,9 +49,9 @@ func TestManifest(t *testing.T) { t.Fatalf("error creating DeserializedManifest: %v", err) } - mediaType, canonical, err := deserialized.Payload() + mediaType, canonical, _ := deserialized.Payload() - if mediaType != MediaTypeManifest { + if mediaType != v1.MediaTypeImageManifest { t.Fatalf("unexpected media type: %s", mediaType) } @@ -82,7 +83,7 @@ func TestManifest(t *testing.T) { if target.Digest != "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b" { t.Fatalf("unexpected digest in target: %s", target.Digest.String()) } - if target.MediaType != MediaTypeConfig { + if target.MediaType != v1.MediaTypeImageConfig { t.Fatalf("unexpected media type in target: %s", target.MediaType) } if target.Size != 985 { @@ -102,7 +103,7 @@ func TestManifest(t *testing.T) { if references[1].Digest != "sha256:62d8908bee94c202b2d35224a221aaa2058318bfa9879fa541efaecba272331b" { t.Fatalf("unexpected digest in reference: %s", references[0].Digest.String()) } - if references[1].MediaType != MediaTypeLayer { + if references[1].MediaType != v1.MediaTypeImageLayerGzip { t.Fatalf("unexpected media type in reference: %s", references[0].MediaType) } if references[1].Size != 153263 { diff --git a/registry/handlers/manifests.go b/registry/handlers/manifests.go index af0a8876c..07fd6f8c6 100644 --- a/registry/handlers/manifests.go +++ b/registry/handlers/manifests.go @@ -18,6 +18,7 @@ import ( "github.com/docker/distribution/registry/auth" "github.com/gorilla/handlers" "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" ) // These constants determine which architecture and OS to choose from a @@ -76,7 +77,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) supportsSchema2 := false supportsManifestList := false supportsOCISchema := false - supportsOCIManifestList := false + supportsOCIImageIndex := false // this parsing of Accept headers is not quite as full-featured as godoc.org's parser, but we don't care about "q=" values // https://github.com/golang/gddo/blob/e91d4165076d7474d20abda83f92d15c7ebc3e81/httputil/header/header.go#L165-L202 for _, acceptHeader := range r.Header["Accept"] { @@ -100,15 +101,15 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) if mediaType == manifestlist.MediaTypeManifestList { supportsManifestList = true } - if mediaType == ocischema.MediaTypeManifest { + if mediaType == v1.MediaTypeImageManifest { supportsOCISchema = true } - if mediaType == manifestlist.MediaTypeOCIManifestList { - supportsOCIManifestList = true + if mediaType == v1.MediaTypeImageIndex { + supportsOCIImageIndex = true } } } - supportsOCI := supportsOCISchema || supportsOCIManifestList + supportsOCI := supportsOCISchema || supportsOCIImageIndex var manifest distribution.Manifest if imh.Tag != "" { @@ -151,15 +152,15 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest) manifestList, isManifestList := manifest.(*manifestlist.DeserializedManifestList) - isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == ocischema.MediaTypeManifest) - isAnOCIManifestList := isManifestList && (manifestList.MediaType == manifestlist.MediaTypeOCIManifestList) + isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == v1.MediaTypeImageManifest) + isAnOCIImageIndex := isManifestList && (manifestList.MediaType == v1.MediaTypeImageIndex) if (isSchema2 && !isAnOCIManifest) && (supportsOCISchema && !supportsSchema2) { fmt.Printf("\n\nmanifest is schema2, but accept header only supports OCISchema \n\n") w.WriteHeader(http.StatusNotFound) return } - if (isManifestList && !isAnOCIManifestList) && (supportsOCIManifestList && !supportsManifestList) { + if (isManifestList && !isAnOCIImageIndex) && (supportsOCIImageIndex && !supportsManifestList) { fmt.Printf("\n\nmanifestlist is not OCI, but accept header only supports an OCI manifestlist\n\n") w.WriteHeader(http.StatusNotFound) return @@ -169,7 +170,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusNotFound) return } - if isAnOCIManifestList && (!supportsOCIManifestList && supportsManifestList) { + if isAnOCIImageIndex && (!supportsOCIImageIndex && supportsManifestList) { fmt.Printf("\n\nmanifestlist is OCI, but accept header only supports non-OCI manifestlists\n\n") w.WriteHeader(http.StatusNotFound) return @@ -185,7 +186,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) if err != nil { return } - } else if imh.Tag != "" && isManifestList && !(supportsManifestList || supportsOCIManifestList) { + } else if imh.Tag != "" && isManifestList && !(supportsManifestList || supportsOCIImageIndex) { // Rewrite manifest in schema1 format ctxu.GetLogger(imh).Infof("rewriting manifest list %s in schema1 format to support old client", imh.Digest.String()) @@ -243,7 +244,7 @@ func (imh *manifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Requ supportsSchema2 := false supportsManifestList := false supportsOCISchema := false - supportsOCIManifestList := false + supportsOCIImageIndex := false // this parsing of Accept headers is not quite as full-featured as godoc.org's parser, but we don't care about "q=" values // https://github.com/golang/gddo/blob/e91d4165076d7474d20abda83f92d15c7ebc3e81/httputil/header/header.go#L165-L202 @@ -268,15 +269,15 @@ func (imh *manifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Requ if mediaType == manifestlist.MediaTypeManifestList { supportsManifestList = true } - if mediaType == ocischema.MediaTypeManifest { + if mediaType == v1.MediaTypeImageManifest { supportsOCISchema = true } - if mediaType == manifestlist.MediaTypeOCIManifestList { - supportsOCIManifestList = true + if mediaType == v1.MediaTypeImageIndex { + supportsOCIImageIndex = true } } } - supportsOCI := supportsOCISchema || supportsOCIManifestList + supportsOCI := supportsOCISchema || supportsOCIImageIndex ctxu.GetLogger(imh).Debug("GetImageManifest") manifests, err := imh.Repository.Manifests(imh) @@ -325,14 +326,14 @@ func (imh *manifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Requ schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest) manifestList, isManifestList := manifest.(*manifestlist.DeserializedManifestList) - isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == ocischema.MediaTypeManifest) - isAnOCIManifestList := isManifestList && (manifestList.MediaType == manifestlist.MediaTypeOCIManifestList) + isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == v1.MediaTypeImageManifest) + isAnOCIImageIndex := isManifestList && (manifestList.MediaType == v1.MediaTypeImageIndex) badCombinations := [][]bool{ {isSchema2 && !isAnOCIManifest, supportsOCISchema && !supportsSchema2}, - {isManifestList && !isAnOCIManifestList, supportsOCIManifestList && !supportsManifestList}, + {isManifestList && !isAnOCIImageIndex, supportsOCIImageIndex && !supportsManifestList}, {isAnOCIManifest, !supportsOCISchema && supportsSchema2}, - {isAnOCIManifestList, !supportsOCIManifestList && supportsManifestList}, + {isAnOCIImageIndex, !supportsOCIImageIndex && supportsManifestList}, } for i, combo := range badCombinations { if combo[0] && combo[1] { @@ -360,7 +361,7 @@ func (imh *manifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Requ if err != nil { return } - } else if imh.Tag != "" && isManifestList && !(supportsManifestList || supportsOCIManifestList) { + } else if imh.Tag != "" && isManifestList && !(supportsManifestList || supportsOCIImageIndex) { // Rewrite manifest in schema1 format dcontext.GetLogger(imh).Infof("rewriting manifest list %s in schema1 format to support old client", imh.Digest.String()) @@ -499,7 +500,7 @@ func (imh *manifestHandler) PutManifest(w http.ResponseWriter, r *http.Request) return } - isAnOCIManifest := mediaType == ocischema.MediaTypeManifest || mediaType == manifestlist.MediaTypeOCIManifestList + isAnOCIManifest := mediaType == v1.MediaTypeImageManifest || mediaType == v1.MediaTypeImageIndex if isAnOCIManifest { fmt.Printf("\n\nPutting an OCI Manifest!\n\n\n") @@ -615,6 +616,14 @@ func (imh *manifestHandler) applyResourcePolicy(manifest distribution.Manifest) message := fmt.Sprintf("unknown manifest class for %s", m.Config.MediaType) return errcode.ErrorCodeDenied.WithMessage(message) } + case *ocischema.DeserializedManifest: + switch m.Config.MediaType { + case v1.MediaTypeImageConfig: + class = "image" + default: + message := fmt.Sprintf("unknown manifest class for %s", m.Config.MediaType) + return errcode.ErrorCodeDenied.WithMessage(message) + } } if class == "" { diff --git a/registry/storage/manifeststore.go b/registry/storage/manifeststore.go index 13b4f5b55..6543f6fd6 100644 --- a/registry/storage/manifeststore.go +++ b/registry/storage/manifeststore.go @@ -13,6 +13,7 @@ import ( "github.com/docker/distribution/manifest/schema1" "github.com/docker/distribution/manifest/schema2" "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" ) // A ManifestHandler gets and puts manifests of a particular type. @@ -101,9 +102,9 @@ func (ms *manifestStore) Get(ctx context.Context, dgst digest.Digest, options .. switch versioned.MediaType { case schema2.MediaTypeManifest: return ms.schema2Handler.Unmarshal(ctx, dgst, content) - case ocischema.MediaTypeManifest: + case v1.MediaTypeImageManifest: return ms.ocischemaHandler.Unmarshal(ctx, dgst, content) - case manifestlist.MediaTypeManifestList, manifestlist.MediaTypeOCIManifestList: + case manifestlist.MediaTypeManifestList, v1.MediaTypeImageIndex: return ms.manifestListHandler.Unmarshal(ctx, dgst, content) default: return nil, distribution.ErrManifestVerification{fmt.Errorf("unrecognized manifest content type %s", versioned.MediaType)} diff --git a/registry/storage/ocimanifesthandler.go b/registry/storage/ocimanifesthandler.go index bb6583487..148b7a2ea 100644 --- a/registry/storage/ocimanifesthandler.go +++ b/registry/storage/ocimanifesthandler.go @@ -9,6 +9,7 @@ import ( "github.com/docker/distribution/context" "github.com/docker/distribution/manifest/ocischema" "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" ) //ocischemaManifestHandler is a ManifestHandler that covers ocischema manifests. @@ -79,7 +80,8 @@ func (ms *ocischemaManifestHandler) verifyManifest(ctx context.Context, mnfst oc var err error switch descriptor.MediaType { - case ocischema.MediaTypeForeignLayer: + // TODO: mikebrow/steveoe verify we should treat oci nondistributable like foreign layers? + case v1.MediaTypeImageLayerNonDistributable, v1.MediaTypeImageLayerNonDistributableGzip: // Clients download this layer from an external URL, so do not check for // its presense. if len(descriptor.URLs) == 0 { @@ -95,7 +97,7 @@ func (ms *ocischemaManifestHandler) verifyManifest(ctx context.Context, mnfst oc break } } - case ocischema.MediaTypeManifest: + case v1.MediaTypeImageManifest: var exists bool exists, err = manifestService.Exists(ctx, descriptor.Digest) if err != nil || !exists { diff --git a/registry/storage/ocimanifesthandler_test.go b/registry/storage/ocimanifesthandler_test.go index e09f1ee3c..d04ce5316 100644 --- a/registry/storage/ocimanifesthandler_test.go +++ b/registry/storage/ocimanifesthandler_test.go @@ -9,9 +9,10 @@ import ( "github.com/docker/distribution/manifest" "github.com/docker/distribution/manifest/ocischema" "github.com/docker/distribution/registry/storage/driver/inmemory" + "github.com/opencontainers/image-spec/specs-go/v1" ) -func TestVerifyOCIManifestForeignLayer(t *testing.T) { +func TestVerifyOCIManifestNonDistributableLayer(t *testing.T) { ctx := context.Background() inmemoryDriver := inmemory.New() registry := createRegistry(t, inmemoryDriver, @@ -20,26 +21,26 @@ func TestVerifyOCIManifestForeignLayer(t *testing.T) { repo := makeRepository(t, registry, "test") manifestService := makeManifestService(t, repo) - config, err := repo.Blobs(ctx).Put(ctx, ocischema.MediaTypeConfig, nil) + config, err := repo.Blobs(ctx).Put(ctx, v1.MediaTypeImageConfig, nil) if err != nil { t.Fatal(err) } - layer, err := repo.Blobs(ctx).Put(ctx, ocischema.MediaTypeLayer, nil) + layer, err := repo.Blobs(ctx).Put(ctx, v1.MediaTypeImageLayerGzip, nil) if err != nil { t.Fatal(err) } - foreignLayer := distribution.Descriptor{ + nonDistributableLayer := distribution.Descriptor{ Digest: "sha256:463435349086340864309863409683460843608348608934092322395278926a", Size: 6323, - MediaType: ocischema.MediaTypeForeignLayer, + MediaType: v1.MediaTypeImageLayerNonDistributableGzip, } template := ocischema.Manifest{ Versioned: manifest.Versioned{ SchemaVersion: 2, - MediaType: ocischema.MediaTypeManifest, + MediaType: v1.MediaTypeImageManifest, }, Config: config, } @@ -52,58 +53,58 @@ func TestVerifyOCIManifestForeignLayer(t *testing.T) { cases := []testcase{ { - foreignLayer, + nonDistributableLayer, nil, errMissingURL, }, { - // regular layers may have foreign urls + // regular layers may have foreign urls (non-Distributable Layers) layer, []string{"http://foo/bar"}, nil, }, { - foreignLayer, + nonDistributableLayer, []string{"file:///local/file"}, errInvalidURL, }, { - foreignLayer, + nonDistributableLayer, []string{"http://foo/bar#baz"}, errInvalidURL, }, { - foreignLayer, + nonDistributableLayer, []string{""}, errInvalidURL, }, { - foreignLayer, + nonDistributableLayer, []string{"https://foo/bar", ""}, errInvalidURL, }, { - foreignLayer, + nonDistributableLayer, []string{"", "https://foo/bar"}, errInvalidURL, }, { - foreignLayer, + nonDistributableLayer, []string{"http://nope/bar"}, errInvalidURL, }, { - foreignLayer, + nonDistributableLayer, []string{"http://foo/nope"}, errInvalidURL, }, { - foreignLayer, + nonDistributableLayer, []string{"http://foo/bar"}, nil, }, { - foreignLayer, + nonDistributableLayer, []string{"https://foo/bar"}, nil, },