address get manifest issue with oci. namespace; and comment descriptions
Signed-off-by: Mike Brown <brownwm@us.ibm.com>master
							parent
							
								
									fcaffa38bc
								
							
						
					
					
						commit
						426afb3a4c
					
				|  | @ -61,7 +61,7 @@ func (m Manifest) References() []distribution.Descriptor { | ||||||
| 	return references | 	return references | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Target returns the target of this signed manifest.
 | // Target returns the target of this manifest.
 | ||||||
| func (m Manifest) Target() distribution.Descriptor { | func (m Manifest) Target() distribution.Descriptor { | ||||||
| 	return m.Config | 	return m.Config | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -79,7 +79,7 @@ func (m Manifest) References() []distribution.Descriptor { | ||||||
| 	return references | 	return references | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Target returns the target of this signed manifest.
 | // Target returns the target of this manifest.
 | ||||||
| func (m Manifest) Target() distribution.Descriptor { | func (m Manifest) Target() distribution.Descriptor { | ||||||
| 	return m.Config | 	return m.Config | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -111,13 +111,11 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) | ||||||
| 	} | 	} | ||||||
| 	supportsOCI := supportsOCISchema || supportsOCIImageIndex | 	supportsOCI := supportsOCISchema || supportsOCIImageIndex | ||||||
| 
 | 
 | ||||||
| 	var manifest distribution.Manifest |  | ||||||
| 	if imh.Tag != "" { | 	if imh.Tag != "" { | ||||||
| 		tags := imh.Repository.Tags(imh) | 		tags := imh.Repository.Tags(imh) | ||||||
| 		var desc distribution.Descriptor | 		var desc distribution.Descriptor | ||||||
| 		if !supportsOCI { | 		desc, err = tags.Get(imh, imh.annotatedTag(supportsOCI)) | ||||||
| 			desc, err = tags.Get(imh, imh.Tag) | 		if err != nil && supportsOCI { // in the supportsOCI case fall back to the non OCI image
 | ||||||
| 		} else { |  | ||||||
| 			desc, err = tags.Get(imh, imh.annotatedTag(false)) | 			desc, err = tags.Get(imh, imh.annotatedTag(false)) | ||||||
| 		} | 		} | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -140,7 +138,12 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request) | ||||||
| 	if imh.Tag != "" { | 	if imh.Tag != "" { | ||||||
| 		options = append(options, distribution.WithTag(imh.annotatedTag(supportsOCI))) | 		options = append(options, distribution.WithTag(imh.annotatedTag(supportsOCI))) | ||||||
| 	} | 	} | ||||||
|  | 	var manifest distribution.Manifest | ||||||
| 	manifest, err = manifests.Get(imh, imh.Digest, options...) | 	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 err != nil { | ||||||
| 		if _, ok := err.(distribution.ErrManifestUnknownRevision); ok { | 		if _, ok := err.(distribution.ErrManifestUnknownRevision); ok { | ||||||
| 			imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown.WithDetail(err)) | 			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) | 	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) { | func (imh *manifestHandler) convertSchema2Manifest(schema2Manifest *schema2.DeserializedManifest) (distribution.Manifest, error) { | ||||||
| 	targetDescriptor := schema2Manifest.Target() | 	targetDescriptor := schema2Manifest.Target() | ||||||
| 	blobs := imh.Repository.Blobs(imh) | 	blobs := imh.Repository.Blobs(imh) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue