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