aboutsummaryrefslogtreecommitdiff
path: root/libpod/image/image.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/image/image.go')
-rw-r--r--libpod/image/image.go206
1 files changed, 122 insertions, 84 deletions
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 5c530858a..2ab88f2e9 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -3,6 +3,7 @@ package image
import (
"context"
"encoding/json"
+ stderrors "errors"
"fmt"
"io"
"io/ioutil"
@@ -16,6 +17,7 @@ import (
"github.com/containers/image/v5/directory"
dockerarchive "github.com/containers/image/v5/docker/archive"
"github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/image"
"github.com/containers/image/v5/manifest"
ociarchive "github.com/containers/image/v5/oci/archive"
is "github.com/containers/image/v5/storage"
@@ -42,8 +44,8 @@ import (
type Image struct {
// Adding these two structs for now but will cull when we near
// completion of this library.
- imgRef types.Image
- storeRef types.ImageReference
+ imgRef types.Image
+ imgSrcRef types.ImageSource
inspect.ImageData
inspect.ImageResult
inspectInfo *types.ImageInspectInfo
@@ -72,7 +74,10 @@ type InfoImage struct {
}
// ErrRepoTagNotFound is the error returned when the image id given doesn't match a rep tag in store
-var ErrRepoTagNotFound = errors.New("unable to match user input to any specific repotag")
+var ErrRepoTagNotFound = stderrors.New("unable to match user input to any specific repotag")
+
+// ErrImageIsBareList is the error returned when the image is just a list or index
+var ErrImageIsBareList = stderrors.New("image contains a manifest list or image index, but no runnable image")
// NewImageRuntimeFromStore creates an ImageRuntime based on a provided store
func NewImageRuntimeFromStore(store storage.Store) *Runtime {
@@ -294,9 +299,18 @@ func (i *Image) Digest() digest.Digest {
return i.image.Digest
}
+// GetManifest returns the image's manifest as a byte array
+// and manifest type as a string.
+func (i *Image) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
+ imgSrcRef, err := i.toImageSourceRef(ctx)
+ if err != nil {
+ return nil, "", err
+ }
+ return imgSrcRef.GetManifest(ctx, instanceDigest)
+}
+
// Manifest returns the image's manifest as a byte array
-// and manifest type as a string. The manifest type is
-// MediaTypeImageManifest from ociv1.
+// and manifest type as a string.
func (i *Image) Manifest(ctx context.Context) ([]byte, string, error) {
imgRef, err := i.toImageRef(ctx)
if err != nil {
@@ -379,26 +393,6 @@ func (i *Image) Remove(ctx context.Context, force bool) error {
return nil
}
-// TODO: Rework this method to not require an assembly of the fq name with transport
-/*
-// GetManifest tries to GET an images manifest, returns nil on success and err on failure
-func (i *Image) GetManifest() error {
- pullRef, err := alltransports.ParseImageName(i.assembleFqNameTransport())
- if err != nil {
- return errors.Errorf("unable to parse '%s'", i.Names()[0])
- }
- imageSource, err := pullRef.NewImageSource(nil)
- if err != nil {
- return errors.Wrapf(err, "unable to create new image source")
- }
- _, _, err = imageSource.GetManifest(nil)
- if err == nil {
- return nil
- }
- return err
-}
-*/
-
// getImage retrieves an image matching the given name or hash from system
// storage
// If no matching image can be found, an error is returned
@@ -612,76 +606,98 @@ func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageRefere
// MatchesID returns a bool based on if the input id
// matches the image's id
+// TODO: This isn't used anywhere, so remove it
func (i *Image) MatchesID(id string) bool {
return strings.HasPrefix(i.ID(), id)
}
-// toStorageReference returns a *storageReference from an Image
-func (i *Image) toStorageReference() (types.ImageReference, error) {
- var lookupName string
- if i.storeRef == nil {
- if i.image != nil {
- lookupName = i.ID()
- } else {
- lookupName = i.InputName
- }
- storeRef, err := is.Transport.ParseStoreReference(i.imageruntime.store, lookupName)
- if err != nil {
- return nil, err
- }
- i.storeRef = storeRef
- }
- return i.storeRef, nil
-}
-
// ToImageRef returns an image reference type from an image
// TODO: Hopefully we can remove this exported function for mheon
func (i *Image) ToImageRef(ctx context.Context) (types.Image, error) {
return i.toImageRef(ctx)
}
-// toImageRef returns an Image Reference type from an image
-func (i *Image) toImageRef(ctx context.Context) (types.Image, error) {
+// toImageSourceRef returns an ImageSource Reference type from an image
+func (i *Image) toImageSourceRef(ctx context.Context) (types.ImageSource, error) {
if i == nil {
- return nil, errors.Errorf("cannot convert nil image to image reference")
+ return nil, errors.Errorf("cannot convert nil image to image source reference")
}
- if i.imgRef == nil {
+ if i.imgSrcRef == nil {
ref, err := is.Transport.ParseStoreReference(i.imageruntime.store, "@"+i.ID())
if err != nil {
return nil, errors.Wrapf(err, "error parsing reference to image %q", i.ID())
}
- imgRef, err := ref.NewImage(ctx, nil)
+ imgSrcRef, err := ref.NewImageSource(ctx, nil)
if err != nil {
- return nil, errors.Wrapf(err, "error reading image %q", i.ID())
+ return nil, errors.Wrapf(err, "error reading image %q as image source", i.ID())
}
- i.imgRef = imgRef
+ i.imgSrcRef = imgSrcRef
}
- return i.imgRef, nil
-}
-
-// sizer knows its size.
-type sizer interface {
- Size() (int64, error)
+ return i.imgSrcRef, nil
}
//Size returns the size of the image
func (i *Image) Size(ctx context.Context) (*uint64, error) {
- storeRef, err := is.Transport.ParseStoreReference(i.imageruntime.store, i.ID())
- if err != nil {
- return nil, err
+ if i.image == nil {
+ localImage, err := i.getLocalImage()
+ if err != nil {
+ return nil, err
+ }
+ i.image = localImage
+ }
+ if sum, err := i.imageruntime.store.ImageSize(i.ID()); err == nil && sum >= 0 {
+ usum := uint64(sum)
+ return &usum, nil
+ }
+ return nil, errors.Errorf("unable to determine size")
+}
+
+// toImageRef returns an Image Reference type from an image
+func (i *Image) toImageRef(ctx context.Context) (types.Image, error) {
+ if i == nil {
+ return nil, errors.Errorf("cannot convert nil image to image reference")
}
- systemContext := &types.SystemContext{}
- img, err := storeRef.NewImageSource(ctx, systemContext)
+ imgSrcRef, err := i.toImageSourceRef(ctx)
if err != nil {
return nil, err
}
- if s, ok := img.(sizer); ok {
- if sum, err := s.Size(); err == nil {
- usum := uint64(sum)
- return &usum, nil
+ if i.imgRef == nil {
+ systemContext := &types.SystemContext{}
+ unparsedDefaultInstance := image.UnparsedInstance(imgSrcRef, nil)
+ imgRef, err := image.FromUnparsedImage(ctx, systemContext, unparsedDefaultInstance)
+ if err != nil {
+ // check for a "tried-to-treat-a-bare-list-like-a-runnable-image" problem, else
+ // return info about the not-a-bare-list runnable image part of this storage.Image
+ if manifestBytes, manifestType, err2 := imgSrcRef.GetManifest(ctx, nil); err2 == nil {
+ if manifest.MIMETypeIsMultiImage(manifestType) {
+ if list, err3 := manifest.ListFromBlob(manifestBytes, manifestType); err3 == nil {
+ switch manifestType {
+ case ociv1.MediaTypeImageIndex:
+ err = errors.Wrapf(ErrImageIsBareList, "%q is an image index", i.InputName)
+ case manifest.DockerV2ListMediaType:
+ err = errors.Wrapf(ErrImageIsBareList, "%q is a manifest list", i.InputName)
+ default:
+ err = errors.Wrapf(ErrImageIsBareList, "%q", i.InputName)
+ }
+ for _, instanceDigest := range list.Instances() {
+ instance := instanceDigest
+ unparsedInstance := image.UnparsedInstance(imgSrcRef, &instance)
+ if imgRef2, err4 := image.FromUnparsedImage(ctx, systemContext, unparsedInstance); err4 == nil {
+ imgRef = imgRef2
+ err = nil
+ break
+ }
+ }
+ }
+ }
+ }
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading image %q as image", i.ID())
+ }
}
+ i.imgRef = imgRef
}
- return nil, errors.Errorf("unable to determine size")
+ return i.imgRef, nil
}
// DriverData gets the driver data from the store on a layer
@@ -708,6 +724,9 @@ type History struct {
func (i *Image) History(ctx context.Context) ([]*History, error) {
img, err := i.toImageRef(ctx)
if err != nil {
+ if errors.Cause(err) == ErrImageIsBareList {
+ return nil, nil
+ }
return nil, err
}
oci, err := img.OCIConfig(ctx)
@@ -853,7 +872,10 @@ func (i *Image) GetLabel(ctx context.Context, label string) (string, error) {
func (i *Image) Annotations(ctx context.Context) (map[string]string, error) {
imageManifest, manifestType, err := i.Manifest(ctx)
if err != nil {
- return nil, err
+ imageManifest, manifestType, err = i.GetManifest(ctx, nil)
+ if err != nil {
+ return nil, err
+ }
}
annotations := make(map[string]string)
switch manifestType {
@@ -868,24 +890,19 @@ func (i *Image) Annotations(ctx context.Context) (map[string]string, error) {
return annotations, nil
}
-// ociv1Image converts and image to an imgref and then an
-// ociv1 image type
+// ociv1Image converts an image to an imgref and then returns its config blob
+// converted to an ociv1 image type
func (i *Image) ociv1Image(ctx context.Context) (*ociv1.Image, error) {
imgRef, err := i.toImageRef(ctx)
if err != nil {
return nil, err
}
-
return imgRef.OCIConfig(ctx)
}
func (i *Image) imageInspectInfo(ctx context.Context) (*types.ImageInspectInfo, error) {
if i.inspectInfo == nil {
- sr, err := i.toStorageReference()
- if err != nil {
- return nil, err
- }
- ic, err := sr.NewImage(ctx, &types.SystemContext{})
+ ic, err := i.toImageRef(ctx)
if err != nil {
return nil, err
}
@@ -906,20 +923,20 @@ func (i *Image) Inspect(ctx context.Context) (*inspect.ImageData, error) {
ociv1Img, err := i.ociv1Image(ctx)
if err != nil {
- return nil, err
+ ociv1Img = &ociv1.Image{}
}
info, err := i.imageInspectInfo(ctx)
if err != nil {
- return nil, err
+ info = &types.ImageInspectInfo{}
}
annotations, err := i.Annotations(ctx)
if err != nil {
return nil, err
}
- size, err := i.Size(ctx)
- if err != nil {
- return nil, err
+ size := int64(-1)
+ if usize, err := i.Size(ctx); err == nil {
+ size = int64(*usize)
}
repoDigests, err := i.RepoDigests()
@@ -932,7 +949,7 @@ func (i *Image) Inspect(ctx context.Context) (*inspect.ImageData, error) {
return nil, err
}
- _, manifestType, err := i.Manifest(ctx)
+ _, manifestType, err := i.GetManifest(ctx, nil)
if err != nil {
return nil, errors.Wrapf(err, "unable to determine manifest type")
}
@@ -952,8 +969,8 @@ func (i *Image) Inspect(ctx context.Context) (*inspect.ImageData, error) {
Os: ociv1Img.OS,
Config: &ociv1Img.Config,
Version: info.DockerVersion,
- Size: int64(*size),
- VirtualSize: int64(*size),
+ Size: size,
+ VirtualSize: size,
Annotations: annotations,
Digest: i.Digest(),
Labels: info.Labels,
@@ -1082,6 +1099,9 @@ func splitString(input string) string {
func (i *Image) IsParent(ctx context.Context) (bool, error) {
children, err := i.getChildren(ctx, 1)
if err != nil {
+ if errors.Cause(err) == ErrImageIsBareList {
+ return false, nil
+ }
return false, err
}
return len(children) > 0, nil
@@ -1165,6 +1185,9 @@ func (i *Image) GetParent(ctx context.Context) (*Image, error) {
// fetch the configuration for the child image
child, err := i.ociv1Image(ctx)
if err != nil {
+ if errors.Cause(err) == ErrImageIsBareList {
+ return nil, nil
+ }
return nil, err
}
for _, img := range images {
@@ -1205,12 +1228,24 @@ func (i *Image) GetParent(ctx context.Context) (*Image, error) {
// GetChildren returns a list of the imageIDs that depend on the image
func (i *Image) GetChildren(ctx context.Context) ([]string, error) {
- return i.getChildren(ctx, 0)
+ children, err := i.getChildren(ctx, 0)
+ if err != nil {
+ if errors.Cause(err) == ErrImageIsBareList {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return children, nil
}
// getChildren returns a list of at most "max" imageIDs that depend on the image
func (i *Image) getChildren(ctx context.Context, max int) ([]string, error) {
var children []string
+
+ if _, err := i.toImageRef(ctx); err != nil {
+ return nil, nil
+ }
+
images, err := i.imageruntime.GetImages()
if err != nil {
return nil, err
@@ -1301,6 +1336,9 @@ func (i *Image) Comment(ctx context.Context, manifestType string) (string, error
}
ociv1Img, err := i.ociv1Image(ctx)
if err != nil {
+ if errors.Cause(err) == ErrImageIsBareList {
+ return "", nil
+ }
return "", err
}
if len(ociv1Img.History) > 0 {