From 0f7d54b0260c1be992ee3b9cee359ef3a9e8bd21 Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Thu, 22 Apr 2021 08:01:12 +0200
Subject: migrate Podman to containers/common/libimage

Migrate the Podman code base over to `common/libimage` which replaces
`libpod/image` and a lot of glue code entirely.

Note that I tried to leave bread crumbs for changed tests.

Miscellaneous changes:

 * Some errors yield different messages which required to alter some
   tests.

 * I fixed some pre-existing issues in the code.  Others were marked as
   `//TODO`s to prevent the PR from exploding.

 * The `NamesHistory` of an image is returned as is from the storage.
   Previously, we did some filtering which I think is undesirable.
   Instead we should return the data as stored in the storage.

 * Touched handlers use the ABI interfaces where possible.

 * Local image resolution: previously Podman would match "foo" on
   "myfoo".  This behaviour has been changed and Podman will now
   only match on repository boundaries such that "foo" would match
   "my/foo" but not "myfoo".  I consider the old behaviour to be a
   bug, at the very least an exotic corner case.

 * Futhermore, "foo:none" does *not* resolve to a local image "foo"
   without tag anymore.  It's a hill I am (almost) willing to die on.

 * `image prune` prints the IDs of pruned images.  Previously, in some
   cases, the names were printed instead.  The API clearly states ID,
   so we should stick to it.

 * Compat endpoint image removal with _force_ deletes the entire not
   only the specified tag.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
---
 pkg/domain/entities/manifest.go             |   1 +
 pkg/domain/infra/abi/containers.go          |  16 +-
 pkg/domain/infra/abi/containers_runlabel.go |  86 ++--
 pkg/domain/infra/abi/images.go              | 582 ++++++++++++----------------
 pkg/domain/infra/abi/images_list.go         |  61 +--
 pkg/domain/infra/abi/manifest.go            | 327 +++++++++-------
 pkg/domain/infra/abi/play.go                |  59 ++-
 pkg/domain/infra/abi/system.go              |  21 +-
 pkg/domain/infra/tunnel/images.go           |   4 +-
 9 files changed, 553 insertions(+), 604 deletions(-)

(limited to 'pkg/domain')

diff --git a/pkg/domain/entities/manifest.go b/pkg/domain/entities/manifest.go
index 6a645e20b..3f89e4d30 100644
--- a/pkg/domain/entities/manifest.go
+++ b/pkg/domain/entities/manifest.go
@@ -8,6 +8,7 @@ type ManifestCreateOptions struct {
 	All bool `schema:"all"`
 }
 
