From d24ec648873698bac14047e0af128099186e38d3 Mon Sep 17 00:00:00 2001
From: Qi Wang <qiwan@redhat.com>
Date: Sat, 26 Sep 2020 19:49:43 -0400
Subject: Use local image if input image is a manifest list

If run&create image returns error: image contains manifest list, not a runnable image, find the local image that has digest matching the digest from the list and use the image from local storage for the command.

Signed-off-by: Qi Wang <qiwan@redhat.com>
---
 pkg/specgen/generate/container.go | 39 ++++++++++++++++++++++++++++++++++++++-
 test/e2e/create_test.go           | 17 +++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 147ebd61b..592e194aa 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -13,6 +13,7 @@ import (
 	"github.com/containers/podman/v2/pkg/specgen"
 	spec "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 )
 
@@ -33,7 +34,43 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
 
 		_, mediaType, err := newImage.Manifest(ctx)
 		if err != nil {
-			return nil, err
+			if errors.Cause(err) != image.ErrImageIsBareList {
+				return nil, err
+			}
+			// if err is not runnable image
+			// use the local store image with repo@digest matches with the list, if exists
+			manifestByte, manifestType, err := newImage.GetManifest(ctx, nil)
+			if err != nil {
+				return nil, err
+			}
+			list, err := manifest.ListFromBlob(manifestByte, manifestType)
+			if err != nil {
+				return nil, err
+			}
+			images, err := r.ImageRuntime().GetImages()
+			if err != nil {
+				return nil, err
+			}
+			findLocal := false
+			listDigest, err := list.ChooseInstance(r.SystemContext())
+			if err != nil {
+				return nil, err
+			}
+			for _, img := range images {
+				for _, imageDigest := range img.Digests() {
+					if imageDigest == listDigest {
+						newImage = img
+						s.Image = img.ID()
+						mediaType = manifestType
+						findLocal = true
+						logrus.Debug("image contains manifest list, using image from local storage")
+						break
+					}
+				}
+			}
+			if !findLocal {
+				return nil, image.ErrImageIsBareList
+			}
 		}
 
 		if s.HealthConfig == nil && mediaType == manifest.DockerV2Schema2MediaType {
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 45dbe9b56..3045bc7f4 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -609,4 +609,21 @@ var _ = Describe("Podman create", func() {
 		Expect(session.ExitCode()).ToNot(BeZero())
 	})
 
+	It("create use local store image if input image contains a manifest list", func() {
+		session := podmanTest.Podman([]string{"pull", BB})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(BeZero())
+
+		session = podmanTest.Podman([]string{"manifest", "create", "mylist"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+
+		session = podmanTest.Podman([]string{"manifest", "add", "--all", "mylist", BB})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(BeZero())
+
+		session = podmanTest.Podman([]string{"create", "mylist"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(BeZero())
+	})
 })
-- 
cgit v1.2.3-54-g00ecf