From 9d883d2032b112d5c65040629313cfba0de6c479 Mon Sep 17 00:00:00 2001 From: baude Date: Sun, 25 Nov 2018 16:26:39 -0600 Subject: add podman container|image exists Add an exists subcommand to podman container and podman image that allows users to verify the existence of a container or image by ID or name. The return code can be 0 (success), 1 (failed to find), or 125 (failed to work with runtime). Issue #1845 Signed-off-by: baude --- cmd/podman/container.go | 1 + cmd/podman/exists.go | 83 ++++++++++++++++++++++++++++++++++++++ cmd/podman/image.go | 1 + completions/bash/podman | 16 ++++++++ docs/podman-container-exists.1.md | 40 ++++++++++++++++++ docs/podman-container.1.md | 1 + docs/podman-image-exists.1.md | 40 ++++++++++++++++++ docs/podman-image.1.md | 1 + libpod/image/errors.go | 15 +++++++ libpod/image/image.go | 4 +- test/e2e/exists_test.go | 85 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 cmd/podman/exists.go create mode 100644 docs/podman-container-exists.1.md create mode 100644 docs/podman-image-exists.1.md create mode 100644 libpod/image/errors.go create mode 100644 test/e2e/exists_test.go diff --git a/cmd/podman/container.go b/cmd/podman/container.go index ff634278f..b6262f890 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -9,6 +9,7 @@ var ( attachCommand, checkpointCommand, cleanupCommand, + containerExistsCommand, commitCommand, createCommand, diffCommand, diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go new file mode 100644 index 000000000..2f7b7c185 --- /dev/null +++ b/cmd/podman/exists.go @@ -0,0 +1,83 @@ +package main + +import ( + "os" + + "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var ( + imageExistsDescription = ` + podman image exists + + Check if an image exists in local storage +` + + imageExistsCommand = cli.Command{ + Name: "exists", + Usage: "Check if an image exists in local storage", + Description: imageExistsDescription, + Action: imageExistsCmd, + ArgsUsage: "IMAGE-NAME", + OnUsageError: usageErrorHandler, + } +) + +var ( + containerExistsDescription = ` + podman container exists + + Check if a container exists in local storage +` + + containerExistsCommand = cli.Command{ + Name: "exists", + Usage: "Check if a container exists in local storage", + Description: containerExistsDescription, + Action: containerExistsCmd, + ArgsUsage: "CONTAINER-NAME", + OnUsageError: usageErrorHandler, + } +) + +func imageExistsCmd(c *cli.Context) error { + args := c.Args() + if len(args) > 1 || len(args) < 1 { + return errors.New("you may only check for the existence of one image at a time") + } + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + if _, err := runtime.ImageRuntime().NewFromLocal(args[0]); err != nil { + if errors.Cause(err) == image.ErrNoSuchImage { + os.Exit(1) + } + return err + } + return nil +} + +func containerExistsCmd(c *cli.Context) error { + args := c.Args() + if len(args) > 1 || len(args) < 1 { + return errors.New("you may only check for the existence of one container at a time") + } + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + if _, err := runtime.LookupContainer(args[0]); err != nil { + if errors.Cause(err) == libpod.ErrNoSuchCtr { + os.Exit(1) + } + return err + } + return nil +} diff --git a/cmd/podman/image.go b/cmd/podman/image.go index e67f61799..418b442e3 100644 --- a/cmd/podman/image.go +++ b/cmd/podman/image.go @@ -9,6 +9,7 @@ var ( buildCommand, historyCommand, importCommand, + imageExistsCommand, inspectCommand, loadCommand, lsImagesCommand, diff --git a/completions/bash/podman b/completions/bash/podman index 8eaa1e6a9..3c6b6ec50 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2178,6 +2178,22 @@ _podman_container_runlabel() { esac } +_podman_container_exists() { + local options_with_args=" + " + + local boolean_options=" + " +} + +_podman_image_exists() { + local options_with_args=" + " + + local boolean_options=" + " +} + _podman_pod_create() { local options_with_args=" --cgroup-parent diff --git a/docs/podman-container-exists.1.md b/docs/podman-container-exists.1.md new file mode 100644 index 000000000..76701e2c2 --- /dev/null +++ b/docs/podman-container-exists.1.md @@ -0,0 +1,40 @@ +% PODMAN(1) Podman Man Pages +% Brent Baude +% November 2018 +# NAME +podman-container-exists- Check if a container exists in local storage + +# SYNOPSIS +**podman container exists** +[**-h**|**--help**] +CONTAINER + +# DESCRIPTION +**podman container exists** checks if a container exists in local storage. The **ID** or **Name** +of the container may be used as input. Podman will return an exit code +of `0` when the container is found. A `1` will be returned otherwise. An exit code of `125` indicates there +was an issue accessing the local storage. + +## Examples ## + +Check if an container called `webclient` exists in local storage (the container does actually exist). +``` +$ sudo podman container exists webclient +$ echo $? +0 +$ +``` + +Check if an container called `webbackend` exists in local storage (the container does not actually exist). +``` +$ sudo podman container exists webbackend +$ echo $? +1 +$ +``` + +## SEE ALSO +podman(1) + +# HISTORY +November 2018, Originally compiled by Brent Baude (bbaude at redhat dot com) diff --git a/docs/podman-container.1.md b/docs/podman-container.1.md index 67d42bfef..aa5dfa82c 100644 --- a/docs/podman-container.1.md +++ b/docs/podman-container.1.md @@ -20,6 +20,7 @@ The container command allows you to manage containers | create | [podman-create(1)](podman-create.1.md) | Create a new container. | | diff | [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. | | exec | [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. | +| exists | [podman-exists(1)](podman-container-exists.1.md) | Check if a container exists in local storage | | export | [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. | | inspect | [podman-inspect(1)](podman-inspect.1.md) | Display a container or image's configuration. | | kill | [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. | diff --git a/docs/podman-image-exists.1.md b/docs/podman-image-exists.1.md new file mode 100644 index 000000000..e04c23721 --- /dev/null +++ b/docs/podman-image-exists.1.md @@ -0,0 +1,40 @@ +% PODMAN(1) Podman Man Pages +% Brent Baude +% November 2018 +# NAME +podman-image-exists- Check if an image exists in local storage + +# SYNOPSIS +**podman image exists** +[**-h**|**--help**] +IMAGE + +# DESCRIPTION +**podman image exists** checks if an image exists in local storage. The **ID** or **Name** +of the image may be used as input. Podman will return an exit code +of `0` when the image is found. A `1` will be returned otherwise. An exit code of `125` indicates there +was an issue accessing the local storage. + +## Examples ## + +Check if an image called `webclient` exists in local storage (the image does actually exist). +``` +$ sudo podman image exists webclient +$ echo $? +0 +$ +``` + +Check if an image called `webbackend` exists in local storage (the image does not actually exist). +``` +$ sudo podman image exists webbackend +$ echo $? +1 +$ +``` + +## SEE ALSO +podman(1) + +# HISTORY +November 2018, Originally compiled by Brent Baude (bbaude at redhat dot com) diff --git a/docs/podman-image.1.md b/docs/podman-image.1.md index 33de0456f..446f8667d 100644 --- a/docs/podman-image.1.md +++ b/docs/podman-image.1.md @@ -14,6 +14,7 @@ The image command allows you to manage images | Command | Man Page | Description | | -------- | ----------------------------------------- | ------------------------------------------------------------------------------ | | build | [podman-build(1)](podman-build.1.md) | Build a container using a Dockerfile. | +| exists | [podman-exists(1)](podman-image-exists.1.md) | Check if a image exists in local storage | | history | [podman-history(1)](podman-history.1.md) | Show the history of an image. | | import | [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. | | inspect | [podman-inspect(1)](podman-inspect.1.md) | Display a image or image's configuration. | diff --git a/libpod/image/errors.go b/libpod/image/errors.go new file mode 100644 index 000000000..4088946cb --- /dev/null +++ b/libpod/image/errors.go @@ -0,0 +1,15 @@ +package image + +import ( + "errors" +) + +// Copied directly from libpod errors to avoid circular imports +var ( + // ErrNoSuchCtr indicates the requested container does not exist + ErrNoSuchCtr = errors.New("no such container") + // ErrNoSuchPod indicates the requested pod does not exist + ErrNoSuchPod = errors.New("no such pod") + // ErrNoSuchImage indicates the requested image does not exist + ErrNoSuchImage = errors.New("no such image") +) diff --git a/libpod/image/image.go b/libpod/image/image.go index 7e520d97e..a05c15160 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -252,7 +252,7 @@ func (i *Image) getLocalImage() (*storage.Image, error) { // The image has a registry name in it and we made sure we looked for it locally // with a tag. It cannot be local. if decomposedImage.hasRegistry { - return nil, errors.Errorf("%s", imageError) + return nil, errors.Wrapf(ErrNoSuchImage, imageError) } @@ -275,7 +275,7 @@ func (i *Image) getLocalImage() (*storage.Image, error) { return repoImage, nil } - return nil, errors.Wrapf(err, imageError) + return nil, errors.Wrapf(ErrNoSuchImage, err.Error()) } // ID returns the image ID as a string diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go new file mode 100644 index 000000000..9165e8902 --- /dev/null +++ b/test/e2e/exists_test.go @@ -0,0 +1,85 @@ +package integration + +import ( + "fmt" + "os" + + . "github.com/containers/libpod/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman image|container exists", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.RestoreAllArtifacts() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()) + GinkgoWriter.Write([]byte(timedResult)) + + }) + It("podman image exists in local storage by fq name", func() { + session := podmanTest.Podman([]string{"image", "exists", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman image exists in local storage by short name", func() { + session := podmanTest.Podman([]string{"image", "exists", "alpine"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman image does not exist in local storage", func() { + session := podmanTest.Podman([]string{"image", "exists", "alpine9999"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) + It("podman container exists in local storage by name", func() { + setup := podmanTest.RunTopContainer("foobar") + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"container", "exists", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman container exists in local storage by container ID", func() { + setup := podmanTest.RunTopContainer("") + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + cid := setup.OutputToString() + + session := podmanTest.Podman([]string{"container", "exists", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman container exists in local storage by short container ID", func() { + setup := podmanTest.RunTopContainer("") + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + cid := setup.OutputToString()[0:12] + + session := podmanTest.Podman([]string{"container", "exists", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman container does not exist in local storage", func() { + session := podmanTest.Podman([]string{"container", "exists", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) + +}) -- cgit v1.2.3-54-g00ecf