mirror of
https://github.com/containers/podman.git
synced 2025-12-01 10:38:05 +08:00
Pull in updates made to the filters code for images. Filters now perform an AND operation except for th reference filter which does an OR operation for positive case but an AND operation for negative cases. Signed-off-by: Urvashi Mohnani <umohnani@redhat.com>
154 lines
4.8 KiB
Go
154 lines
4.8 KiB
Go
//go:build !remote
|
|
|
|
package libimage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
dirTransport "github.com/containers/image/v5/directory"
|
|
dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
|
|
ociArchiveTransport "github.com/containers/image/v5/oci/archive"
|
|
ociTransport "github.com/containers/image/v5/oci/layout"
|
|
"github.com/containers/image/v5/types"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type LoadOptions struct {
|
|
CopyOptions
|
|
}
|
|
|
|
// Load loads one or more images (depending on the transport) from the
|
|
// specified path. The path may point to an image the following transports:
|
|
// oci, oci-archive, dir, docker-archive.
|
|
func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ([]string, error) {
|
|
logrus.Debugf("Loading image from %q", path)
|
|
|
|
if options == nil {
|
|
options = &LoadOptions{}
|
|
}
|
|
|
|
// we have 4 functions, so a maximum of 4 errors
|
|
loadErrors := make([]error, 0, 4)
|
|
for _, f := range []func() ([]string, string, error){
|
|
// OCI
|
|
func() ([]string, string, error) {
|
|
logrus.Debugf("-> Attempting to load %q as an OCI directory", path)
|
|
ref, err := ociTransport.NewReference(path, "")
|
|
if err != nil {
|
|
return nil, ociTransport.Transport.Name(), err
|
|
}
|
|
images, err := r.copyFromDefault(ctx, ref, &options.CopyOptions)
|
|
return images, ociTransport.Transport.Name(), err
|
|
},
|
|
|
|
// OCI-ARCHIVE
|
|
func() ([]string, string, error) {
|
|
logrus.Debugf("-> Attempting to load %q as an OCI archive", path)
|
|
ref, err := ociArchiveTransport.NewReference(path, "")
|
|
if err != nil {
|
|
return nil, ociArchiveTransport.Transport.Name(), err
|
|
}
|
|
images, err := r.copyFromDefault(ctx, ref, &options.CopyOptions)
|
|
return images, ociArchiveTransport.Transport.Name(), err
|
|
},
|
|
|
|
// DOCKER-ARCHIVE
|
|
func() ([]string, string, error) {
|
|
logrus.Debugf("-> Attempting to load %q as a Docker archive", path)
|
|
ref, err := dockerArchiveTransport.ParseReference(path)
|
|
if err != nil {
|
|
return nil, dockerArchiveTransport.Transport.Name(), err
|
|
}
|
|
images, err := r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions)
|
|
return images, dockerArchiveTransport.Transport.Name(), err
|
|
},
|
|
|
|
// DIR
|
|
func() ([]string, string, error) {
|
|
logrus.Debugf("-> Attempting to load %q as a Docker dir", path)
|
|
ref, err := dirTransport.NewReference(path)
|
|
if err != nil {
|
|
return nil, dirTransport.Transport.Name(), err
|
|
}
|
|
images, err := r.copyFromDefault(ctx, ref, &options.CopyOptions)
|
|
return images, dirTransport.Transport.Name(), err
|
|
},
|
|
} {
|
|
loadedImages, transportName, err := f()
|
|
if err == nil {
|
|
if r.eventChannel != nil {
|
|
err = r.writeLoadEvents(path, loadedImages)
|
|
}
|
|
return loadedImages, err
|
|
}
|
|
logrus.Debugf("Error loading %s (%s): %v", path, transportName, err)
|
|
loadErrors = append(loadErrors, fmt.Errorf("%s: %v", transportName, err))
|
|
}
|
|
|
|
// Give a decent error message if nothing above worked.
|
|
// we want the colon here for the multiline error
|
|
//nolint:revive
|
|
loadError := fmt.Errorf("payload does not match any of the supported image formats:")
|
|
for _, err := range loadErrors {
|
|
loadError = fmt.Errorf("%v\n * %v", loadError, err)
|
|
}
|
|
|
|
return nil, loadError
|
|
}
|
|
|
|
// writeLoadEvents writes the events of the loaded image.
|
|
func (r *Runtime) writeLoadEvents(path string, loadedImages []string) error {
|
|
for _, name := range loadedImages {
|
|
image, _, err := r.LookupImage(name, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("locating pulled image %q name in containers storage: %w", name, err)
|
|
}
|
|
r.writeEvent(&Event{ID: image.ID(), Name: path, Time: time.Now(), Type: EventTypeImageLoad})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// loadMultiImageDockerArchive loads the docker archive specified by ref. In
|
|
// case the path@reference notation was used, only the specified image will be
|
|
// loaded. Otherwise, all images will be loaded.
|
|
func (r *Runtime) loadMultiImageDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) {
|
|
// If we cannot stat the path, it either does not exist OR the correct
|
|
// syntax to reference an image within the archive was used, so we
|
|
// should.
|
|
path := ref.StringWithinTransport()
|
|
if _, err := os.Stat(path); err != nil {
|
|
return r.copyFromDockerArchive(ctx, ref, options)
|
|
}
|
|
|
|
reader, err := dockerArchiveTransport.NewReader(r.systemContextCopy(), path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() {
|
|
if err := reader.Close(); err != nil {
|
|
logrus.Errorf("Closing reader of docker archive: %v", err)
|
|
}
|
|
}()
|
|
|
|
refLists, err := reader.List()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var copiedImages []string
|
|
for _, list := range refLists {
|
|
for _, listRef := range list {
|
|
names, err := r.copyFromDockerArchiveReaderReference(ctx, reader, listRef, options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copiedImages = append(copiedImages, names...)
|
|
}
|
|
}
|
|
|
|
return copiedImages, nil
|
|
}
|