diff options
Diffstat (limited to 'libpod/image/image.go')
-rw-r--r-- | libpod/image/image.go | 178 |
1 files changed, 148 insertions, 30 deletions
diff --git a/libpod/image/image.go b/libpod/image/image.go index 15fc5174c..633a682cc 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -26,15 +26,23 @@ import ( "github.com/projectatomic/libpod/pkg/util" ) +// imageConversions is used to cache image "cast" types +type imageConversions struct { + imgRef types.Image + storeRef types.ImageReference +} + // Image is the primary struct for dealing with images // It is still very much a work in progress type Image struct { // Adding these two structs for now but will cull when we near // completion of this library. + imageConversions inspect.ImageData inspect.ImageResult - InputName string - Local bool + inspectInfo *types.ImageInspectInfo + InputName string + Local bool //runtime *libpod.Runtime image *storage.Image imageruntime *Runtime @@ -226,11 +234,22 @@ func (i *Image) ID() string { return i.image.ID } -// Digest returns the image's Manifest +// Digest returns the image's digest func (i *Image) Digest() digest.Digest { return i.image.Digest } +// Manifest returns the image's manifest as a byte array +// and manifest type as a string. The manifest type is +// MediaTypeImageManifest from ociv1. +func (i *Image) Manifest() ([]byte, string, error) { + imgRef, err := i.toImageRef() + if err != nil { + return nil, "", err + } + return imgRef.Manifest() +} + // Names returns a string array of names associated with the image func (i *Image) Names() []string { return i.image.Names @@ -253,20 +272,6 @@ func (i *Image) Remove(force bool) error { return err } -func annotations(manifest []byte, manifestType string) map[string]string { - annotations := make(map[string]string) - switch manifestType { - case ociv1.MediaTypeImageManifest: - var m ociv1.Manifest - if err := json.Unmarshal(manifest, &m); err == nil { - for k, v := range m.Annotations { - annotations[k] = v - } - } - } - return annotations -} - // Decompose an Image func (i *Image) Decompose() error { return types2.NotImplementedError @@ -349,6 +354,14 @@ func getImageDigest(src types.ImageReference, ctx *types.SystemContext) (string, // TagImage adds a tag to the given image func (i *Image) TagImage(tag string) error { + decomposedTag, err := decompose(tag) + if err != nil { + return err + } + // If the input does not have a tag, we need to add one (latest) + if !decomposedTag.isTagged { + tag = fmt.Sprintf("%s:%s", tag, decomposedTag.tag) + } tags := i.Names() if util.StringInSlice(tag, tags) { return nil @@ -426,7 +439,14 @@ func (i *Image) MatchesID(id string) bool { // toStorageReference returns a *storageReference from an Image func (i *Image) toStorageReference() (types.ImageReference, error) { - return is.Transport.ParseStoreReference(i.imageruntime.store, i.ID()) + if i.storeRef == nil { + storeRef, err := is.Transport.ParseStoreReference(i.imageruntime.store, i.ID()) + if err != nil { + return nil, err + } + i.storeRef = storeRef + } + return i.storeRef, nil } // ToImageRef returns an image reference type from an image @@ -437,15 +457,18 @@ func (i *Image) ToImageRef() (types.Image, error) { // toImageRef returns an Image Reference type from an image func (i *Image) toImageRef() (types.Image, error) { - 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(nil) - if err != nil { - return nil, errors.Wrapf(err, "error reading image %q", i.ID()) + if i.imgRef == 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(nil) + if err != nil { + return nil, errors.Wrapf(err, "error reading image %q", i.ID()) + } + i.imgRef = imgRef } - return imgRef, nil + return i.imgRef, nil } // sizer knows its size. @@ -507,19 +530,114 @@ func (i *Image) Dangling() bool { // Labels returns the image's labels func (i *Image) Labels() (map[string]string, error) { - sr, err := i.toStorageReference() + imgInspect, err := i.imageInspectInfo() + if err != nil { + return nil, nil + } + return imgInspect.Labels, nil +} + +// Annotations returns the annotations of an image +func (i *Image) Annotations() (map[string]string, error) { + manifest, manifestType, err := i.Manifest() + if err != nil { + return nil, err + } + annotations := make(map[string]string) + switch manifestType { + case ociv1.MediaTypeImageManifest: + var m ociv1.Manifest + if err := json.Unmarshal(manifest, &m); err == nil { + for k, v := range m.Annotations { + annotations[k] = v + } + } + } + return annotations, nil +} + +// ociv1Image converts and image to an imgref and then an +// ociv1 image type +func (i *Image) ociv1Image() (*ociv1.Image, error) { + imgRef, err := i.toImageRef() if err != nil { return nil, err } - ic, err := sr.NewImage(&types.SystemContext{}) + return imgRef.OCIConfig() +} + +func (i *Image) imageInspectInfo() (*types.ImageInspectInfo, error) { + if i.inspectInfo == nil { + sr, err := i.toStorageReference() + if err != nil { + return nil, err + } + ic, err := sr.NewImage(&types.SystemContext{}) + if err != nil { + return nil, err + } + imgInspect, err := ic.Inspect() + if err != nil { + return nil, err + } + i.inspectInfo = imgInspect + } + return i.inspectInfo, nil +} + +// Inspect returns an image's inspect data +func (i *Image) Inspect() (*inspect.ImageData, error) { + ociv1Img, err := i.ociv1Image() if err != nil { return nil, err } - imgInspect, err := ic.Inspect() + info, err := i.imageInspectInfo() if err != nil { return nil, err } - return imgInspect.Labels, nil + annotations, err := i.Annotations() + if err != nil { + return nil, err + } + + size, err := i.Size() + if err != nil { + return nil, err + } + + var repoDigests []string + for _, name := range i.Names() { + repoDigests = append(repoDigests, strings.SplitN(name, ":", 2)[0]+"@"+i.Digest().String()) + } + + driver, err := i.DriverData() + if err != nil { + return nil, err + } + + data := &inspect.ImageData{ + ID: i.ID(), + RepoTags: i.Names(), + RepoDigests: repoDigests, + Comment: ociv1Img.History[0].Comment, + Created: ociv1Img.Created, + Author: ociv1Img.Author, + Architecture: ociv1Img.Architecture, + Os: ociv1Img.OS, + ContainerConfig: &ociv1Img.Config, + Version: info.DockerVersion, + Size: int64(*size), + VirtualSize: int64(*size), + Annotations: annotations, + Digest: i.Digest(), + Labels: info.Labels, + RootFS: &inspect.RootFS{ + Type: ociv1Img.RootFS.Type, + Layers: ociv1Img.RootFS.DiffIDs, + }, + GraphDriver: driver, + } + return data, nil } // Import imports and image into the store and returns an image |