summaryrefslogtreecommitdiff
path: root/libpod/image/image.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/image/image.go')
-rw-r--r--libpod/image/image.go191
1 files changed, 191 insertions, 0 deletions
diff --git a/libpod/image/image.go b/libpod/image/image.go
new file mode 100644
index 000000000..a3f0bce83
--- /dev/null
+++ b/libpod/image/image.go
@@ -0,0 +1,191 @@
+package image
+
+import (
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/containers/image/docker/reference"
+ "github.com/containers/storage"
+ "github.com/pkg/errors"
+ "github.com/projectatomic/libpod/libpod"
+ "github.com/projectatomic/libpod/pkg/inspect"
+)
+
+// Image is the primary struct for dealing with images
+// It is still very much a work in progress
+type Image struct {
+ inspect.ImageData
+ InputName string
+ Local bool
+ runtime *libpod.Runtime
+ image *storage.Image
+}
+
+// NewFromLocal creates a new image object that is intended
+// to only deal with local images already in the store (or
+// its aliases)
+func NewFromLocal(name string, runtime *libpod.Runtime) (Image, error) {
+ image := Image{
+ InputName: name,
+ Local: true,
+ runtime: runtime,
+ }
+ localImage, err := image.getLocalImage()
+ if err != nil {
+ return Image{}, err
+ }
+ image.image = localImage
+ return image, nil
+}
+
+// New creates a new image object where the image could be local
+// or remote
+func New(name string, runtime *libpod.Runtime) (Image, error) {
+ // We don't know if the image is local or not ... check local first
+ newImage := Image{
+ InputName: name,
+ Local: false,
+ runtime: runtime,
+ }
+ localImage, err := newImage.getLocalImage()
+ if err == nil {
+ newImage.Local = true
+ newImage.image = localImage
+ return newImage, nil
+ }
+
+ // The image is not local
+ pullNames, err := newImage.createNamesToPull()
+ if err != nil {
+ return newImage, err
+ }
+ if len(pullNames) == 0 {
+ return newImage, errors.Errorf("unable to pull %s", newImage.InputName)
+ }
+ var writer io.Writer
+ writer = os.Stderr
+ for _, p := range pullNames {
+ _, err := newImage.pull(p, writer, runtime)
+ if err == nil {
+ newImage.InputName = p
+ img, err := newImage.getLocalImage()
+ newImage.image = img
+ return newImage, err
+ }
+ }
+ return newImage, errors.Errorf("unable to find %s", name)
+}
+
+// getLocalImage resolves an unknown input describing an image and
+// returns a storage.Image or an error. It is used by NewFromLocal.
+func (i *Image) getLocalImage() (*storage.Image, error) {
+ imageError := fmt.Sprintf("unable to find '%s' in local storage\n", i.InputName)
+ if i.InputName == "" {
+ return nil, errors.Errorf("input name is blank")
+ }
+ var taggedName string
+ img, err := i.runtime.GetImage(i.InputName)
+ if err == nil {
+ return img, err
+ }
+
+ // container-storage wasn't able to find it in its current form
+ // check if the input name has a tag, and if not, run it through
+ // again
+ decomposedImage, err := decompose(i.InputName)
+ if err != nil {
+ return nil, err
+ }
+ // the inputname isn't tagged, so we assume latest and try again
+ if !decomposedImage.isTagged {
+ taggedName = fmt.Sprintf("%s:latest", i.InputName)
+ img, err = i.runtime.GetImage(taggedName)
+ if err == nil {
+ return img, nil
+ }
+ }
+ hasReg, err := i.hasRegistry()
+ if err != nil {
+ return nil, errors.Wrapf(err, imageError)
+ }
+
+ // if the input name has a registry in it, the image isnt here
+ if hasReg {
+ return nil, errors.Errorf("%s", imageError)
+ }
+
+ // grab all the local images
+ images, err := i.runtime.GetImages(&libpod.ImageFilterParams{})
+ if err != nil {
+ return nil, err
+ }
+
+ // check the repotags of all images for a match
+ repoImage, err := findImageInRepotags(decomposedImage, images)
+ if err == nil {
+ return repoImage, nil
+ }
+
+ return nil, errors.Errorf("%s", imageError)
+}
+
+// hasRegistry returns a bool/err response if the image has a registry in its
+// name
+func (i *Image) hasRegistry() (bool, error) {
+ imgRef, err := reference.Parse(i.InputName)
+ if err != nil {
+ return false, err
+ }
+ registry := reference.Domain(imgRef.(reference.Named))
+ if registry != "" {
+ return true, nil
+ }
+ return false, nil
+}
+
+// ID returns the image ID as a string
+func (i *Image) ID() string {
+ return i.image.ID
+}
+
+// createNamesToPull looks at a decomposed image and determines the possible
+// images names to try pulling in combination with the registries.conf file as well
+func (i *Image) createNamesToPull() ([]string, error) {
+ var pullNames []string
+ decomposedImage, err := decompose(i.InputName)
+ if err != nil {
+ return nil, err
+ }
+
+ if decomposedImage.hasRegistry {
+ pullNames = append(pullNames, i.InputName)
+ } else {
+ registries, err := libpod.GetRegistries()
+ if err != nil {
+ return nil, err
+ }
+ for _, registry := range registries {
+ decomposedImage.registry = registry
+ pullNames = append(pullNames, decomposedImage.assemble())
+ }
+ }
+ return pullNames, nil
+}
+
+// pull is a temporary function for stage1 to be able to pull images during the image
+// resolution tests. it will be replaced in stage2 with a more robust function.
+func (i *Image) pull(name string, writer io.Writer, r *libpod.Runtime) (string, error) {
+ options := libpod.CopyOptions{
+ Writer: writer,
+ SignaturePolicyPath: r.GetConfig().SignaturePolicyPath,
+ }
+ return i.runtime.PullImage(name, options)
+}
+
+// Remove an image
+// This function is only complete enough for the stage 1 tests.
+func (i *Image) Remove(force bool) error {
+ _, err := i.runtime.RemoveImage(i.image, force)
+ return err
+}