github.com/mforkel/docker-ce-i386@v17.12.1-ce-rc2+incompatible/components/engine/distribution/pull_v2_windows.go (about) 1 // +build windows 2 3 package distribution 4 5 import ( 6 "fmt" 7 "net/http" 8 "os" 9 "runtime" 10 "sort" 11 "strings" 12 13 "github.com/docker/distribution" 14 "github.com/docker/distribution/context" 15 "github.com/docker/distribution/manifest/manifestlist" 16 "github.com/docker/distribution/manifest/schema2" 17 "github.com/docker/distribution/registry/client/transport" 18 "github.com/docker/docker/pkg/system" 19 "github.com/sirupsen/logrus" 20 ) 21 22 var _ distribution.Describable = &v2LayerDescriptor{} 23 24 func (ld *v2LayerDescriptor) Descriptor() distribution.Descriptor { 25 if ld.src.MediaType == schema2.MediaTypeForeignLayer && len(ld.src.URLs) > 0 { 26 return ld.src 27 } 28 return distribution.Descriptor{} 29 } 30 31 func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) { 32 blobs := ld.repo.Blobs(ctx) 33 rsc, err := blobs.Open(ctx, ld.digest) 34 35 if len(ld.src.URLs) == 0 { 36 return rsc, err 37 } 38 39 // We're done if the registry has this blob. 40 if err == nil { 41 // Seek does an HTTP GET. If it succeeds, the blob really is accessible. 42 if _, err = rsc.Seek(0, os.SEEK_SET); err == nil { 43 return rsc, nil 44 } 45 rsc.Close() 46 } 47 48 // Find the first URL that results in a 200 result code. 49 for _, url := range ld.src.URLs { 50 logrus.Debugf("Pulling %v from foreign URL %v", ld.digest, url) 51 rsc = transport.NewHTTPReadSeeker(http.DefaultClient, url, nil) 52 53 // Seek does an HTTP GET. If it succeeds, the blob really is accessible. 54 _, err = rsc.Seek(0, os.SEEK_SET) 55 if err == nil { 56 break 57 } 58 logrus.Debugf("Download for %v failed: %v", ld.digest, err) 59 rsc.Close() 60 rsc = nil 61 } 62 return rsc, err 63 } 64 65 func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []manifestlist.ManifestDescriptor { 66 osVersion := "" 67 if os == "windows" { 68 // TODO: Add UBR (Update Build Release) component after build 69 version := system.GetOSVersion() 70 osVersion = fmt.Sprintf("%d.%d.%d", version.MajorVersion, version.MinorVersion, version.Build) 71 logrus.Debugf("will prefer entries with version %s", osVersion) 72 } 73 74 var matches []manifestlist.ManifestDescriptor 75 for _, manifestDescriptor := range manifests { 76 // TODO: Consider filtering out greater versions, including only greater UBR 77 if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == os { 78 matches = append(matches, manifestDescriptor) 79 logrus.Debugf("found match for %s/%s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String()) 80 } 81 } 82 if os == "windows" { 83 sort.Stable(manifestsByVersion{osVersion, matches}) 84 } 85 return matches 86 } 87 88 func versionMatch(actual, expected string) bool { 89 // Check whether the version matches up to the build, ignoring UBR 90 return strings.HasPrefix(actual, expected+".") 91 } 92 93 type manifestsByVersion struct { 94 version string 95 list []manifestlist.ManifestDescriptor 96 } 97 98 func (mbv manifestsByVersion) Less(i, j int) bool { 99 // TODO: Split version by parts and compare 100 // TODO: Prefer versions which have a greater version number 101 // Move compatible versions to the top, with no other ordering changes 102 return versionMatch(mbv.list[i].Platform.OSVersion, mbv.version) && !versionMatch(mbv.list[j].Platform.OSVersion, mbv.version) 103 } 104 105 func (mbv manifestsByVersion) Len() int { 106 return len(mbv.list) 107 } 108 109 func (mbv manifestsByVersion) Swap(i, j int) { 110 mbv.list[i], mbv.list[j] = mbv.list[j], mbv.list[i] 111 }