github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/api/server/router/distribution/distribution_routes.go (about) 1 package distribution // import "github.com/docker/docker/api/server/router/distribution" 2 3 import ( 4 "context" 5 "encoding/json" 6 "net/http" 7 8 "github.com/docker/distribution/manifest/manifestlist" 9 "github.com/docker/distribution/manifest/schema1" 10 "github.com/docker/distribution/manifest/schema2" 11 "github.com/docker/distribution/reference" 12 "github.com/docker/docker/api/server/httputils" 13 "github.com/docker/docker/api/types/registry" 14 "github.com/docker/docker/errdefs" 15 v1 "github.com/opencontainers/image-spec/specs-go/v1" 16 "github.com/pkg/errors" 17 ) 18 19 func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 20 if err := httputils.ParseForm(r); err != nil { 21 return err 22 } 23 24 w.Header().Set("Content-Type", "application/json") 25 26 image := vars["name"] 27 28 // TODO why is reference.ParseAnyReference() / reference.ParseNormalizedNamed() not using the reference.ErrTagInvalidFormat (and so on) errors? 29 ref, err := reference.ParseAnyReference(image) 30 if err != nil { 31 return errdefs.InvalidParameter(err) 32 } 33 namedRef, ok := ref.(reference.Named) 34 if !ok { 35 if _, ok := ref.(reference.Digested); ok { 36 // full image ID 37 return errors.Errorf("no manifest found for full image ID") 38 } 39 return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", image)) 40 } 41 42 // For a search it is not an error if no auth was given. Ignore invalid 43 // AuthConfig to increase compatibility with the existing API. 44 authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader)) 45 distrepo, err := s.backend.GetRepository(ctx, namedRef, authConfig) 46 if err != nil { 47 return err 48 } 49 blobsrvc := distrepo.Blobs(ctx) 50 51 var distributionInspect registry.DistributionInspect 52 if canonicalRef, ok := namedRef.(reference.Canonical); !ok { 53 namedRef = reference.TagNameOnly(namedRef) 54 55 taggedRef, ok := namedRef.(reference.NamedTagged) 56 if !ok { 57 return errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", image)) 58 } 59 60 descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag()) 61 if err != nil { 62 return err 63 } 64 distributionInspect.Descriptor = v1.Descriptor{ 65 MediaType: descriptor.MediaType, 66 Digest: descriptor.Digest, 67 Size: descriptor.Size, 68 } 69 } else { 70 // TODO(nishanttotla): Once manifests can be looked up as a blob, the 71 // descriptor should be set using blobsrvc.Stat(ctx, canonicalRef.Digest()) 72 // instead of having to manually fill in the fields 73 distributionInspect.Descriptor.Digest = canonicalRef.Digest() 74 } 75 76 // we have a digest, so we can retrieve the manifest 77 mnfstsrvc, err := distrepo.Manifests(ctx) 78 if err != nil { 79 return err 80 } 81 mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest) 82 if err != nil { 83 switch err { 84 case reference.ErrReferenceInvalidFormat, 85 reference.ErrTagInvalidFormat, 86 reference.ErrDigestInvalidFormat, 87 reference.ErrNameContainsUppercase, 88 reference.ErrNameEmpty, 89 reference.ErrNameTooLong, 90 reference.ErrNameNotCanonical: 91 return errdefs.InvalidParameter(err) 92 } 93 return err 94 } 95 96 mediaType, payload, err := mnfst.Payload() 97 if err != nil { 98 return err 99 } 100 // update MediaType because registry might return something incorrect 101 distributionInspect.Descriptor.MediaType = mediaType 102 if distributionInspect.Descriptor.Size == 0 { 103 distributionInspect.Descriptor.Size = int64(len(payload)) 104 } 105 106 // retrieve platform information depending on the type of manifest 107 switch mnfstObj := mnfst.(type) { 108 case *manifestlist.DeserializedManifestList: 109 for _, m := range mnfstObj.Manifests { 110 distributionInspect.Platforms = append(distributionInspect.Platforms, v1.Platform{ 111 Architecture: m.Platform.Architecture, 112 OS: m.Platform.OS, 113 OSVersion: m.Platform.OSVersion, 114 OSFeatures: m.Platform.OSFeatures, 115 Variant: m.Platform.Variant, 116 }) 117 } 118 case *schema2.DeserializedManifest: 119 configJSON, err := blobsrvc.Get(ctx, mnfstObj.Config.Digest) 120 var platform v1.Platform 121 if err == nil { 122 err := json.Unmarshal(configJSON, &platform) 123 if err == nil && (platform.OS != "" || platform.Architecture != "") { 124 distributionInspect.Platforms = append(distributionInspect.Platforms, platform) 125 } 126 } 127 case *schema1.SignedManifest: 128 platform := v1.Platform{ 129 Architecture: mnfstObj.Architecture, 130 OS: "linux", 131 } 132 distributionInspect.Platforms = append(distributionInspect.Platforms, platform) 133 } 134 135 return httputils.WriteJSON(w, http.StatusOK, distributionInspect) 136 }