+// swagger:model ManifestAddOpts
 type ManifestAddOptions struct {
 	All           bool               `json:"all" schema:"all"`
 	Annotation    []string           `json:"annotation" schema:"annotation"`
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 82f2a2424..ef3ccab0c 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -15,7 +15,6 @@ import (
 	"github.com/containers/podman/v3/libpod"
 	"github.com/containers/podman/v3/libpod/define"
 	"github.com/containers/podman/v3/libpod/events"
-	"github.com/containers/podman/v3/libpod/image"
 	"github.com/containers/podman/v3/libpod/logs"
 	"github.com/containers/podman/v3/pkg/cgroups"
 	"github.com/containers/podman/v3/pkg/checkpoint"
@@ -23,6 +22,7 @@ import (
 	"github.com/containers/podman/v3/pkg/domain/entities/reports"
 	dfilters "github.com/containers/podman/v3/pkg/domain/filters"
 	"github.com/containers/podman/v3/pkg/domain/infra/abi/terminal"
+	"github.com/containers/podman/v3/pkg/errorhandling"
 	parallelctr "github.com/containers/podman/v3/pkg/parallel/ctr"
 	"github.com/containers/podman/v3/pkg/ps"
 	"github.com/containers/podman/v3/pkg/rootless"
@@ -438,7 +438,8 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
 	default:
 		return nil, errors.Errorf("unrecognized image format %q", options.Format)
 	}
-	sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
+
+	sc := ic.Libpod.SystemContext()
 	coptions := buildah.CommitOptions{
 		SignaturePolicyPath:   rtc.Engine.SignaturePolicyPath,
 		ReportWriter:          options.Writer,
@@ -999,14 +1000,9 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
 
 		if options.RemoveImage {
 			_, imageName := ctr.Image()
-			ctrImage, err := ic.Libpod.ImageRuntime().NewFromLocal(imageName)
-			if err != nil {
-				report.RmiErr = err
-				reports = append(reports, &report)
-				continue
-			}
-			_, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
-			report.RmiErr = err
+			imageEngine := ImageEngine{Libpod: ic.Libpod}
+			_, rmErrors := imageEngine.Remove(ctx, []string{imageName}, entities.ImageRemoveOptions{})
+			report.RmiErr = errorhandling.JoinErrors(rmErrors)
 		}
 
 		reports = append(reports, &report)
diff --git a/pkg/domain/infra/abi/containers_runlabel.go b/pkg/domain/infra/abi/containers_runlabel.go
index 2cabab988..199ae43ad 100644
--- a/pkg/domain/infra/abi/containers_runlabel.go
+++ b/pkg/domain/infra/abi/containers_runlabel.go
@@ -7,8 +7,9 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/config"
 	"github.com/containers/podman/v3/libpod/define"
-	"github.com/containers/podman/v3/libpod/image"
 	"github.com/containers/podman/v3/pkg/domain/entities"
 	envLib "github.com/containers/podman/v3/pkg/env"
 	"github.com/containers/podman/v3/utils"
@@ -18,21 +19,48 @@ import (
 )
 
 func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string, imageRef string, args []string, options entities.ContainerRunlabelOptions) error {
-	// First, get the image and pull it if needed.
-	img, err := ic.runlabelImage(ctx, label, imageRef, options)
+	pullOptions := &libimage.PullOptions{}
+	pullOptions.AuthFilePath = options.Authfile
+	pullOptions.CertDirPath = options.CertDir
+	pullOptions.Credentials = options.Credentials
+	pullOptions.SignaturePolicyPath = options.SignaturePolicy
+	pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
+
+	pullPolicy := config.PullPolicyNever
+	if options.Pull {
+		pullPolicy = config.PullPolicyMissing
+	}
+	if !options.Quiet {
+		pullOptions.Writer = os.Stderr
+	}
+
+	pulledImages, err := ic.Libpod.LibimageRuntime().Pull(ctx, imageRef, pullPolicy, pullOptions)
 	if err != nil {
 		return err
 	}
+
+	if len(pulledImages) != 1 {
+		return errors.Errorf("internal error: expected an image to be pulled (or an error)")
+	}
+
 	// Extract the runlabel from the image.
-	runlabel, err := img.GetLabel(ctx, label)
+	labels, err := pulledImages[0].Labels(ctx)
 	if err != nil {
 		return err
 	}
+
+	var runlabel string
+	for k, v := range labels {
+		if strings.EqualFold(k, label) {
+			runlabel = v
+			break
+		}
+	}
 	if runlabel == "" {
 		return errors.Errorf("cannot find the value of label: %s in image: %s", label, imageRef)
 	}
 
-	cmd, env, err := generateRunlabelCommand(runlabel, img, args, options)
+	cmd, env, err := generateRunlabelCommand(runlabel, pulledImages[0], imageRef, args, options)
 	if err != nil {
 		return err
 	}
@@ -76,36 +104,9 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
 	return utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...)
 }
 
-// runlabelImage returns an image based on the specified image AND options.
-func (ic *ContainerEngine) runlabelImage(ctx context.Context, label string, imageRef string, options entities.ContainerRunlabelOptions) (*image.Image, error) {
-	// First, look up the image locally. If we get an error and requested
-	// to pull, fallthrough and pull it.
-	img, err := ic.Libpod.ImageRuntime().NewFromLocal(imageRef)
-	switch {
-	case err == nil:
-		return img, nil
-	case !options.Pull:
-		return nil, err
-	default:
-		// Fallthrough and pull!
-	}
-
-	pullOptions := entities.ImagePullOptions{
-		Quiet:           options.Quiet,
-		CertDir:         options.CertDir,
-		SkipTLSVerify:   options.SkipTLSVerify,
-		SignaturePolicy: options.SignaturePolicy,
-		Authfile:        options.Authfile,
-	}
-	if _, err := pull(ctx, ic.Libpod.ImageRuntime(), imageRef, pullOptions, &label); err != nil {
-		return nil, err
-	}
-	return ic.Libpod.ImageRuntime().NewFromLocal(imageRef)
-}
-
 // generateRunlabelCommand generates the to-be-executed command as a string
 // slice along with a base environment.
-func generateRunlabelCommand(runlabel string, img *image.Image, args []string, options entities.ContainerRunlabelOptions) ([]string, []string, error) {
+func generateRunlabelCommand(runlabel string, img *libimage.Image, inputName string, args []string, options entities.ContainerRunlabelOptions) ([]string, []string, error) {
 	var (
 		err             error
 		name, imageName string
@@ -113,24 +114,25 @@ func generateRunlabelCommand(runlabel string, img *image.Image, args []string, o
 		cmd             []string
 	)
 
-	// TODO: How do we get global opts as done in v1?
-
 	// Extract the imageName (or ID).
-	imgNames := img.Names()
+	imgNames := img.NamesHistory()
 	if len(imgNames) == 0 {
 		imageName = img.ID()
 	} else {
+		// The newest name is the first entry in the `NamesHistory`
+		// slice.
 		imageName = imgNames[0]
 	}
 
 	// Use the user-specified name or extract one from the image.
-	if options.Name != "" {
-		name = options.Name
-	} else {
-		name, err = image.GetImageBaseName(imageName)
-		if err != nil {
-			return nil, nil, err
+	name = options.Name
+	if name == "" {
+		normalize := imageName
+		if !strings.HasPrefix(img.ID(), inputName) {
+			normalize = inputName
 		}
+		splitImageName := strings.Split(normalize, "/")
+		name = splitImageName[len(splitImageName)-1]
 	}
 
 	// Append the user-specified arguments to the runlabel (command).
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 84c7ebecd..0364b00a3 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -3,15 +3,14 @@ package abi
 import (
 	"context"
 	"fmt"
-	"io"
 	"io/ioutil"
 	"net/url"
 	"os"
 	"path"
 	"path/filepath"
 	"strconv"
-	"strings"
 
+	"github.com/containers/common/libimage"
 	"github.com/containers/common/pkg/config"
 	"github.com/containers/image/v5/docker"
 	"github.com/containers/image/v5/docker/reference"
@@ -19,14 +18,11 @@ import (
 	"github.com/containers/image/v5/signature"
 	"github.com/containers/image/v5/transports"
 	"github.com/containers/image/v5/transports/alltransports"
-	"github.com/containers/image/v5/types"
-	"github.com/containers/podman/v3/libpod/define"
-	"github.com/containers/podman/v3/libpod/image"
 	"github.com/containers/podman/v3/pkg/domain/entities"
 	"github.com/containers/podman/v3/pkg/domain/entities/reports"
 	domainUtils "github.com/containers/podman/v3/pkg/domain/utils"
+	"github.com/containers/podman/v3/pkg/errorhandling"
 	"github.com/containers/podman/v3/pkg/rootless"
-	"github.com/containers/podman/v3/pkg/util"
 	"github.com/containers/storage"
 	dockerRef "github.com/docker/distribution/reference"
 	"github.com/opencontainers/go-digest"
@@ -36,31 +32,84 @@ import (
 )
 
 func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
-	_, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+	exists, err := ir.Libpod.LibimageRuntime().Exists(nameOrID)
 	if err != nil {
-		if errors.Cause(err) == define.ErrMultipleImages {
-			return &entities.BoolReport{Value: true}, nil
-		}
-		if errors.Cause(err) != define.ErrNoSuchImage {
-			return nil, err
-		}
+		return nil, err
 	}
-	return &entities.BoolReport{Value: err == nil}, nil
+	return &entities.BoolReport{Value: exists}, nil
 }
 
 func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
-	reports, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
-	if err != nil {
-		return nil, err
+	// NOTE: the terms "dangling" and "intermediate" are not used
+	// consistently across our code base.  In libimage, "dangling" means
+	// that an image has no tags.  "intermediate" means that an image is
+	// dangling and that no other image depends on it (i.e., has no
+	// children).
+	//
+	// While pruning usually refers to "dangling" images, it has always
+	// removed "intermediate" ones.
+	defaultOptions := &libimage.RemoveImagesOptions{
+		Filters:  append(opts.Filter, "intermediate=true", "containers=false", "readonly=false"),
+		WithSize: true,
+	}
+
+	// `image prune --all` means to *also* remove images which are not in
+	// use by any container.  Since image filters are chained, we need to
+	// do two look ups since the default ones are a subset of all.
+	unusedOptions := &libimage.RemoveImagesOptions{
+		Filters:  append(opts.Filter, "containers=false", "readonly=false"),
+		WithSize: true,
+	}
+
+	var pruneReports []*reports.PruneReport
+
+	// Now prune all images until we converge.
+	numPreviouslyRemovedImages := 1
+	for {
+		removedDefault, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, nil, defaultOptions)
+		if rmErrors != nil {
+			return nil, errorhandling.JoinErrors(rmErrors)
+		}
+		removedUnused, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, nil, unusedOptions)
+		if rmErrors != nil {
+			return nil, errorhandling.JoinErrors(rmErrors)
+		}
+
+		for _, rmReport := range append(removedDefault, removedUnused...) {
+			r := *rmReport
+			pruneReports = append(pruneReports, &reports.PruneReport{
+				Id:   r.ID,
+				Size: uint64(r.Size),
+			})
+		}
+
+		numRemovedImages := len(removedDefault) + len(removedUnused)
+		if numRemovedImages+numPreviouslyRemovedImages == 0 {
+			break
+		}
+		numPreviouslyRemovedImages = numRemovedImages
 	}
-	return reports, err
+
+	return pruneReports, nil
+}
+
+func toDomainHistoryLayer(layer *libimage.ImageHistory) entities.ImageHistoryLayer {
+	l := entities.ImageHistoryLayer{}
+	l.ID = layer.ID
+	l.Created = *layer.Created
+	l.CreatedBy = layer.CreatedBy
+	copy(l.Tags, layer.Tags)
+	l.Size = layer.Size
+	l.Comment = layer.Comment
+	return l
 }
 
 func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
-	image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+	image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
 	if err != nil {
 		return nil, err
 	}
+
 	results, err := image.History(ctx)
 	if err != nil {
 		return nil, err
@@ -70,17 +119,17 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti
 		Layers: make([]entities.ImageHistoryLayer, len(results)),
 	}
 
-	for i, layer := range results {
-		history.Layers[i] = ToDomainHistoryLayer(layer)
+	for i := range results {
+		history.Layers[i] = toDomainHistoryLayer(&results[i])
 	}
 	return &history, nil
 }
 
 func (ir *ImageEngine) Mount(ctx context.Context, nameOrIDs []string, opts entities.ImageMountOptions) ([]*entities.ImageMountReport, error) {
-	var (
-		images []*image.Image
-		err    error
-	)
+	if opts.All && len(nameOrIDs) > 0 {
+		return nil, errors.Errorf("cannot mix --all with images")
+	}
+
 	if os.Geteuid() != 0 {
 		if driver := ir.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
 			// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
@@ -96,219 +145,129 @@ func (ir *ImageEngine) Mount(ctx context.Context, nameOrIDs []string, opts entit
 			os.Exit(ret)
 		}
 	}
+
+	listImagesOptions := &libimage.ListImagesOptions{}
 	if opts.All {
-		allImages, err := ir.Libpod.ImageRuntime().GetImages()
-		if err != nil {
-			return nil, err
-		}
-		for _, img := range allImages {
-			if !img.IsReadOnly() {
-				images = append(images, img)
-			}
-		}
-	} else {
-		for _, i := range nameOrIDs {
-			img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
-			if err != nil {
-				return nil, err
-			}
-			images = append(images, img)
-		}
+		listImagesOptions.Filters = []string{"readonly=false"}
 	}
-	reports := make([]*entities.ImageMountReport, 0, len(images))
-	for _, img := range images {
-		report := entities.ImageMountReport{Id: img.ID()}
-		if img.IsReadOnly() {
-			report.Err = errors.Errorf("mounting readonly %s image not supported", img.ID())
-		} else {
-			report.Path, report.Err = img.Mount([]string{}, "")
-		}
-		reports = append(reports, &report)
-	}
-	if len(reports) > 0 {
-		return reports, nil
-	}
-
-	images, err = ir.Libpod.ImageRuntime().GetImages()
+	images, err := ir.Libpod.LibimageRuntime().ListImages(ctx, nameOrIDs, listImagesOptions)
 	if err != nil {
 		return nil, err
 	}
+
+	mountReports := []*entities.ImageMountReport{}
+	listMountsOnly := !opts.All && len(nameOrIDs) == 0
 	for _, i := range images {
-		mounted, path, err := i.Mounted()
-		if err != nil {
-			if errors.Cause(err) == storage.ErrLayerUnknown {
-				continue
-			}
-			return nil, err
-		}
-		if mounted {
-			tags, err := i.RepoTags()
+		// TODO: the .Err fields are not used. This pre-dates the
+		// libimage migration but should be addressed at some point.
+		// A quick glimpse at cmd/podman/image/mount.go suggests that
+		// the errors needed to be handled there as well.
+		var mountPoint string
+		var err error
+		if listMountsOnly {
+			// We're only looking for mounted images.
+			mountPoint, err = i.Mountpoint()
 			if err != nil {
 				return nil, err
 			}
-			reports = append(reports, &entities.ImageMountReport{
-				Id:           i.ID(),
-				Name:         string(i.Digest()),
-				Repositories: tags,
-				Path:         path,
-			})
-		}
-	}
-	return reports, nil
-}
-
-func (ir *ImageEngine) Unmount(ctx context.Context, nameOrIDs []string, options entities.ImageUnmountOptions) ([]*entities.ImageUnmountReport, error) {
-	var images []*image.Image
-
-	if options.All {
-		allImages, err := ir.Libpod.ImageRuntime().GetImages()
-		if err != nil {
-			return nil, err
-		}
-		for _, img := range allImages {
-			if !img.IsReadOnly() {
-				images = append(images, img)
+			// Not mounted, so skip.
+			if mountPoint == "" {
+				continue
 			}
-		}
-	} else {
-		for _, i := range nameOrIDs {
-			img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
+		} else {
+			mountPoint, err = i.Mount(ctx, nil, "")
 			if err != nil {
 				return nil, err
 			}
-			images = append(images, img)
 		}
-	}
 
-	reports := []*entities.ImageUnmountReport{}
-	for _, img := range images {
-		report := entities.ImageUnmountReport{Id: img.ID()}
-		mounted, _, err := img.Mounted()
+		tags, err := i.RepoTags()
 		if err != nil {
-			// Errors will be caught in Unmount call below
-			// Default assumption to mounted
-			mounted = true
-		}
-		if !mounted {
-			continue
-		}
-		if err := img.Unmount(options.Force); err != nil {
-			if options.All && errors.Cause(err) == storage.ErrLayerNotMounted {
-				logrus.Debugf("Error umounting image %s, storage.ErrLayerNotMounted", img.ID())
-				continue
-			}
-			report.Err = errors.Wrapf(err, "error unmounting image %s", img.ID())
+			return nil, err
 		}
-		reports = append(reports, &report)
+		mountReports = append(mountReports, &entities.ImageMountReport{
+			Id:           i.ID(),
+			Name:         string(i.Digest()),
+			Repositories: tags,
+			Path:         mountPoint,
+		})
 	}
-	return reports, nil
+	return mountReports, nil
 }
 
-func ToDomainHistoryLayer(layer *image.History) entities.ImageHistoryLayer {
-	l := entities.ImageHistoryLayer{}
-	l.ID = layer.ID
-	l.Created = *layer.Created
-	l.CreatedBy = layer.CreatedBy
-	copy(l.Tags, layer.Tags)
-	l.Size = layer.Size
-	l.Comment = layer.Comment
-	return l
-}
-
-func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options entities.ImagePullOptions, label *string) (*entities.ImagePullReport, error) {
-	var writer io.Writer
-	if !options.Quiet {
-		writer = os.Stderr
-	}
-
-	dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
-	imageRef, err := alltransports.ParseImageName(rawImage)
-	if err != nil {
-		imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, rawImage))
-		if err != nil {
-			return nil, errors.Wrapf(err, "invalid image reference %q", rawImage)
-		}
+func (ir *ImageEngine) Unmount(ctx context.Context, nameOrIDs []string, options entities.ImageUnmountOptions) ([]*entities.ImageUnmountReport, error) {
+	if options.All && len(nameOrIDs) > 0 {
+		return nil, errors.Errorf("cannot mix --all with images")
 	}
 
-	var registryCreds *types.DockerAuthConfig
-	if len(options.Username) > 0 && len(options.Password) > 0 {
-		registryCreds = &types.DockerAuthConfig{
-			Username: options.Username,
-			Password: options.Password,
-		}
+	listImagesOptions := &libimage.ListImagesOptions{}
+	if options.All {
+		listImagesOptions.Filters = []string{"readonly=false"}
 	}
-	dockerRegistryOptions := image.DockerRegistryOptions{
-		DockerRegistryCreds:         registryCreds,
-		DockerCertPath:              options.CertDir,
-		OSChoice:                    options.OS,
-		ArchitectureChoice:          options.Arch,
-		VariantChoice:               options.Variant,
-		DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
+	images, err := ir.Libpod.LibimageRuntime().ListImages(ctx, nameOrIDs, listImagesOptions)
+	if err != nil {
+		return nil, err
 	}
 
-	if !options.AllTags {
-		newImage, err := runtime.New(ctx, rawImage, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, label, options.PullPolicy, nil)
+	unmountReports := []*entities.ImageUnmountReport{}
+	for _, image := range images {
+		r := &entities.ImageUnmountReport{Id: image.ID()}
+		mountPoint, err := image.Mountpoint()
 		if err != nil {
-			return nil, err
+			r.Err = err
+			unmountReports = append(unmountReports, r)
+			continue
 		}
-		return &entities.ImagePullReport{Images: []string{newImage.ID()}}, nil
-	}
-
-	// --all-tags requires the docker transport
-	if imageRef.Transport().Name() != docker.Transport.Name() {
-		return nil, errors.New("--all-tags requires docker transport")
+		if mountPoint == "" {
+			// Skip if the image wasn't mounted.
+			continue
+		}
+		r.Err = image.Unmount(options.Force)
+		unmountReports = append(unmountReports, r)
 	}
+	return unmountReports, nil
+}
 
-	// Trim the docker-transport prefix.
-	rawImage = strings.TrimPrefix(rawImage, docker.Transport.Name())
+func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
+	pullOptions := &libimage.PullOptions{AllTags: options.AllTags}
+	pullOptions.AuthFilePath = options.Authfile
+	pullOptions.CertDirPath = options.CertDir
+	pullOptions.Username = options.Username
+	pullOptions.Password = options.Password
+	pullOptions.Architecture = options.Arch
+	pullOptions.OS = options.OS
+	pullOptions.Variant = options.Variant
+	pullOptions.SignaturePolicyPath = options.SignaturePolicy
+	pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
 
-	// all-tags doesn't work with a tagged reference, so let's check early
-	namedRef, err := reference.Parse(rawImage)
-	if err != nil {
-		return nil, errors.Wrapf(err, "error parsing %q", rawImage)
-	}
-	if _, isTagged := namedRef.(reference.Tagged); isTagged {
-		return nil, errors.New("--all-tags requires a reference without a tag")
+	if !options.Quiet {
+		pullOptions.Writer = os.Stderr
 	}
 
-	systemContext := image.GetSystemContext("", options.Authfile, false)
-	tags, err := docker.GetRepositoryTags(ctx, systemContext, imageRef)
+	pulledImages, err := ir.Libpod.LibimageRuntime().Pull(ctx, rawImage, options.PullPolicy, pullOptions)
 	if err != nil {
-		return nil, errors.Wrapf(err, "error getting repository tags")
+		return nil, err
 	}
 
-	foundIDs := []string{}
-	for _, tag := range tags {
-		name := rawImage + ":" + tag
-		newImage, err := runtime.New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways, nil)
-		if err != nil {
-			logrus.Errorf("error pulling image %q", name)
-			continue
-		}
-		foundIDs = append(foundIDs, newImage.ID())
+	pulledIDs := make([]string, len(pulledImages))
+	for i := range pulledImages {
+		pulledIDs[i] = pulledImages[i].ID()
 	}
 
-	if len(tags) != len(foundIDs) {
-		return nil, err
-	}
-	return &entities.ImagePullReport{Images: foundIDs}, nil
-}
-
-func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
-	return pull(ctx, ir.Libpod.ImageRuntime(), rawImage, options, nil)
+	return &entities.ImagePullReport{Images: pulledIDs}, nil
 }
 
 func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
 	reports := []*entities.ImageInspectReport{}
 	errs := []error{}
 	for _, i := range namesOrIDs {
-		img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
+		img, _, err := ir.Libpod.LibimageRuntime().LookupImage(i, &libimage.LookupImageOptions{IgnorePlatform: true})
 		if err != nil {
 			// This is probably a no such image, treat as nonfatal.
 			errs = append(errs, err)
 			continue
 		}
-		result, err := img.Inspect(ctx)
+		result, err := img.Inspect(ctx, true)
 		if err != nil {
 			// This is more likely to be fatal.
 			return nil, nil, err
@@ -323,11 +282,6 @@ func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts en
 }
 
 func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
-	var writer io.Writer
-	if !options.Quiet {
-		writer = os.Stderr
-	}
-
 	var manifestType string
 	switch options.Format {
 	case "":
@@ -342,58 +296,56 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
 		return errors.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", options.Format)
 	}
 
-	var registryCreds *types.DockerAuthConfig
-	if len(options.Username) > 0 && len(options.Password) > 0 {
-		registryCreds = &types.DockerAuthConfig{
-			Username: options.Username,
-			Password: options.Password,
-		}
-	}
-	dockerRegistryOptions := image.DockerRegistryOptions{
-		DockerRegistryCreds:         registryCreds,
-		DockerCertPath:              options.CertDir,
-		DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
-	}
+	pushOptions := &libimage.PushOptions{}
+	pushOptions.AuthFilePath = options.Authfile
+	pushOptions.CertDirPath = options.CertDir
+	pushOptions.DirForceCompress = options.Compress
+	pushOptions.Username = options.Username
+	pushOptions.Password = options.Password
+	pushOptions.ManifestMIMEType = manifestType
+	pushOptions.RemoveSignatures = options.RemoveSignatures
+	pushOptions.SignBy = options.SignBy
+	pushOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
 
-	signOptions := image.SigningOptions{
-		RemoveSignatures: options.RemoveSignatures,
-		SignBy:           options.SignBy,
+	if !options.Quiet {
+		pushOptions.Writer = os.Stderr
 	}
 
-	newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(source)
-	if err != nil {
-		return err
-	}
+	pushedManifestBytes, pushError := ir.Libpod.LibimageRuntime().Push(ctx, source, destination, pushOptions)
+	if pushError == nil {
+		if options.DigestFile != "" {
+			manifestDigest, err := manifest.Digest(pushedManifestBytes)
+			if err != nil {
+				return err
+			}
 
-	err = newImage.PushImageToHeuristicDestination(
-		ctx,
-		destination,
-		manifestType,
-		options.Authfile,
-		options.DigestFile,
-		options.SignaturePolicy,
-		writer,
-		options.Compress,
-		signOptions,
-		&dockerRegistryOptions,
-		nil,
-		options.Progress)
-	if err != nil && errors.Cause(err) != storage.ErrImageUnknown {
+			if err := ioutil.WriteFile(options.DigestFile, []byte(manifestDigest.String()), 0644); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+	// If the image could not be found, we may be referring to a manifest
+	// list but could not find a matching image instance in the local
+	// containers storage. In that case, fall back and attempt to push the
+	// (entire) manifest.
+	if errors.Cause(pushError) == storage.ErrImageUnknown {
 		// Image might be a manifest list so attempt a manifest push
-		if _, manifestErr := ir.ManifestPush(ctx, source, destination, options); manifestErr == nil {
+		_, manifestErr := ir.ManifestPush(ctx, source, destination, options)
+		if manifestErr == nil {
 			return nil
 		}
 	}
-	return err
+	return pushError
 }
 
 func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
-	newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+	image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
 	if err != nil {
 		return err
 	}
 	for _, tag := range tags {
-		if err := newImage.TagImage(tag); err != nil {
+		if err := image.Tag(tag); err != nil {
 			return err
 		}
 	}
@@ -401,54 +353,71 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string,
 }
 
 func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error {
-	newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+	image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
 	if err != nil {
 		return err
 	}
 	// If only one arg is provided, all names are to be untagged
 	if len(tags) == 0 {
-		tags = newImage.Names()
+		tags = image.Names()
 	}
 	for _, tag := range tags {
-		if err := newImage.UntagImage(tag); err != nil {
+		if err := image.Untag(tag); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
-func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) (*entities.ImageLoadReport, error) {
-	var (
-		writer io.Writer
-	)
-	if !opts.Quiet {
-		writer = os.Stderr
-	}
-	name, err := ir.Libpod.LoadImage(ctx, opts.Input, writer, opts.SignaturePolicy)
-	if err != nil {
-		return nil, err
+func (ir *ImageEngine) Load(ctx context.Context, options entities.ImageLoadOptions) (*entities.ImageLoadReport, error) {
+	loadOptions := &libimage.LoadOptions{}
+	loadOptions.SignaturePolicyPath = options.SignaturePolicy
+	if !options.Quiet {
+		loadOptions.Writer = os.Stderr
 	}
-	return &entities.ImageLoadReport{Names: strings.Split(name, ",")}, nil
-}
 
-func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) {
-	id, err := ir.Libpod.Import(ctx, opts.Source, opts.Reference, opts.SignaturePolicy, opts.Changes, opts.Message, opts.Quiet)
+	loadedImages, err := ir.Libpod.LibimageRuntime().Load(ctx, options.Input, loadOptions)
 	if err != nil {
 		return nil, err
 	}
-	return &entities.ImageImportReport{Id: id}, nil
+	return &entities.ImageLoadReport{Names: loadedImages}, nil
 }
 
 func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
+	saveOptions := &libimage.SaveOptions{}
+	saveOptions.DirForceCompress = options.Compress
+	saveOptions.RemoveSignatures = options.RemoveSignatures
+
+	if !options.Quiet {
+		saveOptions.Writer = os.Stderr
+	}
+
+	names := []string{nameOrID}
 	if options.MultiImageArchive {
-		nameOrIDs := append([]string{nameOrID}, tags...)
-		return ir.Libpod.ImageRuntime().SaveImages(ctx, nameOrIDs, options.Format, options.Output, options.Quiet, true)
+		names = append(names, tags...)
+	} else {
+		saveOptions.AdditionalTags = tags
 	}
-	newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+	return ir.Libpod.LibimageRuntime().Save(ctx, names, options.Format, options.Output, saveOptions)
+}
+
+func (ir *ImageEngine) Import(ctx context.Context, options entities.ImageImportOptions) (*entities.ImageImportReport, error) {
+	importOptions := &libimage.ImportOptions{}
+	importOptions.Changes = options.Changes
+	importOptions.CommitMessage = options.Message
+	importOptions.Tag = options.Reference
+	importOptions.SignaturePolicyPath = options.SignaturePolicy
+
+	if !options.Quiet {
+		importOptions.Writer = os.Stderr
+	}
+
+	imageID, err := ir.Libpod.LibimageRuntime().Import(ctx, options.Source, importOptions)
 	if err != nil {
-		return err
+		return nil, err
 	}
-	return newImage.Save(ctx, nameOrID, options.Format, options.Output, tags, options.Quiet, options.Compress, true)
+
+	return &entities.ImageImportReport{Id: imageID}, nil
 }
 
 func (ir *ImageEngine) Diff(_ context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
@@ -460,12 +429,12 @@ func (ir *ImageEngine) Diff(_ context.Context, nameOrID string, _ entities.DiffO
 }
 
 func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
-	filter, err := image.ParseSearchFilter(opts.Filters)
+	filter, err := libimage.ParseSearchFilter(opts.Filters)
 	if err != nil {
 		return nil, err
 	}
 
-	searchOpts := image.SearchOptions{
+	searchOptions := &libimage.SearchOptions{
 		Authfile:              opts.Authfile,
 		Filter:                *filter,
 		Limit:                 opts.Limit,
@@ -474,7 +443,7 @@ func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.Im
 		ListTags:              opts.ListTags,
 	}
 
-	searchResults, err := image.SearchImages(term, searchOpts)
+	searchResults, err := ir.Libpod.LibimageRuntime().Search(ctx, term, searchOptions)
 	if err != nil {
 		return nil, err
 	}
@@ -510,15 +479,15 @@ func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts
 }
 
 func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
-	img, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+	image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
 	if err != nil {
 		return nil, err
 	}
-	results, err := img.GenerateTree(opts.WhatRequires)
+	tree, err := image.Tree(opts.WhatRequires)
 	if err != nil {
 		return nil, err
 	}
-	return &entities.ImageTreeReport{Tree: results}, nil
+	return &entities.ImageTreeReport{Tree: tree}, nil
 }
 
 // removeErrorsToExitCode returns an exit code for the specified slice of
@@ -542,9 +511,9 @@ func removeErrorsToExitCode(rmErrors []error) int {
 
 	for _, e := range rmErrors {
 		switch errors.Cause(e) {
-		case define.ErrNoSuchImage:
+		case storage.ErrImageUnknown, storage.ErrLayerUnknown:
 			noSuchImageErrors = true
-		case define.ErrImageInUse, storage.ErrImageUsedByContainer:
+		case storage.ErrImageUsedByContainer:
 			inUseErrors = true
 		default:
 			otherErrors = true
@@ -574,84 +543,25 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie
 		report.ExitCode = removeErrorsToExitCode(rmErrors)
 	}()
 
-	// deleteImage is an anonymous function to conveniently delete an image
-	// without having to pass all local data around.
-	deleteImage := func(img *image.Image) error {
-		results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force)
-		switch errors.Cause(err) {
-		case nil:
-			// Removal worked, so let's report it.
-			report.Deleted = append(report.Deleted, results.Deleted)
-			report.Untagged = append(report.Untagged, results.Untagged...)
-			return nil
-		case storage.ErrImageUnknown, storage.ErrLayerUnknown:
-			// The image must have been removed already (see #6510)
-			// or the storage is corrupted (see #9617).
-			report.Deleted = append(report.Deleted, img.ID())
-			report.Untagged = append(report.Untagged, img.ID())
-			return nil
-		default:
-			// Fatal error.
-			return err
-		}
+	libimageOptions := &libimage.RemoveImagesOptions{}
+	libimageOptions.Filters = []string{"readonly=false"}
+	libimageOptions.Force = opts.Force
+	if !opts.All {
+		libimageOptions.Filters = append(libimageOptions.Filters, "intermediate=false")
 	}
+	libimageOptions.RemoveContainerFunc = ir.Libpod.RemoveContainersForImageCallback(ctx)
 
-	// Delete all images from the local storage.
-	if opts.All {
-		previousImages := 0
-		// Remove all images one-by-one.
-		for {
-			storageImages, err := ir.Libpod.ImageRuntime().GetRWImages()
-			if err != nil {
-				rmErrors = append(rmErrors, err)
-				return
-			}
-			// No images (left) to remove, so we're done.
-			if len(storageImages) == 0 {
-				return
-			}
-			// Prevent infinity loops by making a delete-progress check.
-			if previousImages == len(storageImages) {
-				rmErrors = append(rmErrors, errors.New("unable to delete all images, check errors and re-run image removal if needed"))
-				break
-			}
-			previousImages = len(storageImages)
-			// Delete all "leaves" (i.e., images without child images).
-			for _, img := range storageImages {
-				isParent, err := img.IsParent(ctx)
-				if err != nil {
-					logrus.Warnf("%v, ignoring the error", err)
-					isParent = false
-				}
-				// Skip parent images.
-				if isParent {
-					continue
-				}
-				if err := deleteImage(img); err != nil {
-					rmErrors = append(rmErrors, err)
-				}
-			}
-		}
-
-		return
-	}
+	libimageReport, libimageErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, images, libimageOptions)
 
-	// Delete only the specified images.
-	for _, id := range images {
-		img, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
-		if err != nil {
-			// attempt to remove image from storage
-			if forceErr := ir.Libpod.RemoveImageFromStorage(id); forceErr == nil {
-				continue
-			}
-			rmErrors = append(rmErrors, err)
-			continue
-		}
-		err = deleteImage(img)
-		if err != nil {
-			rmErrors = append(rmErrors, err)
+	for _, r := range libimageReport {
+		if r.Removed {
+			report.Deleted = append(report.Deleted, r.ID)
 		}
+		report.Untagged = append(report.Untagged, r.Untagged...)
 	}
+
+	rmErrors = libimageErrors
+
 	return //nolint
 }
 
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index 3b8aabeb7..b0e947991 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -3,23 +3,25 @@ package abi
 import (
 	"context"
 
-	libpodImage "github.com/containers/podman/v3/libpod/image"
+	"github.com/containers/common/libimage"
 	"github.com/containers/podman/v3/pkg/domain/entities"
 	"github.com/pkg/errors"
 )
 
 func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
-	images, err := ir.Libpod.ImageRuntime().GetImagesWithFilters(opts.Filter)
-	if err != nil {
-		return nil, err
+	listImagesOptions := &libimage.ListImagesOptions{
+		Filters: opts.Filter,
 	}
-
 	if !opts.All {
-		filter, err := ir.Libpod.ImageRuntime().IntermediateFilter(ctx, images)
-		if err != nil {
-			return nil, err
-		}
-		images = libpodImage.FilterImages(images, []libpodImage.ResultFilter{filter})
+		// Filter intermediate images unless we want to list *all*.
+		// NOTE: it's a positive filter, so `intermediate=false` means
+		// to display non-intermediate images.
+		listImagesOptions.Filters = append(listImagesOptions.Filters, "intermediate=false")
+	}
+
+	images, err := ir.Libpod.LibimageRuntime().ListImages(ctx, nil, listImagesOptions)
+	if err != nil {
+		return nil, err
 	}
 
 	summaries := []*entities.ImageSummary{}
@@ -30,24 +32,21 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
 		}
 
 		e := entities.ImageSummary{
-			ID:           img.ID(),
-			ConfigDigest: string(img.ConfigDigest),
-			Created:      img.Created().Unix(),
-			Dangling:     img.Dangling(),
-			Digest:       string(img.Digest()),
-			RepoDigests:  digests,
-			History:      img.NamesHistory(),
-			Names:        img.Names(),
-			ReadOnly:     img.IsReadOnly(),
-			SharedSize:   0,
-			RepoTags:     img.Names(), // may include tags and digests
+			ID: img.ID(),
+			//			ConfigDigest: string(img.ConfigDigest),
+			Created:     img.Created().Unix(),
+			Dangling:    img.IsDangling(),
+			Digest:      string(img.Digest()),
+			RepoDigests: digests,
+			History:     img.NamesHistory(),
+			Names:       img.Names(),
+			ReadOnly:    img.IsReadOnly(),
+			SharedSize:  0,
+			RepoTags:    img.Names(), // may include tags and digests
 		}
 		e.Labels, err = img.Labels(ctx)
 		if err != nil {
-			// Ignore empty manifest lists.
-			if errors.Cause(err) != libpodImage.ErrImageIsBareList {
-				return nil, errors.Wrapf(err, "error retrieving label for image %q: you may need to remove the image to resolve the error", img.ID())
-			}
+			return nil, errors.Wrapf(err, "error retrieving label for image %q: you may need to remove the image to resolve the error", img.ID())
 		}
 
 		ctnrs, err := img.Containers()
@@ -56,20 +55,22 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
 		}
 		e.Containers = len(ctnrs)
 
-		sz, err := img.Size(ctx)
+		sz, err := img.Size()
 		if err != nil {
 			return nil, errors.Wrapf(err, "error retrieving size of image %q: you may need to remove the image to resolve the error", img.ID())
 		}
-		e.Size = int64(*sz)
+		e.Size = sz
 		// This is good enough for now, but has to be
 		// replaced later with correct calculation logic
-		e.VirtualSize = int64(*sz)
+		e.VirtualSize = sz
 
-		parent, err := img.ParentID(ctx)
+		parent, err := img.Parent(ctx)
 		if err != nil {
 			return nil, errors.Wrapf(err, "error retrieving parent of image %q: you may need to remove the image to resolve the error", img.ID())
 		}
-		e.ParentId = parent
+		if parent != nil {
+			e.ParentId = parent.ID()
+		}
 
 		summaries = append(summaries, &e)
 	}
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 8e3c50fac..f932cf21d 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -4,21 +4,17 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"os"
 	"strings"
 
-	"github.com/containers/buildah/manifests"
-	buildahManifests "github.com/containers/buildah/pkg/manifests"
-	buildahUtil "github.com/containers/buildah/util"
+	"github.com/containers/common/libimage"
 	cp "github.com/containers/image/v5/copy"
-	"github.com/containers/image/v5/docker"
 	"github.com/containers/image/v5/manifest"
+	"github.com/containers/image/v5/pkg/shortnames"
 	"github.com/containers/image/v5/transports"
 	"github.com/containers/image/v5/transports/alltransports"
-	"github.com/containers/image/v5/types"
-	libpodImage "github.com/containers/podman/v3/libpod/image"
 	"github.com/containers/podman/v3/pkg/domain/entities"
+	"github.com/containers/storage"
 	"github.com/opencontainers/go-digest"
 	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
@@ -26,51 +22,103 @@ import (
 )
 
 // ManifestCreate implements logic for creating manifest lists via ImageEngine
-func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []string, opts entities.ManifestCreateOptions) (string, error) {
-	fullNames, err := buildahUtil.ExpandNames(names, "", ir.Libpod.SystemContext(), ir.Libpod.GetStore())
-	if err != nil {
-		return "", errors.Wrapf(err, "error encountered while expanding image name %q", names)
+func (ir *ImageEngine) ManifestCreate(ctx context.Context, names []string, images []string, opts entities.ManifestCreateOptions) (string, error) {
+	// FIXME: change the interface of manifest create `names []string` ->
+	// `name string`.
+	if len(names) == 0 {
+		return "", errors.New("no name specified for creating a manifest list")
 	}
-	imageID, err := libpodImage.CreateManifestList(ir.Libpod.ImageRuntime(), *ir.Libpod.SystemContext(), fullNames, images, opts.All)
+	name := names[0]
+
+	manifestList, err := ir.Libpod.LibimageRuntime().CreateManifestList(name)
 	if err != nil {
-		return imageID, err
+		return "", err
 	}
-	return imageID, err
+
+	addOptions := &libimage.ManifestListAddOptions{All: opts.All}
+	for _, image := range images {
+		if _, err := manifestList.Add(ctx, image, addOptions); err != nil {
+			return "", err
+		}
+	}
+
+	return manifestList.ID(), nil
 }
 
 // ManifestExists checks if a manifest list with the given name exists in local storage
 func (ir *ImageEngine) ManifestExists(ctx context.Context, name string) (*entities.BoolReport, error) {
-	if image, err := ir.Libpod.ImageRuntime().NewFromLocal(name); err == nil {
-		exists, err := image.ExistsManifest()
-		if err != nil && errors.Cause(err) != buildahManifests.ErrManifestTypeNotSupported {
-			return nil, err
+	image, _, err := ir.Libpod.LibimageRuntime().LookupImage(name, &libimage.LookupImageOptions{IgnorePlatform: true})
+	if err != nil {
+		if errors.Cause(err) == storage.ErrImageUnknown {
+			return &entities.BoolReport{Value: false}, nil
 		}
-		return &entities.BoolReport{Value: exists}, nil
+		return nil, err
+	}
+
+	isManifestList, err := image.IsManifestList(ctx)
+	if err != nil {
+		return nil, err
 	}
-	return &entities.BoolReport{Value: false}, nil
+	return &entities.BoolReport{Value: isManifestList}, nil
 }
 
 // ManifestInspect returns the content of a manifest list or image
 func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) {
-	if newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name); err == nil {
-		// return the manifest in local storage
-		if list, err := newImage.InspectManifest(); err == nil {
-			buf, err := json.MarshalIndent(list, "", "    ")
-			if err != nil {
-				return buf, errors.Wrapf(err, "error rendering manifest %s for display", name)
-			}
-			return buf, nil
-			// no return if local image is not a list of images type
-			// continue on getting valid manifest through remote service
-		} else if errors.Cause(err) != buildahManifests.ErrManifestTypeNotSupported {
-			return nil, errors.Wrapf(err, "loading manifest %q", name)
+	// NOTE: we have to do a bit of a limbo here as `podman manifest
+	// inspect foo` wants to do a remote-inspect of foo iff "foo" in the
+	// containers storage is an ordinary image but not a manifest list.
+
+	lookupOptions := &libimage.LookupImageOptions{IgnorePlatform: true}
+	image, _, err := ir.Libpod.LibimageRuntime().LookupImage(name, lookupOptions)
+	if err != nil {
+		// If the image doesn't exist, do a remote inspect.
+		if errors.Cause(err) == storage.ErrImageUnknown {
+			return ir.remoteManifestInspect(ctx, name)
 		}
+		return nil, err
+	}
+
+	isManifestList, err := image.IsManifestList(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	// If the image isn't a manifest list, do a remote inspect.
+	if !isManifestList {
+		return ir.remoteManifestInspect(ctx, name)
 	}
-	sc := ir.Libpod.SystemContext()
-	refs, err := buildahUtil.ResolveNameToReferences(ir.Libpod.GetStore(), sc, name)
+
+	manifestList, err := image.ToManifestList()
 	if err != nil {
 		return nil, err
 	}
+
+	schema2List, err := manifestList.Inspect()
+	if err != nil {
+		return nil, err
+	}
+
+	rawSchema2List, err := json.Marshal(schema2List)
+	if err != nil {
+		return nil, err
+	}
+
+	var b bytes.Buffer
+	if err := json.Indent(&b, rawSchema2List, "", "    "); err != nil {
+		return nil, errors.Wrapf(err, "error rendering manifest %s for display", name)
+	}
+	return b.Bytes(), nil
+}
+
+// inspect a remote manifest list.
+func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string) ([]byte, error) {
+	sys := ir.Libpod.SystemContext()
+
+	resolved, err := shortnames.Resolve(sys, name)
+	if err != nil {
+		return nil, err
+	}
+
 	var (
 		latestErr error
 		result    []byte
@@ -84,8 +132,13 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
 			latestErr = errors.Wrapf(latestErr, "tried %v\n", e)
 		}
 	}
-	for _, ref := range refs {
-		src, err := ref.NewImageSource(ctx, sc)
+
+	for _, candidate := range resolved.PullCandidates {
+		ref, err := alltransports.ParseImageName("docker://" + candidate.Value.String())
+		if err != nil {
+			return nil, err
+		}
+		src, err := ref.NewImageSource(ctx, sys)
 		if err != nil {
 			appendErr(errors.Wrapf(err, "reading image %q", transports.ImageName(ref)))
 			continue
@@ -102,6 +155,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
 		manType = manifestType
 		break
 	}
+
 	if len(result) == 0 && latestErr != nil {
 		return nil, latestErr
 	}
@@ -138,29 +192,41 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
 
 // ManifestAdd adds images to the manifest list
 func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAddOptions) (string, error) {
-	imageSpec := opts.Images[0]
-	listImageSpec := opts.Images[1]
-	dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
-	_, err := alltransports.ParseImageName(imageSpec)
+	// FIXME: the name options below are *mandatory* arguments and should
+	// be reflected as such in the signature.
+
+	if len(opts.Images) < 2 {
+		return "", errors.New("manifest add requires two images")
+	}
+
+	imageName := opts.Images[0]
+	listName := opts.Images[1]
+
+	manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(listName)
 	if err != nil {
-		_, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, imageSpec))
-		if err != nil {
-			return "", errors.Errorf("invalid image reference %q", imageSpec)
-		}
+		return "", err
 	}
-	listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(listImageSpec)
+
+	addOptions := &libimage.ManifestListAddOptions{
+		All:                   opts.All,
+		AuthFilePath:          opts.Authfile,
+		CertDirPath:           opts.CertDir,
+		InsecureSkipTLSVerify: opts.SkipTLSVerify,
+		Username:              opts.Username,
+		Password:              opts.Password,
+	}
+
+	instanceDigest, err := manifestList.Add(ctx, imageName, addOptions)
 	if err != nil {
-		return "", errors.Wrapf(err, "error retrieving local image from image name %s", listImageSpec)
+		return "", err
 	}
 
-	manifestAddOpts := libpodImage.ManifestAddOpts{
-		All:       opts.All,
-		Arch:      opts.Arch,
-		Features:  opts.Features,
-		Images:    opts.Images,
-		OS:        opts.OS,
-		OSVersion: opts.OSVersion,
-		Variant:   opts.Variant,
+	annotateOptions := &libimage.ManifestListAnnotateOptions{
+		Architecture: opts.Arch,
+		Features:     opts.Features,
+		OS:           opts.OS,
+		OSVersion:    opts.OSVersion,
+		Variant:      opts.Variant,
 	}
 	if len(opts.Annotation) != 0 {
 		annotations := make(map[string]string)
@@ -171,51 +237,44 @@ func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAd
 			}
 			annotations[spec[0]] = spec[1]
 		}
-		manifestAddOpts.Annotation = annotations
-	}
-
-	// Set the system context.
-	sys := ir.Libpod.SystemContext()
-	if sys != nil {
-		sys = &types.SystemContext{}
+		annotateOptions.Annotations = annotations
 	}
-	sys.AuthFilePath = opts.Authfile
-	sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
-	sys.DockerCertPath = opts.CertDir
 
-	if opts.Username != "" && opts.Password != "" {
-		sys.DockerAuthConfig = &types.DockerAuthConfig{
-			Username: opts.Username,
-			Password: opts.Password,
-		}
+	if err := manifestList.AnnotateInstance(instanceDigest, annotateOptions); err != nil {
+		return "", err
 	}
 
-	listID, err := listImage.AddManifest(*sys, manifestAddOpts)
-	if err != nil {
-		return listID, err
-	}
-	return listID, nil
+	return manifestList.ID(), nil
 }
 
 // ManifestAnnotate updates an entry of the manifest list
 func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opts entities.ManifestAnnotateOptions) (string, error) {
-	listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
-	if err != nil {
-		return "", errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
+	// FIXME: the `names` are *mandatory* arguments and should be
+	// reflected as such in the signature.
+
+	if len(names) < 2 {
+		return "", errors.New("manifest annotate requires two names")
 	}
-	digest, err := digest.Parse(names[1])
+
+	listName := names[0]
+	instanceDigest, err := digest.Parse(names[1])
 	if err != nil {
 		return "", errors.Errorf(`invalid image digest "%s": %v`, names[1], err)
 	}
-	manifestAnnotateOpts := libpodImage.ManifestAnnotateOpts{
-		Arch:       opts.Arch,
-		Features:   opts.Features,
-		OS:         opts.OS,
-		OSFeatures: opts.OSFeatures,
-		OSVersion:  opts.OSVersion,
-		Variant:    opts.Variant,
+
+	manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(listName)
+	if err != nil {
+		return "", err
+	}
+
+	annotateOptions := &libimage.ManifestListAnnotateOptions{
+		Architecture: opts.Arch,
+		Features:     opts.Features,
+		OS:           opts.OS,
+		OSVersion:    opts.OSVersion,
+		Variant:      opts.Variant,
 	}
-	if len(opts.Annotation) > 0 {
+	if len(opts.Annotation) != 0 {
 		annotations := make(map[string]string)
 		for _, annotationSpec := range opts.Annotation {
 			spec := strings.SplitN(annotationSpec, "=", 2)
@@ -224,48 +283,49 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt
 			}
 			annotations[spec[0]] = spec[1]
 		}
-		manifestAnnotateOpts.Annotation = annotations
+		annotateOptions.Annotations = annotations
 	}
-	updatedListID, err := listImage.AnnotateManifest(*ir.Libpod.SystemContext(), digest, manifestAnnotateOpts)
-	if err == nil {
-		return fmt.Sprintf("%s: %s", updatedListID, digest.String()), nil
+
+	if err := manifestList.AnnotateInstance(instanceDigest, annotateOptions); err != nil {
+		return "", err
 	}
-	return "", err
+
+	return manifestList.ID(), nil
 }
 
 // ManifestRemove removes specified digest from the specified manifest list
 func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (string, error) {
+	// FIXME: the `names` are *mandatory* arguments and should be
+	// reflected as such in the signature.
+
+	if len(names) < 2 {
+		return "", errors.New("manifest remove requires two names")
+	}
+
+	listName := names[0]
 	instanceDigest, err := digest.Parse(names[1])
 	if err != nil {
 		return "", errors.Errorf(`invalid image digest "%s": %v`, names[1], err)
 	}
-	listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
+
+	manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(listName)
 	if err != nil {
-		return "", errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
+		return "", err
 	}
-	updatedListID, err := listImage.RemoveManifest(instanceDigest)
-	if err == nil {
-		return fmt.Sprintf("%s :%s\n", updatedListID, instanceDigest.String()), nil
+
+	if err := manifestList.RemoveInstance(instanceDigest); err != nil {
+		return "", err
 	}
-	return "", err
+
+	return manifestList.ID(), nil
 }
 
 // ManifestPush pushes a manifest list or image index to the destination
 func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination string, opts entities.ImagePushOptions) (string, error) {
-	listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name)
+	manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(name)
 	if err != nil {
 		return "", errors.Wrapf(err, "error retrieving local image from image name %s", name)
 	}
-	dest, err := alltransports.ParseImageName(destination)
-	if err != nil {
-		oldErr := err
-		// Try adding the images default transport
-		destination2 := libpodImage.DefaultTransport + destination
-		dest, err = alltransports.ParseImageName(destination2)
-		if err != nil {
-			return "", oldErr
-		}
-	}
 
 	var manifestType string
 	if opts.Format != "" {
@@ -279,40 +339,33 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin
 		}
 	}
 
-	// Set the system context.
-	sys := ir.Libpod.SystemContext()
-	if sys == nil {
-		sys = new(types.SystemContext)
-	}
-	sys.AuthFilePath = opts.Authfile
-	sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
-	sys.DockerCertPath = opts.CertDir
-
-	if opts.Username != "" && opts.Password != "" {
-		sys.DockerAuthConfig = &types.DockerAuthConfig{
-			Username: opts.Username,
-			Password: opts.Password,
-		}
-	}
+	pushOptions := &libimage.ManifestListPushOptions{}
+	pushOptions.AuthFilePath = opts.Authfile
+	pushOptions.CertDirPath = opts.CertDir
+	pushOptions.Username = opts.Username
+	pushOptions.Password = opts.Password
+	pushOptions.ImageListSelection = cp.CopySpecificImages
+	pushOptions.ManifestMIMEType = manifestType
+	pushOptions.RemoveSignatures = opts.RemoveSignatures
+	pushOptions.SignBy = opts.SignBy
 
-	options := manifests.PushOptions{
-		Store:              ir.Libpod.GetStore(),
-		SystemContext:      sys,
-		ImageListSelection: cp.CopySpecificImages,
-		Instances:          nil,
-		RemoveSignatures:   opts.RemoveSignatures,
-		SignBy:             opts.SignBy,
-		ManifestType:       manifestType,
-	}
 	if opts.All {
-		options.ImageListSelection = cp.CopyAllImages
+		pushOptions.ImageListSelection = cp.CopyAllImages
 	}
 	if !opts.Quiet {
-		options.ReportWriter = os.Stderr
+		pushOptions.Writer = os.Stderr
 	}
-	manDigest, err := listImage.PushManifest(dest, options)
-	if err == nil && opts.Rm {
-		_, err = ir.Libpod.GetStore().DeleteImage(listImage.ID(), true)
+
+	manDigest, err := manifestList.Push(ctx, destination, pushOptions)
+	if err != nil {
+		return "", err
+	}
+
+	if opts.Rm {
+		if _, err := ir.Libpod.GetStore().DeleteImage(manifestList.ID(), true); err != nil {
+			return "", errors.Wrap(err, "error removing manifest after push")
+		}
 	}
+
 	return manDigest.String(), err
 }
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 6ddd4a042..d235c9ed8 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -10,17 +10,17 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/config"
 	"github.com/containers/common/pkg/secrets"
 	"github.com/containers/image/v5/types"
 	"github.com/containers/podman/v3/libpod"
 	"github.com/containers/podman/v3/libpod/define"
-	"github.com/containers/podman/v3/libpod/image"
 	"github.com/containers/podman/v3/pkg/domain/entities"
 	"github.com/containers/podman/v3/pkg/specgen"
 	"github.com/containers/podman/v3/pkg/specgen/generate"
 	"github.com/containers/podman/v3/pkg/specgen/generate/kube"
 	"github.com/containers/podman/v3/pkg/util"
-	"github.com/docker/distribution/reference"
 	"github.com/ghodss/yaml"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -154,10 +154,9 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM
 
 func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions, ipIndex *int) (*entities.PlayKubeReport, error) {
 	var (
-		registryCreds *types.DockerAuthConfig
-		writer        io.Writer
-		playKubePod   entities.PlayKubePod
-		report        entities.PlayKubeReport
+		writer      io.Writer
+		playKubePod entities.PlayKubePod
+		report      entities.PlayKubeReport
 	)
 
 	// Create the secret manager before hand
@@ -220,19 +219,6 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
 		writer = os.Stderr
 	}
 
-	if len(options.Username) > 0 && len(options.Password) > 0 {
-		registryCreds = &types.DockerAuthConfig{
-			Username: options.Username,
-			Password: options.Password,
-		}
-	}
-
-	dockerRegistryOptions := image.DockerRegistryOptions{
-		DockerRegistryCreds:         registryCreds,
-		DockerCertPath:              options.CertDir,
-		DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
-	}
-
 	volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes)
 	if err != nil {
 		return nil, err
@@ -273,35 +259,36 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
 
 	containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
 	for _, container := range podYAML.Spec.Containers {
-		pullPolicy := util.PullImageMissing
+		// NOTE: set the pull policy to "newer".  This will cover cases
+		// where the "latest" tag requires a pull and will also
+		// transparently handle "localhost/" prefixed files which *may*
+		// refer to a locally built image OR an image running a
+		// registry on localhost.
+		pullPolicy := config.PullPolicyNewer
 		if len(container.ImagePullPolicy) > 0 {
-			pullPolicy, err = util.ValidatePullType(string(container.ImagePullPolicy))
+			pullPolicy, err = config.ParsePullPolicy(string(container.ImagePullPolicy))
 			if err != nil {
 				return nil, err
 			}
 		}
-		named, err := reference.ParseNormalizedNamed(container.Image)
-		if err != nil {
-			return nil, errors.Wrapf(err, "Failed to parse image %q", container.Image)
-		}
-		// In kube, if the image is tagged with latest, it should always pull
-		// but if the domain is localhost, that means the image was built locally
-		// so do not attempt a pull.
-		if tagged, isTagged := named.(reference.NamedTagged); isTagged {
-			if tagged.Tag() == image.LatestTag && reference.Domain(named) != image.DefaultLocalRegistry {
-				pullPolicy = util.PullImageAlways
-			}
-		}
-
 		// This ensures the image is the image store
-		newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy, nil)
+		pullOptions := &libimage.PullOptions{}
+		pullOptions.AuthFilePath = options.Authfile
+		pullOptions.CertDirPath = options.CertDir
+		pullOptions.SignaturePolicyPath = options.SignaturePolicy
+		pullOptions.Writer = writer
+		pullOptions.Username = options.Username
+		pullOptions.Password = options.Password
+		pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
+
+		pulledImages, err := ic.Libpod.LibimageRuntime().Pull(ctx, container.Image, pullPolicy, pullOptions)
 		if err != nil {
 			return nil, err
 		}
 
 		specgenOpts := kube.CtrSpecGenOptions{
 			Container:      container,
-			Image:          newImage,
+			Image:          pulledImages[0],
 			Volumes:        volumes,
 			PodID:          pod.ID(),
 			PodName:        podName,
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 9bba0fa6c..ebe59e871 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -164,7 +164,10 @@ func movePauseProcessToScope(r *libpod.Runtime) error {
 // SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images.
 func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
 	var systemPruneReport = new(entities.SystemPruneReport)
-	var filters []string
+	filters := []string{}
+	for k, v := range options.Filters {
+		filters = append(filters, fmt.Sprintf("%s=%s", k, v[0]))
+	}
 	reclaimedSpace := (uint64)(0)
 	found := true
 	for found {
@@ -188,10 +191,12 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
 		}
 		reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(containerPruneReports)
 		systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...)
-		for k, v := range options.Filters {
-			filters = append(filters, fmt.Sprintf("%s=%s", k, v[0]))
+		imagePruneOptions := entities.ImagePruneOptions{
+			All:    options.All,
+			Filter: filters,
 		}
-		imagePruneReports, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
+		imageEngine := ImageEngine{Libpod: ic.Libpod}
+		imagePruneReports, err := imageEngine.Prune(ctx, imagePruneOptions)
 		reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(imagePruneReports)
 
 		if err != nil {
@@ -225,13 +230,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
 		dfImages = []*entities.SystemDfImageReport{}
 	)
 
-	// Compute disk-usage stats for all local images.
-	imgs, err := ic.Libpod.ImageRuntime().GetImages()
-	if err != nil {
-		return nil, err
-	}
-
-	imageStats, err := ic.Libpod.ImageRuntime().DiskUsage(ctx, imgs)
+	imageStats, err := ic.Libpod.LibimageRuntime().DiskUsage(ctx)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 90b6e104b..3fd9a755d 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -8,10 +8,10 @@ import (
 	"strings"
 	"time"
 
+	"github.com/containers/common/libimage"
 	"github.com/containers/common/pkg/config"
 	"github.com/containers/image/v5/docker/reference"
 	"github.com/containers/image/v5/types"
-	"github.com/containers/podman/v3/libpod/image"
 	images "github.com/containers/podman/v3/pkg/bindings/images"
 	"github.com/containers/podman/v3/pkg/domain/entities"
 	"github.com/containers/podman/v3/pkg/domain/entities/reports"
@@ -311,7 +311,7 @@ func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.Dif
 
 func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
 	mappedFilters := make(map[string][]string)
-	filters, err := image.ParseSearchFilter(opts.Filters)
+	filters, err := libimage.ParseSearchFilter(opts.Filters)
 	if err != nil {
 		return nil, err
 	}
-- 
cgit v1.2.3-54-g00ecf