summaryrefslogtreecommitdiff
path: root/libpod/image
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/image')
-rw-r--r--libpod/image/image.go130
-rw-r--r--libpod/image/image_test.go4
-rw-r--r--libpod/image/pull.go4
-rw-r--r--libpod/image/utils.go18
4 files changed, 134 insertions, 22 deletions
diff --git a/libpod/image/image.go b/libpod/image/image.go
index b218c7d67..5e69a0a98 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -12,6 +12,7 @@ import (
cp "github.com/containers/image/copy"
"github.com/containers/image/docker/reference"
is "github.com/containers/image/storage"
+ "github.com/containers/image/tarball"
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
"github.com/containers/storage"
@@ -19,6 +20,8 @@ import (
"github.com/opencontainers/go-digest"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
+ "github.com/projectatomic/libpod/libpod/common"
+ "github.com/projectatomic/libpod/libpod/driver"
"github.com/projectatomic/libpod/pkg/inspect"
"github.com/projectatomic/libpod/pkg/util"
)
@@ -36,12 +39,20 @@ type Image struct {
// Runtime contains the store
type Runtime struct {
- store storage.Store
+ store storage.Store
+ SignaturePolicyPath string
}
-// NewImageRuntime creates an Image Runtime including the store given
+// NewImageRuntimeFromStore creates an ImageRuntime based on a provided store
+func NewImageRuntimeFromStore(store storage.Store) *Runtime {
+ return &Runtime{
+ store: store,
+ }
+}
+
+// NewImageRuntimeFromOptions creates an Image Runtime including the store given
// store options
-func NewImageRuntime(options storage.StoreOptions) (*Runtime, error) {
+func NewImageRuntimeFromOptions(options storage.StoreOptions) (*Runtime, error) {
if reexec.Init() {
return nil, errors.Errorf("unable to reexec")
}
@@ -110,10 +121,12 @@ func (ir *Runtime) New(name, signaturePolicyPath, authfile string, writer io.Wri
}
// The image is not local
-
+ if signaturePolicyPath == "" {
+ signaturePolicyPath = ir.SignaturePolicyPath
+ }
imageName, err := newImage.pullImage(writer, authfile, signaturePolicyPath, signingoptions, dockeroptions)
if err != nil {
- return &newImage, errors.Errorf("unable to pull %s", name)
+ return nil, errors.Errorf("unable to pull %s", name)
}
newImage.InputName = imageName
@@ -141,7 +154,7 @@ func (i *Image) reloadImage() error {
// 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)
+ imageError := fmt.Sprintf("unable to find '%s' in local storage", i.InputName)
if i.InputName == "" {
return nil, errors.Errorf("input name is blank")
}
@@ -187,8 +200,7 @@ func (i *Image) getLocalImage() (*storage.Image, error) {
if err == nil {
return repoImage, nil
}
-
- return nil, errors.Errorf("%s", imageError)
+ return nil, errors.Wrapf(err, imageError)
}
// hasRegistry returns a bool/err response if the image has a registry in its
@@ -307,7 +319,11 @@ func (ir *Runtime) GetImages() ([]*Image, error) {
return nil, err
}
for _, i := range images {
- newImages = append(newImages, ir.newFromStorage(&i))
+ // iterating over these, be careful to not iterate on the literal
+ // pointer.
+ image := i
+ img := ir.newFromStorage(&image)
+ newImages = append(newImages, img)
}
return newImages, nil
}
@@ -338,10 +354,24 @@ func (i *Image) TagImage(tag string) error {
return i.imageruntime.store.SetNames(i.ID(), tags)
}
+// UntagImage removes a tag from the given image
+func (i *Image) UntagImage(tag string) error {
+ var newTags []string
+ tags := i.Names()
+ if !util.StringInSlice(tag, tags) {
+ return nil
+ }
+ for _, t := range tags {
+ if tag != t {
+ newTags = append(newTags, t)
+ }
+ }
+ i.reloadImage()
+ return i.imageruntime.store.SetNames(i.ID(), newTags)
+}
+
// PushImage pushes the given image to a location described by the given path
func (i *Image) PushImage(destination, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions) error {
- // PushImage pushes the src image to the destination
- //func PushImage(source, destination string, options CopyOptions) error {
if destination == "" {
return errors.Wrapf(syscall.EINVAL, "destination image name must be specified")
}
@@ -395,6 +425,12 @@ func (i *Image) toStorageReference() (types.ImageReference, error) {
return is.Transport.ParseStoreReference(i.imageruntime.store, i.ID())
}
+// ToImageRef returns an image reference type from an image
+// TODO: Hopefully we can remove this exported function for mheon
+func (i *Image) ToImageRef() (types.Image, error) {
+ return i.toImageRef()
+}
+
// 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())
@@ -431,5 +467,77 @@ func (i *Image) Size() (*uint64, error) {
}
}
return nil, errors.Errorf("unable to determine size")
+}
+
+// DriverData gets the driver data from the store on a layer
+func (i *Image) DriverData() (*inspect.Data, error) {
+ topLayer, err := i.Layer()
+ if err != nil {
+ return nil, err
+ }
+ return driver.GetDriverData(i.imageruntime.store, topLayer.ID)
+}
+// Layer returns the image's top layer
+func (i *Image) Layer() (*storage.Layer, error) {
+ return i.imageruntime.store.Layer(i.image.TopLayer)
+}
+
+// History gets the history of an image and information about its layers
+func (i *Image) History() ([]ociv1.History, []types.BlobInfo, error) {
+ img, err := i.toImageRef()
+ if err != nil {
+ return nil, nil, err
+ }
+ oci, err := img.OCIConfig()
+ if err != nil {
+ return nil, nil, err
+ }
+ return oci.History, img.LayerInfos(), nil
+}
+
+// Import imports and image into the store and returns an image
+func Import(path, reference string, writer io.Writer, signingOptions SigningOptions, imageConfig ociv1.Image, runtime *Runtime) (*Image, error) {
+ file := TarballTransport + ":" + path
+ src, err := alltransports.ParseImageName(file)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error parsing image name %q", path)
+ }
+
+ updater, ok := src.(tarball.ConfigUpdater)
+ if !ok {
+ return nil, errors.Wrapf(err, "unexpected type, a tarball reference should implement tarball.ConfigUpdater")
+ }
+
+ annotations := make(map[string]string)
+
+ // config imgspecv1.Image
+ err = updater.ConfigUpdate(imageConfig, annotations)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error updating image config")
+ }
+
+ sc := common.GetSystemContext("", "", false)
+
+ // if reference not given, get the image digest
+ if reference == "" {
+ reference, err = getImageDigest(src, sc)
+ if err != nil {
+ return nil, err
+ }
+ }
+ policyContext, err := getPolicyContext(sc)
+ if err != nil {
+ return nil, err
+ }
+ defer policyContext.Destroy()
+ copyOptions := getCopyOptions(writer, "", nil, nil, signingOptions, "", "", false)
+ dest, err := is.Transport.ParseStoreReference(runtime.store, reference)
+ if err != nil {
+ errors.Wrapf(err, "error getting image reference for %q", reference)
+ }
+ if err = cp.Image(policyContext, dest, src, copyOptions); err != nil {
+ return nil, err
+ }
+ return runtime.NewFromLocal(reference)
}
diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go
index 0e2f0c241..d9e8987a6 100644
--- a/libpod/image/image_test.go
+++ b/libpod/image/image_test.go
@@ -79,7 +79,7 @@ func TestImage_NewFromLocal(t *testing.T) {
writer = os.Stdout
// Need images to be present for this test
- ir, err := NewImageRuntime(so)
+ ir, err := NewImageRuntimeFromOptions(so)
assert.NoError(t, err)
bb, err := ir.New("docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{})
assert.NoError(t, err)
@@ -115,7 +115,7 @@ func TestImage_New(t *testing.T) {
RunRoot: workdir,
GraphRoot: workdir,
}
- ir, err := NewImageRuntime(so)
+ ir, err := NewImageRuntimeFromOptions(so)
assert.NoError(t, err)
// Build the list of pull names
names = append(names, bbNames...)
diff --git a/libpod/image/pull.go b/libpod/image/pull.go
index 52ef175d4..8c43c6054 100644
--- a/libpod/image/pull.go
+++ b/libpod/image/pull.go
@@ -177,8 +177,8 @@ func (i *Image) pullImage(writer io.Writer, authfile, signaturePolicyPath string
copyOptions := getCopyOptions(writer, signaturePolicyPath, dockerOptions, nil, signingOptions, authfile, "", false)
for _, imageInfo := range pullStructs {
// Print the following statement only when pulling from a docker or atomic registry
- if writer != nil && (imageInfo.srcRef.Transport().Name() == DockerTransport || imageInfo.srcRef.Transport().Name() == AtomicTransport) {
- io.WriteString(writer, fmt.Sprintf("Trying to pull %s...\n", imageInfo.image))
+ if writer != nil && (strings.HasPrefix(DockerTransport, imageInfo.srcRef.Transport().Name()) || imageInfo.srcRef.Transport().Name() == AtomicTransport) {
+ io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image))
}
if err = cp.Image(policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions); err != nil {
if writer != nil {
diff --git a/libpod/image/utils.go b/libpod/image/utils.go
index adc795e3a..76ec349f9 100644
--- a/libpod/image/utils.go
+++ b/libpod/image/utils.go
@@ -2,15 +2,14 @@ package image
import (
"io"
+ "strings"
cp "github.com/containers/image/copy"
"github.com/containers/image/docker/reference"
- "github.com/containers/storage"
- "github.com/pkg/errors"
-
"github.com/containers/image/signature"
"github.com/containers/image/types"
- "strings"
+ "github.com/containers/storage"
+ "github.com/pkg/errors"
)
func getTags(nameInput string) (reference.NamedTagged, bool, error) {
@@ -36,14 +35,19 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er
}
if d.name == search.name && d.tag == search.tag {
results = append(results, image.image)
- break
+ continue
+ }
+ // account for registry:/somedir/image
+ if strings.HasSuffix(d.name, search.name) && d.tag == search.tag {
+ results = append(results, image.image)
+ continue
}
}
}
if len(results) == 0 {
- return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", search)
+ return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", search.name)
} else if len(results) > 1 {
- return &storage.Image{}, errors.Errorf("found multiple name and tag matches for %s in repotags", search)
+ return &storage.Image{}, errors.Errorf("found multiple name and tag matches for %s in repotags", search.name)
}
return results[0], nil
}