Update logic to choose manifest from manifest list to check
for os version on Windows. Separate the logic for windows
and unix to keep unix logic the same.
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
... | ... |
@@ -708,29 +708,20 @@ func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mf |
708 | 708 |
} |
709 | 709 |
|
710 | 710 |
logrus.Debugf("%s resolved to a manifestList object with %d entries; looking for a os/arch match", ref, len(mfstList.Manifests)) |
711 |
- var manifestDigest digest.Digest |
|
712 |
- // TODO @jhowardmsft LCOW Support: Need to remove the hard coding in LCOW mode. |
|
713 |
- lookingForOS := runtime.GOOS |
|
714 |
- if system.LCOWSupported() { |
|
715 |
- lookingForOS = "linux" |
|
716 |
- } |
|
717 |
- for _, manifestDescriptor := range mfstList.Manifests { |
|
718 |
- // TODO(aaronl): The manifest list spec supports optional |
|
719 |
- // "features" and "variant" fields. These are not yet used. |
|
720 |
- // Once they are, their values should be interpreted here. |
|
721 |
- if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == lookingForOS { |
|
722 |
- manifestDigest = manifestDescriptor.Digest |
|
723 |
- logrus.Debugf("found match for %s/%s with media type %s, digest %s", runtime.GOOS, runtime.GOARCH, manifestDescriptor.MediaType, manifestDigest.String()) |
|
724 |
- break |
|
725 |
- } |
|
726 |
- } |
|
727 | 711 |
|
728 |
- if manifestDigest == "" { |
|
712 |
+ manifestMatches := filterManifests(mfstList.Manifests) |
|
713 |
+ |
|
714 |
+ if len(manifestMatches) == 0 { |
|
729 | 715 |
errMsg := fmt.Sprintf("no matching manifest for %s/%s in the manifest list entries", runtime.GOOS, runtime.GOARCH) |
730 | 716 |
logrus.Debugf(errMsg) |
731 | 717 |
return "", "", errors.New(errMsg) |
732 | 718 |
} |
733 | 719 |
|
720 |
+ if len(manifestMatches) > 1 { |
|
721 |
+ logrus.Debugf("found multiple matches in manifest list, choosing best match %s", manifestMatches[0].Digest.String()) |
|
722 |
+ } |
|
723 |
+ manifestDigest := manifestMatches[0].Digest |
|
724 |
+ |
|
734 | 725 |
manSvc, err := p.repo.Manifests(ctx) |
735 | 726 |
if err != nil { |
736 | 727 |
return "", "", err |
... | ... |
@@ -3,11 +3,27 @@ |
3 | 3 |
package distribution |
4 | 4 |
|
5 | 5 |
import ( |
6 |
+ "runtime" |
|
7 |
+ |
|
6 | 8 |
"github.com/docker/distribution" |
7 | 9 |
"github.com/docker/distribution/context" |
10 |
+ "github.com/docker/distribution/manifest/manifestlist" |
|
11 |
+ "github.com/sirupsen/logrus" |
|
8 | 12 |
) |
9 | 13 |
|
10 | 14 |
func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) { |
11 | 15 |
blobs := ld.repo.Blobs(ctx) |
12 | 16 |
return blobs.Open(ctx, ld.digest) |
13 | 17 |
} |
18 |
+ |
|
19 |
+func filterManifests(manifests []manifestlist.ManifestDescriptor) []manifestlist.ManifestDescriptor { |
|
20 |
+ var matches []manifestlist.ManifestDescriptor |
|
21 |
+ for _, manifestDescriptor := range manifests { |
|
22 |
+ if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == runtime.GOOS { |
|
23 |
+ matches = append(matches, manifestDescriptor) |
|
24 |
+ |
|
25 |
+ logrus.Debugf("found match for %s/%s with media type %s, digest %s", runtime.GOOS, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String()) |
|
26 |
+ } |
|
27 |
+ } |
|
28 |
+ return matches |
|
29 |
+} |
... | ... |
@@ -3,13 +3,19 @@ |
3 | 3 |
package distribution |
4 | 4 |
|
5 | 5 |
import ( |
6 |
+ "fmt" |
|
6 | 7 |
"net/http" |
7 | 8 |
"os" |
9 |
+ "runtime" |
|
10 |
+ "sort" |
|
11 |
+ "strings" |
|
8 | 12 |
|
9 | 13 |
"github.com/docker/distribution" |
10 | 14 |
"github.com/docker/distribution/context" |
15 |
+ "github.com/docker/distribution/manifest/manifestlist" |
|
11 | 16 |
"github.com/docker/distribution/manifest/schema2" |
12 | 17 |
"github.com/docker/distribution/registry/client/transport" |
18 |
+ "github.com/docker/docker/pkg/system" |
|
13 | 19 |
"github.com/sirupsen/logrus" |
14 | 20 |
) |
15 | 21 |
|
... | ... |
@@ -55,3 +61,57 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo |
55 | 55 |
} |
56 | 56 |
return rsc, err |
57 | 57 |
} |
58 |
+ |
|
59 |
+func filterManifests(manifests []manifestlist.ManifestDescriptor) []manifestlist.ManifestDescriptor { |
|
60 |
+ version := system.GetOSVersion() |
|
61 |
+ |
|
62 |
+ // TODO @jhowardmsft LCOW Support: Need to remove the hard coding in LCOW mode. |
|
63 |
+ lookingForOS := runtime.GOOS |
|
64 |
+ osVersion := fmt.Sprintf("%d.%d.%d", version.MajorVersion, version.MinorVersion, version.Build) |
|
65 |
+ if system.LCOWSupported() { |
|
66 |
+ lookingForOS = "linux" |
|
67 |
+ osVersion = "" |
|
68 |
+ } |
|
69 |
+ |
|
70 |
+ var matches []manifestlist.ManifestDescriptor |
|
71 |
+ for _, manifestDescriptor := range manifests { |
|
72 |
+ if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == lookingForOS { |
|
73 |
+ if !versionMatch(manifestDescriptor.Platform.OSVersion, osVersion) { |
|
74 |
+ continue |
|
75 |
+ } |
|
76 |
+ matches = append(matches, manifestDescriptor) |
|
77 |
+ |
|
78 |
+ logrus.Debugf("found match for %s/%s with media type %s, digest %s", runtime.GOOS, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String()) |
|
79 |
+ } |
|
80 |
+ } |
|
81 |
+ sort.Stable(manifestsByVersion(matches)) |
|
82 |
+ return matches |
|
83 |
+} |
|
84 |
+ |
|
85 |
+func versionMatch(actual, expected string) bool { |
|
86 |
+ // Check whether actual and expected are equivalent, or whether |
|
87 |
+ // expected is a version prefix of actual. |
|
88 |
+ return actual == "" || expected == "" || actual == expected || strings.HasPrefix(actual, expected+".") |
|
89 |
+} |
|
90 |
+ |
|
91 |
+type manifestsByVersion []manifestlist.ManifestDescriptor |
|
92 |
+ |
|
93 |
+func (mbv manifestsByVersion) Less(i, j int) bool { |
|
94 |
+ if mbv[i].Platform.OSVersion == "" { |
|
95 |
+ return false |
|
96 |
+ } |
|
97 |
+ if mbv[j].Platform.OSVersion == "" { |
|
98 |
+ return true |
|
99 |
+ } |
|
100 |
+ // TODO: Split version by parts and compare |
|
101 |
+ // TODO: Prefer versions which have a greater version number |
|
102 |
+ return false |
|
103 |
+} |
|
104 |
+ |
|
105 |
+func (mbv manifestsByVersion) Len() int { |
|
106 |
+ return len(mbv) |
|
107 |
+} |
|
108 |
+ |
|
109 |
+func (mbv manifestsByVersion) Swap(i, j int) { |
|
110 |
+ mbv[i], mbv[j] = mbv[j], mbv[i] |
|
111 |
+} |