mirror of
https://github.com/containers/podman.git
synced 2025-06-26 12:56:45 +08:00
Image library stage 4 - create and commit
Migrate the podman create and commit subcommandis to leverage the images library. I also had to migrate the cmd/ portions of run and rmi. Signed-off-by: baude <bbaude@redhat.com> Closes: #498 Approved by: mheon
This commit is contained in:
@ -2,11 +2,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@ -58,8 +59,11 @@ func commitCmd(c *cli.Context) error {
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
var opts libpod.CopyOptions
|
||||
var container string
|
||||
var (
|
||||
container string
|
||||
reference string
|
||||
writer io.Writer
|
||||
)
|
||||
args := c.Args()
|
||||
switch len(args) {
|
||||
case 0:
|
||||
@ -68,7 +72,7 @@ func commitCmd(c *cli.Context) error {
|
||||
container = args[0]
|
||||
case 2:
|
||||
container = args[0]
|
||||
opts.Reference = args[1]
|
||||
reference = args[1]
|
||||
default:
|
||||
return errors.Errorf("too many arguments. Usage CONTAINER [REFERENCE]")
|
||||
}
|
||||
@ -90,20 +94,18 @@ func commitCmd(c *cli.Context) error {
|
||||
History: history,
|
||||
Author: c.String("author"),
|
||||
}
|
||||
opts.ImageConfig = config
|
||||
opts.Writer = nil
|
||||
|
||||
if !c.Bool("quiet") {
|
||||
opts.Writer = os.Stderr
|
||||
writer = os.Stderr
|
||||
}
|
||||
|
||||
ctr, err := runtime.LookupContainer(container)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error looking up container %q", container)
|
||||
}
|
||||
img, err := ctr.Commit(c.BoolT("pause"), opts)
|
||||
newImage, err := ctr.Commit(c.BoolT("pause"), reference, writer, image.SigningOptions{}, config)
|
||||
if err == nil {
|
||||
fmt.Println(img.ID)
|
||||
fmt.Println(newImage.ID())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -3,13 +3,6 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/go-connections/nat"
|
||||
@ -17,10 +10,16 @@ import (
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/projectatomic/libpod/pkg/inspect"
|
||||
"github.com/projectatomic/libpod/pkg/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type mountType string
|
||||
@ -154,6 +153,7 @@ var createCommand = cli.Command{
|
||||
func createCmd(c *cli.Context) error {
|
||||
// TODO should allow user to create based off a directory on the host not just image
|
||||
// Need CLI support for this
|
||||
|
||||
if err := validateFlags(c, createFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -174,11 +174,14 @@ func createCmd(c *cli.Context) error {
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
imageName, _, data, err := imageData(c, runtime, c.Args()[0])
|
||||
rtc := runtime.GetConfig()
|
||||
|
||||
newImage, err := runtime.ImageRuntime().New(c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createConfig, err := parseCreateOpts(c, runtime, imageName, data)
|
||||
data, err := libpod.GetImageData(newImage)
|
||||
createConfig, err := parseCreateOpts(c, runtime, newImage.Names()[0], data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -379,46 +382,6 @@ func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[na
|
||||
return portBindings, nil
|
||||
}
|
||||
|
||||
// imageData pulls down the image if not stored locally and extracts the
|
||||
// default container runtime data out of it. imageData returns the data
|
||||
// to the caller. Example Data: Entrypoint, Env, WorkingDir, Labels ...
|
||||
func imageData(c *cli.Context, runtime *libpod.Runtime, image string) (string, string, *inspect.ImageData, error) {
|
||||
var (
|
||||
err error
|
||||
imageName, imageID string
|
||||
)
|
||||
// Deal with the image after all the args have been checked
|
||||
createImage := runtime.NewImage(image)
|
||||
imageName, imageID, _ = createImage.GetLocalImageName()
|
||||
if createImage.LocalName == "" {
|
||||
// The image wasnt found by the user input'd name or its fqname
|
||||
// Pull the image
|
||||
var writer io.Writer
|
||||
if !c.Bool("quiet") {
|
||||
writer = os.Stderr
|
||||
}
|
||||
createImage.Pull(writer)
|
||||
}
|
||||
|
||||
createImage.LocalName = imageName
|
||||
if imageName == "" {
|
||||
imageName, err = createImage.GetFQName()
|
||||
_, imageID, _ = createImage.GetLocalImageName()
|
||||
}
|
||||
if err != nil {
|
||||
return "", "", nil, err
|
||||
}
|
||||
storageImage, err := runtime.GetImage(imageName)
|
||||
if err != nil {
|
||||
return "", "", nil, errors.Wrapf(err, "error getting storage image %q", image)
|
||||
}
|
||||
data, err := runtime.GetImageInspectInfo(*storageImage)
|
||||
if err != nil {
|
||||
return "", "", nil, errors.Wrapf(err, "error parsing image data %q", image)
|
||||
}
|
||||
return imageName, imageID, data, err
|
||||
}
|
||||
|
||||
// Parses CLI options related to container creation into a config which can be
|
||||
// parsed into an OCI runtime spec
|
||||
func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*createConfig, error) {
|
||||
|
@ -98,8 +98,11 @@ func historyCmd(c *cli.Context) error {
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("podman history takes at most 1 argument")
|
||||
}
|
||||
imgName := args[0]
|
||||
|
||||
image, err := runtime.ImageRuntime().NewFromLocal(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts := historyOptions{
|
||||
human: c.BoolT("human"),
|
||||
noTrunc: c.Bool("no-trunc"),
|
||||
@ -107,12 +110,12 @@ func historyCmd(c *cli.Context) error {
|
||||
format: format,
|
||||
}
|
||||
|
||||
history, layers, imageID, err := runtime.GetHistory(imgName)
|
||||
history, layers, err := image.History()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting history of image %q", imgName)
|
||||
return errors.Wrapf(err, "error getting history of image %q", image.InputName)
|
||||
}
|
||||
|
||||
return generateHistoryOutput(history, layers, imageID, opts)
|
||||
return generateHistoryOutput(history, layers, image.ID(), opts)
|
||||
}
|
||||
|
||||
func genHistoryFormat(format string, quiet bool) string {
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@ -55,8 +55,12 @@ func importCmd(c *cli.Context) error {
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
var opts libpod.CopyOptions
|
||||
var source string
|
||||
var (
|
||||
source string
|
||||
reference string
|
||||
writer io.Writer
|
||||
)
|
||||
|
||||
args := c.Args()
|
||||
switch len(args) {
|
||||
case 0:
|
||||
@ -65,7 +69,7 @@ func importCmd(c *cli.Context) error {
|
||||
source = args[0]
|
||||
case 2:
|
||||
source = args[0]
|
||||
opts.Reference = args[1]
|
||||
reference = args[1]
|
||||
default:
|
||||
return errors.Errorf("too many arguments. Usage TARBALL [REFERENCE]")
|
||||
}
|
||||
@ -87,11 +91,9 @@ func importCmd(c *cli.Context) error {
|
||||
History: history,
|
||||
}
|
||||
|
||||
opts.ImageConfig = config
|
||||
opts.Writer = nil
|
||||
|
||||
writer = nil
|
||||
if !c.Bool("quiet") {
|
||||
opts.Writer = os.Stderr
|
||||
writer = os.Stderr
|
||||
}
|
||||
|
||||
// if source is a url, download it and save to a temp file
|
||||
@ -105,9 +107,9 @@ func importCmd(c *cli.Context) error {
|
||||
source = file
|
||||
}
|
||||
|
||||
img, err := runtime.ImportImage(source, opts)
|
||||
newImage, err := runtime.Import(source, reference, writer, image.SigningOptions{}, config)
|
||||
if err == nil {
|
||||
fmt.Println(img.ID)
|
||||
fmt.Println(newImage.ID())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -128,31 +128,27 @@ func iterateInput(c *cli.Context, args []string, runtime *libpod.Runtime, inspec
|
||||
break
|
||||
}
|
||||
case inspectTypeImage:
|
||||
newImage := runtime.NewImage(input)
|
||||
newImage.GetLocalImageName()
|
||||
image, err := runtime.GetImage(newImage.LocalName)
|
||||
image, err := runtime.ImageRuntime().NewFromLocal(input)
|
||||
if err != nil {
|
||||
inspectError = errors.Wrapf(err, "error getting image %q", input)
|
||||
break
|
||||
}
|
||||
data, err = runtime.GetImageInspectInfo(*image)
|
||||
data, err = libpod.GetImageData(image)
|
||||
if err != nil {
|
||||
inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID)
|
||||
inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID())
|
||||
break
|
||||
}
|
||||
case inspectAll:
|
||||
ctr, err := runtime.LookupContainer(input)
|
||||
if err != nil {
|
||||
newImage := runtime.NewImage(input)
|
||||
newImage.GetLocalImageName()
|
||||
image, err := runtime.GetImage(newImage.LocalName)
|
||||
image, err := runtime.ImageRuntime().NewFromLocal(input)
|
||||
if err != nil {
|
||||
inspectError = errors.Wrapf(err, "error getting image %q", input)
|
||||
break
|
||||
}
|
||||
data, err = runtime.GetImageInspectInfo(*image)
|
||||
data, err = libpod.GetImageData(image)
|
||||
if err != nil {
|
||||
inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID)
|
||||
inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID())
|
||||
break
|
||||
}
|
||||
} else {
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@ -51,28 +52,37 @@ func rmiCmd(c *cli.Context) error {
|
||||
return errors.Errorf("when using the --all switch, you may not pass any images names or IDs")
|
||||
}
|
||||
|
||||
imagesToDelete := args[:]
|
||||
images := args[:]
|
||||
var lastError error
|
||||
var imagesToDelete []*image.Image
|
||||
if removeAll {
|
||||
localImages, err := runtime.GetImages(&libpod.ImageFilterParams{})
|
||||
imagesToDelete, err = runtime.GetImages(&libpod.ImageFilterParams{})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to query local images")
|
||||
}
|
||||
for _, image := range localImages {
|
||||
imagesToDelete = append(imagesToDelete, image.ID)
|
||||
} else {
|
||||
// Create image.image objects for deletion from user input
|
||||
for _, i := range images {
|
||||
newImage, err := runtime.ImageRuntime().NewFromLocal(i)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
continue
|
||||
}
|
||||
imagesToDelete = append(imagesToDelete, newImage)
|
||||
}
|
||||
}
|
||||
|
||||
for _, arg := range imagesToDelete {
|
||||
image := runtime.NewImage(arg)
|
||||
iid, err := image.Remove(c.Bool("force"))
|
||||
if len(imagesToDelete) == 0 {
|
||||
return errors.Errorf("no valid images to delete")
|
||||
}
|
||||
for _, img := range imagesToDelete {
|
||||
err := runtime.RemoveImage(img, c.Bool("force"))
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = err
|
||||
} else {
|
||||
fmt.Println(iid)
|
||||
fmt.Println(img.ID())
|
||||
}
|
||||
}
|
||||
return lastError
|
||||
|
@ -7,8 +7,10 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
)
|
||||
|
||||
var runDescription = "Runs a command in a new container from the given image"
|
||||
@ -49,12 +51,15 @@ func runCmd(c *cli.Context) error {
|
||||
return errors.Errorf("image name or ID is required")
|
||||
}
|
||||
|
||||
imageName, _, data, err := imageData(c, runtime, c.Args()[0])
|
||||
rtc := runtime.GetConfig()
|
||||
newImage, err := runtime.ImageRuntime().New(c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{})
|
||||
|
||||
data, err := libpod.GetImageData(newImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createConfig, err := parseCreateOpts(c, runtime, imageName, data)
|
||||
createConfig, err := parseCreateOpts(c, runtime, newImage.Names()[0], data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1,16 +1,18 @@
|
||||
package libpod
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage"
|
||||
"github.com/docker/docker/daemon/caps"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod/driver"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/projectatomic/libpod/pkg/inspect"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
@ -532,7 +534,7 @@ func (c *Container) Inspect(size bool) (*inspect.ContainerInspectData, error) {
|
||||
|
||||
// Commit commits the changes between a container and its image, creating a new
|
||||
// image
|
||||
func (c *Container) Commit(pause bool, options CopyOptions) (*storage.Image, error) {
|
||||
func (c *Container) Commit(pause bool, reference string, writer io.Writer, signingOptions image.SigningOptions, imageConfig ociv1.Image) (*image.Image, error) {
|
||||
if !c.locked {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
@ -563,7 +565,7 @@ func (c *Container) Commit(pause bool, options CopyOptions) (*storage.Image, err
|
||||
if err := c.export(tempFile.Name()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.runtime.ImportImage(tempFile.Name(), options)
|
||||
return image.Import(tempFile.Name(), reference, writer, signingOptions, imageConfig, c.runtime.imageRuntime)
|
||||
}
|
||||
|
||||
// Wait blocks on a container to exit and returns its exit code
|
||||
|
@ -926,16 +926,14 @@ func (c *Container) addImageVolumes(g *generate.Generator) error {
|
||||
if !c.state.Mounted {
|
||||
return errors.Wrapf(ErrInternal, "container is not mounted")
|
||||
}
|
||||
|
||||
imageStorage, err := c.runtime.getImage(c.config.RootfsImageID)
|
||||
newImage, err := c.runtime.imageRuntime.NewFromLocal(c.config.RootfsImageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageData, err := c.runtime.getImageInspectInfo(*imageStorage)
|
||||
imageData, err := GetImageData(newImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k := range imageData.ContainerConfig.Volumes {
|
||||
mount := spec.Mount{
|
||||
Destination: k,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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...)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -4,18 +4,22 @@ import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/storage"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/projectatomic/libpod/pkg/inspect"
|
||||
)
|
||||
|
||||
func getImageData(img storage.Image, imgRef types.Image, size int64, driver *inspect.Data) (*inspect.ImageData, error) {
|
||||
imgSize, err := imgRef.Size()
|
||||
// GetImageData returns an image's inspect data
|
||||
func GetImageData(img *image.Image) (*inspect.ImageData, error) {
|
||||
imgRef, err := img.ToImageRef()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error reading size of image %q", img.ID)
|
||||
return nil, err
|
||||
}
|
||||
size, err := imgRef.Size()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
manifest, manifestType, err := imgRef.Manifest()
|
||||
if err != nil {
|
||||
@ -37,13 +41,17 @@ func getImageData(img storage.Image, imgRef types.Image, size int64, driver *ins
|
||||
}
|
||||
|
||||
var repoDigests []string
|
||||
for _, name := range img.Names {
|
||||
for _, name := range img.Names() {
|
||||
repoDigests = append(repoDigests, strings.SplitN(name, ":", 2)[0]+"@"+imgDigest.String())
|
||||
}
|
||||
|
||||
driver, err := img.DriverData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := &inspect.ImageData{
|
||||
ID: img.ID,
|
||||
RepoTags: img.Names,
|
||||
ID: img.ID(),
|
||||
RepoTags: img.Names(),
|
||||
RepoDigests: repoDigests,
|
||||
Comment: ociv1Img.History[0].Comment,
|
||||
Created: ociv1Img.Created,
|
||||
@ -53,7 +61,7 @@ func getImageData(img storage.Image, imgRef types.Image, size int64, driver *ins
|
||||
ContainerConfig: &ociv1Img.Config,
|
||||
Version: info.DockerVersion,
|
||||
Size: size,
|
||||
VirtualSize: size + imgSize,
|
||||
VirtualSize: size,
|
||||
Annotations: annotations,
|
||||
Digest: imgDigest,
|
||||
Labels: info.Labels,
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/containers/storage"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/libpod/image"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/ulule/deepcopier"
|
||||
)
|
||||
@ -69,6 +70,7 @@ type Runtime struct {
|
||||
conmonPath string
|
||||
valid bool
|
||||
lock sync.RWMutex
|
||||
imageRuntime *image.Runtime
|
||||
}
|
||||
|
||||
// RuntimeConfig contains configuration options used to set up the runtime
|
||||
@ -194,11 +196,9 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
|
||||
return nil, errors.Wrapf(err, "error configuring runtime")
|
||||
}
|
||||
}
|
||||
|
||||
if err := makeRuntime(runtime); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return runtime, nil
|
||||
}
|
||||
|
||||
@ -293,8 +293,20 @@ func makeRuntime(runtime *Runtime) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime.store = store
|
||||
is.Transport.SetStore(store)
|
||||
|
||||
// Set up image runtime and store in runtime
|
||||
ir := image.NewImageRuntimeFromStore(runtime.store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime.imageRuntime = ir
|
||||
|
||||
// Setting signaturepolicypath
|
||||
ir.SignaturePolicyPath = runtime.config.SignaturePolicyPath
|
||||
defer func() {
|
||||
if err != nil {
|
||||
// Don't forcibly shut down
|
||||
@ -576,3 +588,8 @@ func SaveDefaultConfig(path string) error {
|
||||
|
||||
return ioutil.WriteFile(path, w.Bytes(), 0644)
|
||||
}
|
||||
|
||||
// ImageRuntime returns the imageruntime for image resolution
|
||||
func (r *Runtime) ImageRuntime() *image.Runtime {
|
||||
return r.imageRuntime
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
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/libpod/image"
|
||||
"github.com/projectatomic/libpod/pkg/inspect"
|
||||
"github.com/projectatomic/libpod/pkg/util"
|
||||
)
|
||||
@ -152,7 +152,7 @@ func (r *Runtime) IsImageID(input string) (bool, error) {
|
||||
return false, errors.Wrapf(err, "unable to get images")
|
||||
}
|
||||
for _, image := range images {
|
||||
if strings.HasPrefix(image.ID, input) {
|
||||
if strings.HasPrefix(image.ID(), input) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
@ -167,8 +167,8 @@ func (k *Image) GetNameByID() (string, error) {
|
||||
return "", errors.Wrapf(err, "unable to get images")
|
||||
}
|
||||
for _, image := range images {
|
||||
if strings.HasPrefix(image.ID, k.Name) {
|
||||
return image.Names[0], nil
|
||||
if strings.HasPrefix(image.ID(), k.Name) {
|
||||
return image.Names()[0], nil
|
||||
}
|
||||
}
|
||||
return "", errors.Errorf("unable to determine image for %s", k.Name)
|
||||
@ -196,13 +196,13 @@ func (k *Image) GetImageID() (string, error) {
|
||||
}
|
||||
for _, image := range images {
|
||||
// Check if we have an ID match
|
||||
if strings.HasPrefix(image.ID, k.Name) {
|
||||
return image.ID, nil
|
||||
if strings.HasPrefix(image.ID(), k.Name) {
|
||||
return image.ID(), nil
|
||||
}
|
||||
// Check if we have a name match, perhaps a tagged name
|
||||
for _, name := range image.Names {
|
||||
for _, name := range image.Names() {
|
||||
if k.Name == name {
|
||||
return image.ID, nil
|
||||
return image.ID(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -364,7 +364,7 @@ func (k *Image) GetLocalImageName() (string, string, error) {
|
||||
return "", "", err
|
||||
}
|
||||
for _, image := range localImages {
|
||||
for _, name := range image.Names {
|
||||
for _, name := range image.Names() {
|
||||
imgRef, err := reference.Parse(name)
|
||||
if err != nil {
|
||||
continue
|
||||
@ -383,13 +383,13 @@ func (k *Image) GetLocalImageName() (string, string, error) {
|
||||
|
||||
if imageName == k.Name {
|
||||
k.LocalName = name
|
||||
return name, image.ID, nil
|
||||
return name, image.ID(), nil
|
||||
}
|
||||
imageSplit := strings.Split(imageName, "/")
|
||||
baseName := imageSplit[len(imageSplit)-1]
|
||||
if baseName == k.Name {
|
||||
k.LocalName = name
|
||||
return name, image.ID, nil
|
||||
return name, image.ID(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -431,26 +431,6 @@ func (k *Image) Pull(writer io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove calls into container storage and deletes the image
|
||||
func (k *Image) Remove(force bool) (string, error) {
|
||||
if k.LocalName == "" {
|
||||
// This populates the images local name
|
||||
_, _, err := k.GetLocalImageName()
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "unable to find %s locally", k.Name)
|
||||
}
|
||||
}
|
||||
iid, err := k.GetImageID()
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "unable to get image id")
|
||||
}
|
||||
image, err := k.runtime.GetImage(iid)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "unable to remove %s", iid)
|
||||
}
|
||||
return k.runtime.RemoveImage(image, force)
|
||||
}
|
||||
|
||||
// GetRegistries gets the searchable registries from the global registration file.
|
||||
func GetRegistries() ([]string, error) {
|
||||
registryConfigPath := ""
|
||||
@ -497,7 +477,7 @@ func getRegistries() ([]string, error) {
|
||||
// ImageFilter is a function to determine whether an image is included in
|
||||
// command output. Images to be outputted are tested using the function. A true
|
||||
// return will include the image, a false return will exclude it.
|
||||
type ImageFilter func(*storage.Image, *inspect.ImageData) bool
|
||||
type ImageFilter func(*image.Image, *inspect.ImageData) bool
|
||||
|
||||
func (ips imageDecomposeStruct) returnFQName() string {
|
||||
return fmt.Sprintf("%s%s/%s:%s", ips.transport, ips.registry, ips.imageName, ips.tag)
|
||||
@ -854,50 +834,52 @@ func (r *Runtime) UntagImage(image *storage.Image, tag string) (string, error) {
|
||||
|
||||
// RemoveImage deletes an image from local storage
|
||||
// Images being used by running containers can only be removed if force=true
|
||||
func (r *Runtime) RemoveImage(image *storage.Image, force bool) (string, error) {
|
||||
func (r *Runtime) RemoveImage(image *image.Image, force bool) error {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
|
||||
if !r.valid {
|
||||
return "", ErrRuntimeStopped
|
||||
return ErrRuntimeStopped
|
||||
}
|
||||
|
||||
// Get all containers, filter to only those using the image, and remove those containers
|
||||
ctrs, err := r.state.AllContainers()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
imageCtrs := []*Container{}
|
||||
for _, ctr := range ctrs {
|
||||
if ctr.config.RootfsImageID == image.ID {
|
||||
if ctr.config.RootfsImageID == image.ID() {
|
||||
imageCtrs = append(imageCtrs, ctr)
|
||||
}
|
||||
}
|
||||
if len(imageCtrs) > 0 && len(image.Names) <= 1 {
|
||||
if len(imageCtrs) > 0 && len(image.Names()) <= 1 {
|
||||
if force {
|
||||
for _, ctr := range imageCtrs {
|
||||
if err := r.removeContainer(ctr, true); err != nil {
|
||||
return "", errors.Wrapf(err, "error removing image %s: container %s using image could not be removed", image.ID, ctr.ID())
|
||||
return errors.Wrapf(err, "error removing image %s: container %s using image could not be removed", image.ID, ctr.ID())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "", fmt.Errorf("could not remove image %s as it is being used by %d containers", image.ID, len(imageCtrs))
|
||||
return fmt.Errorf("could not remove image %s as it is being used by %d containers", image.ID, len(imageCtrs))
|
||||
}
|
||||
}
|
||||
|
||||
if len(image.Names) > 1 && !force {
|
||||
return "", fmt.Errorf("unable to delete %s (must force) - image is referred to in multiple tags", image.ID)
|
||||
if len(image.Names()) > 1 && !force {
|
||||
return fmt.Errorf("unable to delete %s (must force) - image is referred to in multiple tags", image.ID)
|
||||
}
|
||||
|
||||
// If it is forced, we have to untag the image so that it can be deleted
|
||||
if err = r.store.SetNames(image.ID, image.Names[:0]); err != nil {
|
||||
return "", err
|
||||
if len(image.Names()) > 1 && force {
|
||||
// If it is forced, we have to untag the image so that it can be deleted
|
||||
if err = r.store.SetNames(image.ID(), image.Names()[:0]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = r.store.DeleteImage(image.ID, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
if err = image.Remove(force); err != nil {
|
||||
return err
|
||||
}
|
||||
return image.ID, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetImage retrieves an image matching the given name or hash from system
|
||||
@ -964,7 +946,7 @@ func (r *Runtime) getImageRef(image string) (types.Image, error) {
|
||||
// Filters can be provided which will determine which images are included in the
|
||||
// output. Multiple filters are handled by ANDing their output, so only images
|
||||
// matching all filters are included
|
||||
func (r *Runtime) GetImages(params *ImageFilterParams, filters ...ImageFilter) ([]*storage.Image, error) {
|
||||
func (r *Runtime) GetImages(params *ImageFilterParams, filters ...ImageFilter) ([]*image.Image, error) {
|
||||
r.lock.RLock()
|
||||
defer r.lock.RUnlock()
|
||||
|
||||
@ -972,21 +954,21 @@ func (r *Runtime) GetImages(params *ImageFilterParams, filters ...ImageFilter) (
|
||||
return nil, ErrRuntimeStopped
|
||||
}
|
||||
|
||||
images, err := r.store.Images()
|
||||
images, err := r.imageRuntime.GetImages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var imagesFiltered []*storage.Image
|
||||
var imagesFiltered []*image.Image
|
||||
|
||||
for _, img := range images {
|
||||
info, err := r.getImageInspectInfo(img)
|
||||
info, err := GetImageData(img)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var names []string
|
||||
if len(img.Names) > 0 {
|
||||
names = img.Names
|
||||
if len(img.Names()) > 0 {
|
||||
names = img.Names()
|
||||
} else {
|
||||
names = append(names, "<none>")
|
||||
}
|
||||
@ -996,13 +978,14 @@ func (r *Runtime) GetImages(params *ImageFilterParams, filters ...ImageFilter) (
|
||||
params.ImageName = name
|
||||
}
|
||||
for _, filter := range filters {
|
||||
include = include && filter(&img, info)
|
||||
include = include && filter(img, info)
|
||||
}
|
||||
|
||||
if include {
|
||||
newImage := img
|
||||
newImage.Names = []string{name}
|
||||
imagesFiltered = append(imagesFiltered, &newImage)
|
||||
// TODO I dont think this is needed. Will verify along the way
|
||||
//newImage.Names = []string{name}
|
||||
imagesFiltered = append(imagesFiltered, newImage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1037,92 +1020,9 @@ func (r *Runtime) GetHistory(image string) ([]ociv1.History, []types.BlobInfo, s
|
||||
return oci.History, src.LayerInfos(), img.ID, nil
|
||||
}
|
||||
|
||||
// ImportImage imports an OCI format image archive into storage as an image
|
||||
func (r *Runtime) ImportImage(path string, options CopyOptions) (*storage.Image, error) {
|
||||
r.lock.RLock()
|
||||
defer r.lock.RUnlock()
|
||||
|
||||
if !r.valid {
|
||||
return nil, ErrRuntimeStopped
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
err = updater.ConfigUpdate(options.ImageConfig, annotations)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error updating image config")
|
||||
}
|
||||
|
||||
var reference = options.Reference
|
||||
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 := common.GetCopyOptions(options.Writer, "", nil, nil, common.SigningOptions{}, "", "", false)
|
||||
|
||||
dest, err := is.Transport.ParseStoreReference(r.store, reference)
|
||||
if err != nil {
|
||||
errors.Wrapf(err, "error getting image reference for %q", options.Reference)
|
||||
}
|
||||
if err = cp.Image(policyContext, dest, src, copyOptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Use no lock version of GetImage
|
||||
return r.getImage(reference)
|
||||
}
|
||||
|
||||
// GetImageInspectInfo returns the inspect information of an image
|
||||
func (r *Runtime) GetImageInspectInfo(image storage.Image) (*inspect.ImageData, error) {
|
||||
r.lock.RLock()
|
||||
defer r.lock.RUnlock()
|
||||
|
||||
if !r.valid {
|
||||
return nil, ErrRuntimeStopped
|
||||
}
|
||||
return r.getImageInspectInfo(image)
|
||||
}
|
||||
|
||||
func (r *Runtime) getImageInspectInfo(image storage.Image) (*inspect.ImageData, error) {
|
||||
imgRef, err := r.getImageRef("@" + image.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error reading image %q", image.ID)
|
||||
}
|
||||
|
||||
layer, err := r.store.Layer(image.TopLayer)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error reading information about layer %q", image.TopLayer)
|
||||
}
|
||||
size, err := r.store.DiffSize(layer.Parent, layer.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error determining size of layer %q", layer.ID)
|
||||
}
|
||||
driverData, err := driver.GetDriverData(r.store, layer.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error getting graph driver info %q", image.ID)
|
||||
}
|
||||
return getImageData(image, imgRef, size, driverData)
|
||||
//Import imports an oci format image archive into storage as an image
|
||||
func (r *Runtime) Import(path, reference string, writer io.Writer, signingOptions image.SigningOptions, imageConfig ociv1.Image) (*image.Image, error) {
|
||||
return image.Import(path, reference, writer, signingOptions, imageConfig, r.imageRuntime)
|
||||
}
|
||||
|
||||
// ParseImageFilter takes a set of images and a filter string as input, and returns the libpod.ImageFilterParams struct
|
||||
@ -1145,7 +1045,7 @@ func (r *Runtime) ParseImageFilter(imageInput, filter string) (*ImageFilterParam
|
||||
return ¶ms, nil
|
||||
}
|
||||
|
||||
images, err := r.store.Images()
|
||||
images, err := r.imageRuntime.GetImages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1164,7 +1064,7 @@ func (r *Runtime) ParseImageFilter(imageInput, filter string) (*ImageFilterParam
|
||||
params.Label = pair[1]
|
||||
case "before":
|
||||
if img, err := findImageInSlice(images, pair[1]); err == nil {
|
||||
info, err := r.GetImageInspectInfo(img)
|
||||
info, err := GetImageData(img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1174,7 +1074,7 @@ func (r *Runtime) ParseImageFilter(imageInput, filter string) (*ImageFilterParam
|
||||
}
|
||||
case "since":
|
||||
if img, err := findImageInSlice(images, pair[1]); err == nil {
|
||||
info, err := r.GetImageInspectInfo(img)
|
||||
info, err := GetImageData(img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1240,18 +1140,18 @@ func ParseImageNames(names []string) (tags, digests []string, err error) {
|
||||
return tags, digests, nil
|
||||
}
|
||||
|
||||
func findImageInSlice(images []storage.Image, ref string) (storage.Image, error) {
|
||||
func findImageInSlice(images []*image.Image, ref string) (*image.Image, error) {
|
||||
for _, image := range images {
|
||||
if MatchesID(image.ID, ref) {
|
||||
if MatchesID(image.ID(), ref) {
|
||||
return image, nil
|
||||
}
|
||||
for _, name := range image.Names {
|
||||
for _, name := range image.Names() {
|
||||
if MatchesReference(name, ref) {
|
||||
return image, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return storage.Image{}, errors.New("could not find image")
|
||||
return nil, errors.New("could not find image")
|
||||
}
|
||||
|
||||
// getImageDigest creates an image object and uses the hex value of the digest as the image ID
|
||||
|
@ -140,7 +140,7 @@ var _ = Describe("Podman pull", func() {
|
||||
clean.WaitWithDefaultTimeout()
|
||||
})
|
||||
|
||||
It("podman pull from local directory", func() {
|
||||
It("podman pull check quiet", func() {
|
||||
podmanTest.RestoreArtifact(ALPINE)
|
||||
setup := podmanTest.Podman([]string{"images", ALPINE, "-q", "--no-trunc"})
|
||||
setup.WaitWithDefaultTimeout()
|
||||
|
Reference in New Issue
Block a user