Skip to content

Commit

Permalink
Merge pull request containers#622 from vrothberg/platform
Browse files Browse the repository at this point in the history
libimage: lookup images by custom platform
  • Loading branch information
openshift-merge-robot authored Jun 18, 2021
2 parents 3c56250 + d8b7d14 commit c034cf4
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 17 deletions.
7 changes: 6 additions & 1 deletion libimage/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,12 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
// resolved name for pulling. Assume we're doing a `pull foo`.
// If there's already a local image "localhost/foo", then we should
// attempt pulling that instead of doing the full short-name dance.
localImage, resolvedImageName, err = r.LookupImage(imageName, nil)
lookupOptions := &LookupImageOptions{
Architecture: options.Architecture,
OS: options.OS,
Variant: options.Variant,
}
localImage, resolvedImageName, err = r.LookupImage(imageName, lookupOptions)
if err != nil && errors.Cause(err) != storage.ErrImageUnknown {
logrus.Errorf("Looking up %s in local storage: %v", imageName, err)
}
Expand Down
56 changes: 56 additions & 0 deletions libimage/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
goruntime "runtime"
"testing"

"github.com/containers/common/pkg/config"
Expand Down Expand Up @@ -67,3 +68,58 @@ func TestPull(t *testing.T) {
assert.True(t, rmReports[0].Removed)
}
}

func TestPullPlatforms(t *testing.T) {
runtime, cleanup := testNewRuntime(t)
defer cleanup()
ctx := context.Background()
pullOptions := &PullOptions{}
pullOptions.Writer = os.Stdout

localArch := goruntime.GOARCH
localOS := goruntime.GOOS

pulledImages, err := runtime.Pull(ctx, "busybox", config.PullPolicyAlways, pullOptions)
require.NoError(t, err, "pull busybox")
require.Len(t, pulledImages, 1)

image, _, err := runtime.LookupImage("busybox", nil)
require.NoError(t, err, "lookup busybox")
require.NotNil(t, image, "lookup busybox")

image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{IgnorePlatform: true})
require.NoError(t, err, "lookup busybox - ign. platform")
require.NotNil(t, image, "lookup busybox - ing. platform")

image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{Architecture: localArch})
require.NoError(t, err, "lookup busybox - by local arch")
require.NotNil(t, image, "lookup busybox - by local arch")

image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{OS: localOS})
require.NoError(t, err, "lookup busybox - by local arch")
require.NotNil(t, image, "lookup busybox - by local arch")

_, _, err = runtime.LookupImage("busybox", &LookupImageOptions{Architecture: "bogus"})
require.Error(t, err, "lookup busybox - bogus arch")

_, _, err = runtime.LookupImage("busybox", &LookupImageOptions{OS: "bogus"})
require.Error(t, err, "lookup busybox - bogus OS")

pullOptions.Architecture = "arm"
pulledImages, err = runtime.Pull(ctx, "busybox", config.PullPolicyAlways, pullOptions)
require.NoError(t, err, "pull busybox - arm")
require.Len(t, pulledImages, 1)

if localArch != "arm" {
_, _, err = runtime.LookupImage("busybox", nil)
require.Error(t, err, "lookup busybox - local arch != arm")
}

image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{Architecture: "arm"})
require.NoError(t, err, "lookup busybox - by arm")
require.NotNil(t, image, "lookup busybox - by local arch")

image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{IgnorePlatform: true})
require.NoError(t, err, "lookup busybox - ign. platform")
require.NotNil(t, image, "lookup busybox - ing. platform")
}
51 changes: 35 additions & 16 deletions libimage/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ type LookupImageOptions struct {
// the platform does not matter, for instance, for image removal.
IgnorePlatform bool

// Lookup an image matching the specified architecture.
Architecture string
// Lookup an image matching the specified OS.
OS string
// Lookup an image matching the specified variant.
Variant string

// If set, do not look for items/instances in the manifest list that
// match the current platform but return the manifest list as is.
lookupManifest bool
Expand Down Expand Up @@ -210,6 +217,25 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image,
name = strings.TrimPrefix(name, "sha256:")
}

// Set the platform for matching local images.
if !options.IgnorePlatform {
if options.Architecture == "" {
options.Architecture = r.systemContext.ArchitectureChoice
}
if options.Architecture == "" {
options.Architecture = runtime.GOARCH
}
if options.OS == "" {
options.OS = r.systemContext.OSChoice
}
if options.OS == "" {
options.OS = runtime.GOOS
}
if options.Variant == "" {
options.Variant = r.systemContext.VariantChoice
}
}

// First, check if we have an exact match in the storage. Maybe an ID
// or a fully-qualified image name.
img, err := r.lookupImageInLocalStorage(name, name, options)
Expand Down Expand Up @@ -295,7 +321,7 @@ func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *Loo
if err != nil {
return nil, err
}
instance, err := manifestList.LookupInstance(context.Background(), "", "", "")
instance, err := manifestList.LookupInstance(context.Background(), options.Architecture, options.OS, options.Variant)
if err != nil {
// NOTE: If we are not looking for a specific platform
// and already found the manifest list, then return it
Expand All @@ -316,7 +342,7 @@ func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *Loo
return image, nil
}

matches, err := imageReferenceMatchesContext(context.Background(), ref, &r.systemContext)
matches, err := r.imageReferenceMatchesContext(ref, options)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -428,12 +454,13 @@ func (r *Runtime) ResolveName(name string) (string, error) {
}

// imageReferenceMatchesContext return true if the specified reference matches
// the platform (os, arch, variant) as specified by the system context.
func imageReferenceMatchesContext(ctx context.Context, ref types.ImageReference, sys *types.SystemContext) (bool, error) {
if sys == nil {
// the platform (os, arch, variant) as specified by the lookup options.
func (r *Runtime) imageReferenceMatchesContext(ref types.ImageReference, options *LookupImageOptions) (bool, error) {
if options.IgnorePlatform {
return true, nil
}
img, err := ref.NewImage(ctx, sys)
ctx := context.Background()
img, err := ref.NewImage(ctx, &r.systemContext)
if err != nil {
return false, err
}
Expand All @@ -442,16 +469,8 @@ func imageReferenceMatchesContext(ctx context.Context, ref types.ImageReference,
if err != nil {
return false, err
}
osChoice := sys.OSChoice
if osChoice == "" {
osChoice = runtime.GOOS
}
arch := sys.ArchitectureChoice
if arch == "" {
arch = runtime.GOARCH
}
if osChoice == data.Os && arch == data.Architecture {
if sys.VariantChoice == "" || sys.VariantChoice == data.Variant {
if options.OS == data.Os && options.Architecture == data.Architecture {
if options.Variant == "" || options.Variant == data.Variant {
return true, nil
}
}
Expand Down

0 comments on commit c034cf4

Please sign in to comment.