Merge pull request #327 from johnstep/windows-manifest-lists

[17.09] Backport version fix for Windows manifest lists
This commit is contained in:
Andrew Hsu
2017-11-29 14:00:08 -08:00
committed by GitHub
3 changed files with 81 additions and 17 deletions
+8 -17
View File
@@ -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))
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)
logrus.Debugf(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)
if err != nil {
return "", "", err
@@ -3,11 +3,27 @@
package distribution
import (
"runtime"
"github.com/docker/distribution"
"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) {
blobs := ld.repo.Blobs(ctx)
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
}
@@ -3,13 +3,19 @@
package distribution
import (
"fmt"
"net/http"
"os"
"runtime"
"sort"
"strings"
"github.com/docker/distribution"
"github.com/docker/distribution/context"
"github.com/docker/distribution/manifest/manifestlist"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/registry/client/transport"
"github.com/docker/docker/pkg/system"
"github.com/sirupsen/logrus"
)
@@ -55,3 +61,54 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo
}
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 {
// TODO: Consider filtering out greater versions, including only greater UBR
if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == lookingForOS {
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())
}
}
if lookingForOS == "windows" {
sort.Stable(manifestsByVersion{osVersion, matches})
}
return matches
}
func versionMatch(actual, expected string) bool {
// Check whether the version matches up to the build, ignoring UBR
return strings.HasPrefix(actual, expected+".")
}
type manifestsByVersion struct {
version string
list []manifestlist.ManifestDescriptor
}
func (mbv manifestsByVersion) Less(i, j int) bool {
// TODO: Split version by parts and compare
// TODO: Prefer versions which have a greater version number
// Move compatible versions to the top, with no other ordering changes
return versionMatch(mbv.list[i].Platform.OSVersion, mbv.version) && !versionMatch(mbv.list[j].Platform.OSVersion, mbv.version)
}
func (mbv manifestsByVersion) Len() int {
return len(mbv.list)
}
func (mbv manifestsByVersion) Swap(i, j int) {
mbv.list[i], mbv.list[j] = mbv.list[j], mbv.list[i]
}