address get manifest issue with oci. namespace; and comment descriptions

Signed-off-by: Mike Brown <brownwm@us.ibm.com>
pull/2614/head
Mike Brown 2017-07-12 18:07:46 -05:00
parent fcaffa38bc
commit 426afb3a4c
3 changed files with 9 additions and 183 deletions

View File

@ -61,7 +61,7 @@ func (m Manifest) References() []distribution.Descriptor {
return references
}
// Target returns the target of this signed manifest.
// Target returns the target of this manifest.
func (m Manifest) Target() distribution.Descriptor {
return m.Config
}

View File

@ -79,7 +79,7 @@ func (m Manifest) References() []distribution.Descriptor {
return references
}
// Target returns the target of this signed manifest.
// Target returns the target of this manifest.
func (m Manifest) Target() distribution.Descriptor {
return m.Config
}

View File

@ -111,13 +111,11 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
}
supportsOCI := supportsOCISchema || supportsOCIImageIndex
var manifest distribution.Manifest
if imh.Tag != "" {
tags := imh.Repository.Tags(imh)
var desc distribution.Descriptor
if !supportsOCI {
desc, err = tags.Get(imh, imh.Tag)
} else {
desc, err = tags.Get(imh, imh.annotatedTag(supportsOCI))
if err != nil && supportsOCI { // in the supportsOCI case fall back to the non OCI image
desc, err = tags.Get(imh, imh.annotatedTag(false))
}
if err != nil {
@ -140,7 +138,12 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
if imh.Tag != "" {
options = append(options, distribution.WithTag(imh.annotatedTag(supportsOCI)))
}
var manifest distribution.Manifest
manifest, err = manifests.Get(imh, imh.Digest, options...)
if err != nil && supportsOCI && imh.Tag != "" { // in the supportsOCI case fall back to the non OCI image
options = append(options[:0], distribution.WithTag(imh.annotatedTag(false)))
manifest, err = manifests.Get(imh, imh.Digest, options...)
}
if err != nil {
if _, ok := err.(distribution.ErrManifestUnknownRevision); ok {
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
@ -238,183 +241,6 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
w.Write(p)
}
// GetImageManifest fetches the image manifest from the storage backend, if it exists.
func (imh *manifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Request) {
fmt.Printf("\n\nGetting a manifest!\n\n\n")
supportsSchema2 := false
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
// https://github.com/golang/gddo/blob/e91d4165076d7474d20abda83f92d15c7ebc3e81/httputil/header/header.go#L165-L202
for _, acceptHeader := range r.Header["Accept"] {
// r.Header[...] is a slice in case the request contains the same header more than once
// if the header isn't set, we'll get the zero value, which "range" will handle gracefully
// we need to split each header value on "," to get the full list of "Accept" values (per RFC 2616)
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
for _, mediaType := range strings.Split(acceptHeader, ",") {
// remove "; q=..." if present
if i := strings.Index(mediaType, ";"); i >= 0 {
mediaType = mediaType[:i]
}
// it's common (but not required) for Accept values to be space separated ("a/b, c/d, e/f")
mediaType = strings.TrimSpace(mediaType)
if mediaType == schema2.MediaTypeManifest {
supportsSchema2 = true
}
if mediaType == manifestlist.MediaTypeManifestList {
supportsManifestList = true
}
if mediaType == v1.MediaTypeImageManifest {
supportsOCISchema = true
}
if mediaType == v1.MediaTypeImageIndex {
supportsOCIImageIndex = true
}
}
}
supportsOCI := supportsOCISchema || supportsOCIImageIndex
ctxu.GetLogger(imh).Debug("GetImageManifest")
manifests, err := imh.Repository.Manifests(imh)
if err != nil {
imh.Errors = append(imh.Errors, err)
return
}
var manifest distribution.Manifest
if imh.Tag != "" {
tags := imh.Repository.Tags(imh)
var desc distribution.Descriptor
if !supportsOCI {
desc, err = tags.Get(imh, imh.Tag)
if err != nil {
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
return
}
} else {
desc, err = tags.Get(imh, imh.annotatedTag(supportsOCI))
if err != nil {
desc, err = tags.Get(imh, imh.annotatedTag(false))
if err != nil {
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
return
}
}
}
imh.Digest = desc.Digest
}
if etagMatch(r, imh.Digest.String()) {
w.WriteHeader(http.StatusNotModified)
return
}
var options []distribution.ManifestServiceOption
if imh.Tag != "" {
options = append(options, distribution.WithTag(imh.annotatedTag(supportsOCI)))
}
manifest, err = manifests.Get(imh, imh.Digest, options...)
if err != nil {
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
return
}
schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest)
manifestList, isManifestList := manifest.(*manifestlist.DeserializedManifestList)
isAnOCIManifest := isSchema2 && (schema2Manifest.MediaType == v1.MediaTypeImageManifest)
isAnOCIImageIndex := isManifestList && (manifestList.MediaType == v1.MediaTypeImageIndex)
badCombinations := [][]bool{
{isSchema2 && !isAnOCIManifest, supportsOCISchema && !supportsSchema2},
{isManifestList && !isAnOCIImageIndex, supportsOCIImageIndex && !supportsManifestList},
{isAnOCIManifest, !supportsOCISchema && supportsSchema2},
{isAnOCIImageIndex, !supportsOCIImageIndex && supportsManifestList},
}
for i, combo := range badCombinations {
if combo[0] && combo[1] {
fmt.Printf("\n\nbad combo! %d\n\n\n", i)
w.WriteHeader(http.StatusNotFound)
return
}
}
if isAnOCIManifest {
fmt.Print("\n\nreturning OCI manifest\n\n")
} else if isSchema2 {
fmt.Print("\n\nreturning schema 2 manifest\n\n")
} else {
fmt.Print("\n\nreturning schema 1 manifest\n\n")
}
// Only rewrite schema2 manifests when they are being fetched by tag.
// If they are being fetched by digest, we can't return something not
// matching the digest.
if imh.Tag != "" && isSchema2 && !(supportsSchema2 || supportsOCISchema) {
// Rewrite manifest in schema1 format
dcontext.GetLogger(imh).Infof("rewriting manifest %s in schema1 format to support old client", imh.Digest.String())
manifest, err = imh.convertSchema2Manifest(schema2Manifest)
if err != nil {
return
}
} 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())
// Find the image manifest corresponding to the default
// platform
var manifestDigest digest.Digest
for _, manifestDescriptor := range manifestList.Manifests {
if manifestDescriptor.Platform.Architecture == defaultArch && manifestDescriptor.Platform.OS == defaultOS {
manifestDigest = manifestDescriptor.Digest
break
}
}
if manifestDigest == "" {
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown)
return
}
manifest, err = manifests.Get(imh, manifestDigest)
if err != nil {
if _, ok := err.(distribution.ErrManifestUnknownRevision); ok {
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err))
} else {
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
}
return
}
// If necessary, convert the image manifest
if schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest); isSchema2 && !supportsSchema2 {
manifest, err = imh.convertSchema2Manifest(schema2Manifest)
if err != nil {
return
}
} else {
imh.Digest = manifestDigest
}
}
ct, p, err := manifest.Payload()
if err != nil {
return
}
w.Header().Set("Content-Type", ct)
w.Header().Set("Content-Length", fmt.Sprint(len(p)))
w.Header().Set("Docker-Content-Digest", imh.Digest.String())
w.Header().Set("Etag", fmt.Sprintf(`"%s"`, imh.Digest))
w.Write(p)
fmt.Printf("\n\nSucceeded in getting the manifest!\n\n\n")
}
func (imh *manifestHandler) convertSchema2Manifest(schema2Manifest *schema2.DeserializedManifest) (distribution.Manifest, error) {
targetDescriptor := schema2Manifest.Target()
blobs := imh.Repository.Blobs(imh)