forked from TrueCloudLab/distribution
refactor adding enum for storage types
Signed-off-by: Mike Brown <brownwm@us.ibm.com>
This commit is contained in:
parent
9e3f78b8c8
commit
6bae7ca597
6 changed files with 41 additions and 32 deletions
|
@ -111,6 +111,7 @@ func TestManifestList(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO (mikebrow): add annotations on the index and individual manifests
|
||||||
var expectedOCIImageIndexSerialization = []byte(`{
|
var expectedOCIImageIndexSerialization = []byte(`{
|
||||||
"schemaVersion": 2,
|
"schemaVersion": 2,
|
||||||
"mediaType": "application/vnd.oci.image.index.v1+json",
|
"mediaType": "application/vnd.oci.image.index.v1+json",
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO (not assigned): consider making mockBlobService common for ocischema, schema2, and schema1
|
||||||
type mockBlobService struct {
|
type mockBlobService struct {
|
||||||
descriptors map[digest.Digest]distribution.Descriptor
|
descriptors map[digest.Digest]distribution.Descriptor
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ func (m Manifest) References() []distribution.Descriptor {
|
||||||
references := make([]distribution.Descriptor, 0, 1+len(m.Layers))
|
references := make([]distribution.Descriptor, 0, 1+len(m.Layers))
|
||||||
references = append(references, m.Config)
|
references = append(references, m.Config)
|
||||||
references = append(references, m.Layers...)
|
references = append(references, m.Layers...)
|
||||||
// TODO: (mikebrow/stevvooe) should we return annotations as references
|
|
||||||
return references
|
return references
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO (mikebrow): add annotations to the test
|
||||||
var expectedManifestSerialization = []byte(`{
|
var expectedManifestSerialization = []byte(`{
|
||||||
"schemaVersion": 2,
|
"schemaVersion": 2,
|
||||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||||
|
|
|
@ -30,6 +30,17 @@ const (
|
||||||
imageClass = "image"
|
imageClass = "image"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type storageType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
manifestSchema1 storageType = iota // 0
|
||||||
|
manifestSchema2 // 1
|
||||||
|
manifestlistSchema // 2
|
||||||
|
ociSchema // 3
|
||||||
|
ociImageIndexSchema // 4
|
||||||
|
numStorageTypes // 5
|
||||||
|
)
|
||||||
|
|
||||||
// manifestDispatcher takes the request context and builds the
|
// manifestDispatcher takes the request context and builds the
|
||||||
// appropriate handler for handling manifest requests.
|
// appropriate handler for handling manifest requests.
|
||||||
func manifestDispatcher(ctx *Context, r *http.Request) http.Handler {
|
func manifestDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||||
|
@ -75,10 +86,8 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
|
||||||
imh.Errors = append(imh.Errors, err)
|
imh.Errors = append(imh.Errors, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
supportsSchema2 := false
|
var supports [numStorageTypes]bool
|
||||||
supportsManifestList := false
|
|
||||||
supportsOCISchema := 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
|
// 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
|
// https://github.com/golang/gddo/blob/e91d4165076d7474d20abda83f92d15c7ebc3e81/httputil/header/header.go#L165-L202
|
||||||
for _, acceptHeader := range r.Header["Accept"] {
|
for _, acceptHeader := range r.Header["Accept"] {
|
||||||
|
@ -97,16 +106,16 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
|
||||||
mediaType = strings.TrimSpace(mediaType)
|
mediaType = strings.TrimSpace(mediaType)
|
||||||
|
|
||||||
if mediaType == schema2.MediaTypeManifest {
|
if mediaType == schema2.MediaTypeManifest {
|
||||||
supportsSchema2 = true
|
supports[manifestSchema2] = true
|
||||||
}
|
}
|
||||||
if mediaType == manifestlist.MediaTypeManifestList {
|
if mediaType == manifestlist.MediaTypeManifestList {
|
||||||
supportsManifestList = true
|
supports[manifestlistSchema] = true
|
||||||
}
|
}
|
||||||
if mediaType == v1.MediaTypeImageManifest {
|
if mediaType == v1.MediaTypeImageManifest {
|
||||||
supportsOCISchema = true
|
supports[ociSchema] = true
|
||||||
}
|
}
|
||||||
if mediaType == v1.MediaTypeImageIndex {
|
if mediaType == v1.MediaTypeImageIndex {
|
||||||
supportsOCIImageIndex = true
|
supports[ociImageIndexSchema] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,36 +154,34 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// determine the type of the returned manifest
|
||||||
|
manifestType := manifestSchema1
|
||||||
schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest)
|
schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest)
|
||||||
manifestList, isManifestList := manifest.(*manifestlist.DeserializedManifestList)
|
manifestList, isManifestList := manifest.(*manifestlist.DeserializedManifestList)
|
||||||
isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == v1.MediaTypeImageManifest)
|
if isSchema2 {
|
||||||
isAnOCIImageIndex := isManifestList && (manifestList.MediaType == v1.MediaTypeImageIndex)
|
manifestType = manifestSchema2
|
||||||
|
} else if _, isOCImanifest := manifest.(*ocischema.DeserializedManifest); isOCImanifest {
|
||||||
|
manifestType = ociSchema
|
||||||
|
} else if isManifestList {
|
||||||
|
if manifestList.MediaType == manifestlist.MediaTypeManifestList {
|
||||||
|
manifestType = manifestlistSchema
|
||||||
|
} else if manifestList.MediaType == v1.MediaTypeImageIndex {
|
||||||
|
manifestType = ociImageIndexSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isSchema2 && !isAnOCIManifest) && (supportsOCISchema && !supportsSchema2) {
|
if manifestType == ociSchema && !supports[ociSchema] {
|
||||||
ctxu.GetLogger(imh).Debug("manifest is schema2, but accept header only supports OCISchema")
|
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithMessage("OCI manifest found, but accept header does not support OCI manifests"))
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (isManifestList && !isAnOCIImageIndex) && (supportsOCIImageIndex && !supportsManifestList) {
|
if manifestType == ociImageIndexSchema && !supports[ociImageIndexSchema] {
|
||||||
ctxu.GetLogger(imh).Debug("manifestlist is not OCI, but accept header only supports an OCI manifestlist")
|
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithMessage("OCI index found, but accept header does not support OCI indexes"))
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if isAnOCIManifest && (!supportsOCISchema && supportsSchema2) {
|
|
||||||
ctxu.GetLogger(imh).Debug("manifest is OCI, but accept header only supports schema2")
|
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if isAnOCIImageIndex && (!supportsOCIImageIndex && supportsManifestList) {
|
|
||||||
ctxu.GetLogger(imh).Debug("manifestlist is OCI, but accept header only supports non-OCI manifestlists")
|
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Only rewrite schema2 manifests when they are being fetched by tag.
|
// Only rewrite schema2 manifests when they are being fetched by tag.
|
||||||
// If they are being fetched by digest, we can't return something not
|
// If they are being fetched by digest, we can't return something not
|
||||||
// matching the digest.
|
// matching the digest.
|
||||||
if imh.Tag != "" && isSchema2 && !(supportsSchema2 || supportsOCISchema) {
|
if imh.Tag != "" && manifestType == manifestSchema2 && !supports[manifestSchema2] {
|
||||||
// Rewrite manifest in schema1 format
|
// Rewrite manifest in schema1 format
|
||||||
ctxu.GetLogger(imh).Infof("rewriting manifest %s in schema1 format to support old client", imh.Digest.String())
|
ctxu.GetLogger(imh).Infof("rewriting manifest %s in schema1 format to support old client", imh.Digest.String())
|
||||||
|
|
||||||
|
@ -182,7 +189,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if imh.Tag != "" && isManifestList && !(supportsManifestList || supportsOCIImageIndex) {
|
} else if imh.Tag != "" && manifestType == manifestlistSchema && !supports[manifestlistSchema] {
|
||||||
// Rewrite manifest in schema1 format
|
// Rewrite manifest in schema1 format
|
||||||
ctxu.GetLogger(imh).Infof("rewriting manifest list %s in schema1 format to support old client", imh.Digest.String())
|
ctxu.GetLogger(imh).Infof("rewriting manifest list %s in schema1 format to support old client", imh.Digest.String())
|
||||||
|
|
||||||
|
@ -212,7 +219,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If necessary, convert the image manifest
|
// If necessary, convert the image manifest
|
||||||
if schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest); isSchema2 && !(supportsSchema2 || supportsOCISchema) {
|
if schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest); isSchema2 && !supports[manifestSchema2] {
|
||||||
manifest, err = imh.convertSchema2Manifest(schema2Manifest)
|
manifest, err = imh.convertSchema2Manifest(schema2Manifest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -116,7 +116,7 @@ type FileWriter interface {
|
||||||
// number of path components separated by slashes, where each component is
|
// number of path components separated by slashes, where each component is
|
||||||
// restricted to alphanumeric characters or a period, underscore, or
|
// restricted to alphanumeric characters or a period, underscore, or
|
||||||
// hyphen.
|
// hyphen.
|
||||||
var PathRegexp = regexp.MustCompile(`^(/[A-Za-z0-9._:-]+)+$`)
|
var PathRegexp = regexp.MustCompile(`^(/[A-Za-z0-9._-]+)+$`)
|
||||||
|
|
||||||
// ErrUnsupportedMethod may be returned in the case where a StorageDriver implementation does not support an optional method.
|
// ErrUnsupportedMethod may be returned in the case where a StorageDriver implementation does not support an optional method.
|
||||||
type ErrUnsupportedMethod struct {
|
type ErrUnsupportedMethod struct {
|
||||||
|
|
Loading…
Reference in a new issue