瀏覽代碼

Merge pull request #35090 from dmcgowan/windows-support-os-version

Add support for Windows version filtering on pull
Yong Tang 7 年之前
父節點
當前提交
b8571fd81c
共有 3 個文件被更改,包括 84 次插入17 次删除
  1. 8 17
      distribution/pull_v2.go
  2. 16 0
      distribution/pull_v2_unix.go
  3. 60 0
      distribution/pull_v2_windows.go

+ 8 - 17
distribution/pull_v2.go

@@ -708,29 +708,20 @@ func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mf
 	}
 	}
 
 
 	logrus.Debugf("%s resolved to a manifestList object with %d entries; looking for a os/arch match", ref, len(mfstList.Manifests))
 	logrus.Debugf("%s resolved to a manifestList object with %d entries; looking for a os/arch match", ref, len(mfstList.Manifests))
-	var manifestDigest digest.Digest
-	// TODO @jhowardmsft LCOW Support: Need to remove the hard coding in LCOW mode.
-	lookingForOS := runtime.GOOS
-	if system.LCOWSupported() {
-		lookingForOS = "linux"
-	}
-	for _, manifestDescriptor := range mfstList.Manifests {
-		// TODO(aaronl): The manifest list spec supports optional
-		// "features" and "variant" fields. These are not yet used.
-		// Once they are, their values should be interpreted here.
-		if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == lookingForOS {
-			manifestDigest = manifestDescriptor.Digest
-			logrus.Debugf("found match for %s/%s with media type %s, digest %s", runtime.GOOS, runtime.GOARCH, manifestDescriptor.MediaType, manifestDigest.String())
-			break
-		}
-	}
 
 
-	if manifestDigest == "" {
+	manifestMatches := filterManifests(mfstList.Manifests)
+
+	if len(manifestMatches) == 0 {
 		errMsg := fmt.Sprintf("no matching manifest for %s/%s in the manifest list entries", runtime.GOOS, runtime.GOARCH)
 		errMsg := fmt.Sprintf("no matching manifest for %s/%s in the manifest list entries", runtime.GOOS, runtime.GOARCH)
 		logrus.Debugf(errMsg)
 		logrus.Debugf(errMsg)
 		return "", "", errors.New(errMsg)
 		return "", "", errors.New(errMsg)
 	}
 	}
 
 
+	if len(manifestMatches) > 1 {
+		logrus.Debugf("found multiple matches in manifest list, choosing best match %s", manifestMatches[0].Digest.String())
+	}
+	manifestDigest := manifestMatches[0].Digest
+
 	manSvc, err := p.repo.Manifests(ctx)
 	manSvc, err := p.repo.Manifests(ctx)
 	if err != nil {
 	if err != nil {
 		return "", "", err
 		return "", "", err

+ 16 - 0
distribution/pull_v2_unix.go

@@ -3,11 +3,27 @@
 package distribution
 package distribution
 
 
 import (
 import (
+	"runtime"
+
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
+	"github.com/docker/distribution/manifest/manifestlist"
+	"github.com/sirupsen/logrus"
 )
 )
 
 
 func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) {
 func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) {
 	blobs := ld.repo.Blobs(ctx)
 	blobs := ld.repo.Blobs(ctx)
 	return blobs.Open(ctx, ld.digest)
 	return blobs.Open(ctx, ld.digest)
 }
 }
+
+func filterManifests(manifests []manifestlist.ManifestDescriptor) []manifestlist.ManifestDescriptor {
+	var matches []manifestlist.ManifestDescriptor
+	for _, manifestDescriptor := range manifests {
+		if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == runtime.GOOS {
+			matches = append(matches, manifestDescriptor)
+
+			logrus.Debugf("found match for %s/%s with media type %s, digest %s", runtime.GOOS, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
+		}
+	}
+	return matches
+}

+ 60 - 0
distribution/pull_v2_windows.go

@@ -3,13 +3,19 @@
 package distribution
 package distribution
 
 
 import (
 import (
+	"fmt"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
+	"runtime"
+	"sort"
+	"strings"
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
+	"github.com/docker/distribution/manifest/manifestlist"
 	"github.com/docker/distribution/manifest/schema2"
 	"github.com/docker/distribution/manifest/schema2"
 	"github.com/docker/distribution/registry/client/transport"
 	"github.com/docker/distribution/registry/client/transport"
+	"github.com/docker/docker/pkg/system"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
 
 
@@ -55,3 +61,57 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo
 	}
 	}
 	return rsc, err
 	return rsc, err
 }
 }
+
+func filterManifests(manifests []manifestlist.ManifestDescriptor) []manifestlist.ManifestDescriptor {
+	version := system.GetOSVersion()
+
+	// TODO @jhowardmsft LCOW Support: Need to remove the hard coding in LCOW mode.
+	lookingForOS := runtime.GOOS
+	osVersion := fmt.Sprintf("%d.%d.%d", version.MajorVersion, version.MinorVersion, version.Build)
+	if system.LCOWSupported() {
+		lookingForOS = "linux"
+		osVersion = ""
+	}
+
+	var matches []manifestlist.ManifestDescriptor
+	for _, manifestDescriptor := range manifests {
+		if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == lookingForOS {
+			if !versionMatch(manifestDescriptor.Platform.OSVersion, osVersion) {
+				continue
+			}
+			matches = append(matches, manifestDescriptor)
+
+			logrus.Debugf("found match for %s/%s with media type %s, digest %s", runtime.GOOS, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
+		}
+	}
+	sort.Stable(manifestsByVersion(matches))
+	return matches
+}
+
+func versionMatch(actual, expected string) bool {
+	// Check whether actual and expected are equivalent, or whether
+	// expected is a version prefix of actual.
+	return actual == "" || expected == "" || actual == expected || strings.HasPrefix(actual, expected+".")
+}
+
+type manifestsByVersion []manifestlist.ManifestDescriptor
+
+func (mbv manifestsByVersion) Less(i, j int) bool {
+	if mbv[i].Platform.OSVersion == "" {
+		return false
+	}
+	if mbv[j].Platform.OSVersion == "" {
+		return true
+	}
+	// TODO: Split version by parts and compare
+	// TODO: Prefer versions which have a greater version number
+	return false
+}
+
+func (mbv manifestsByVersion) Len() int {
+	return len(mbv)
+}
+
+func (mbv manifestsByVersion) Swap(i, j int) {
+	mbv[i], mbv[j] = mbv[j], mbv[i]
+}