summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSascha Grunert <sgrunert@suse.com>2019-12-16 13:28:16 +0100
committerSascha Grunert <sgrunert@suse.com>2020-01-08 10:06:10 +0100
commit40b74e02b77e83c377fdae83f626f83403b38152 (patch)
treec71e9d5c4cd1c1517006368c151b81c4ea5d4077
parentc41fd09a8da3a96bc0e58f9f29f87b9bdf30264d (diff)
downloadpodman-40b74e02b77e83c377fdae83f626f83403b38152.tar.gz
podman-40b74e02b77e83c377fdae83f626f83403b38152.tar.bz2
podman-40b74e02b77e83c377fdae83f626f83403b38152.zip
Add `untag` sub-command
Podman now supports untagging images via the `untag` sub-command for the root and `image` commands. Testing and documentation has been added as well. Signed-off-by: Sascha Grunert <sgrunert@suse.com>
-rwxr-xr-xAPI.md10
-rw-r--r--cmd/podman/cliconfig/config.go4
-rw-r--r--cmd/podman/image.go1
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/untag.go67
-rw-r--r--cmd/podman/varlink/io.podman.varlink6
-rw-r--r--docs/source/markdown/links/podman-image-untag.11
-rw-r--r--docs/source/markdown/podman-image.1.md1
-rw-r--r--docs/source/markdown/podman-untag.1.md37
-rw-r--r--docs/source/markdown/podman.1.md1
-rw-r--r--pkg/adapter/runtime_remote.go6
-rw-r--r--pkg/varlinkapi/images.go12
-rw-r--r--test/e2e/untag_test.go73
13 files changed, 220 insertions, 0 deletions
diff --git a/API.md b/API.md
index 469dbaa1b..05b08dc6f 100755
--- a/API.md
+++ b/API.md
@@ -185,6 +185,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func UnpausePod(name: string) string](#UnpausePod)
+[func UntagImage(name: string, tag: string) string](#UntagImage)
+
[func VolumeCreate(options: VolumeCreateOpts) string](#VolumeCreate)
[func VolumeRemove(options: VolumeRemoveOpts) []string, map[string]](#VolumeRemove)
@@ -1234,6 +1236,14 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.UnpausePod '{"name": "foo
"pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f"
}
~~~
+### <a name="UntagImage"></a>func UntagImage
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method UntagImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
+UntagImage takes the name or ID of an image in local storage as well as the
+tag name to be removed. If the image cannot be found, an
+[ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of
+the image is returned on success.
### <a name="VolumeCreate"></a>func VolumeCreate
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index 282d90d0b..0e4315411 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -681,3 +681,7 @@ type SystemDfValues struct {
Verbose bool
Format string
}
+
+type UntagValues struct {
+ PodmanCommand
+}
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index 66c141686..ce576ff4b 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -74,6 +74,7 @@ var imageSubCommands = []*cobra.Command{
_saveCommand,
_tagCommand,
_treeCommand,
+ _untagCommand,
}
func init() {
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 344170ddd..c727eea85 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -68,6 +68,7 @@ var mainCommands = []*cobra.Command{
imageCommand.Command,
_startCommand,
systemCommand.Command,
+ _untagCommand,
}
var rootCmd = &cobra.Command{
diff --git a/cmd/podman/untag.go b/cmd/podman/untag.go
new file mode 100644
index 000000000..9ff62b808
--- /dev/null
+++ b/cmd/podman/untag.go
@@ -0,0 +1,67 @@
+package main
+
+import (
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+)
+
+var (
+ untagCommand cliconfig.UntagValues
+
+ _untagCommand = &cobra.Command{
+ Use: "untag [flags] IMAGE [NAME...]",
+ Short: "Remove a name from a local image",
+ Long: "Removes one or more names from a locally-stored image.",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ untagCommand.InputArgs = args
+ untagCommand.GlobalFlags = MainGlobalOpts
+ untagCommand.Remote = remoteclient
+ return untag(&untagCommand)
+ },
+ Example: `podman untag 0e3bbc2
+ podman untag imageID:latest otherImageName:latest
+ podman untag httpd myregistryhost:5000/fedora/httpd:v2`,
+ }
+)
+
+func init() {
+ untagCommand.Command = _untagCommand
+ untagCommand.SetHelpTemplate(HelpTemplate())
+ untagCommand.SetUsageTemplate(UsageTemplate())
+}
+
+func untag(c *cliconfig.UntagValues) error {
+ args := c.InputArgs
+
+ if len(args) == 0 {
+ return errors.Errorf("at least one image name needs to be specified")
+ }
+
+ runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ if err != nil {
+ return errors.Wrapf(err, "could not create runtime")
+ }
+ defer runtime.DeferredShutdown(false)
+
+ newImage, err := runtime.NewImageFromLocal(args[0])
+ if err != nil {
+ return err
+ }
+
+ tags := args[1:]
+ if len(args) == 1 {
+ // Remove all tags if not explicitly specified
+ tags = newImage.Names()
+ }
+ logrus.Debugf("Tags to be removed: %v", tags)
+
+ for _, tag := range tags {
+ if err := newImage.UntagImage(tag); err != nil {
+ return errors.Wrapf(err, "removing %q from %q", tag, newImage.InputName)
+ }
+ }
+ return nil
+}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 1bacd2de6..e1f28d847 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -860,6 +860,12 @@ method PushImage(name: string, tag: string, compress: bool, format: string, remo
# be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success.
method TagImage(name: string, tagged: string) -> (image: string)
+# UntagImage takes the name or ID of an image in local storage as well as the
+# tag name to be removed. If the image cannot be found, an
+# [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of
+# the image is returned on success.
+method UntagImage(name: string, tag: string) -> (image: string)
+
# RemoveImage takes the name or ID of an image as well as a boolean that determines if containers using that image
# should be deleted. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned. The
# ID of the removed image is returned when complete. See also [DeleteUnusedImages](DeleteUnusedImages).
diff --git a/docs/source/markdown/links/podman-image-untag.1 b/docs/source/markdown/links/podman-image-untag.1
new file mode 100644
index 000000000..3ec6a8a68
--- /dev/null
+++ b/docs/source/markdown/links/podman-image-untag.1
@@ -0,0 +1 @@
+.so man1/podman-untag.1
diff --git a/docs/source/markdown/podman-image.1.md b/docs/source/markdown/podman-image.1.md
index 339a531dd..1552098ac 100644
--- a/docs/source/markdown/podman-image.1.md
+++ b/docs/source/markdown/podman-image.1.md
@@ -27,6 +27,7 @@ The image command allows you to manage images
| save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. |
| sign | [podman-image-sign(1)](podman-image-sign.1.md) | Create a signature for an image. |
| tag | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. |
+| untag | [podman-untag(1)](podman-untag.1.md) | Removes one or more names from a locally-stored image. |
| tree | [podman-image-tree(1)](podman-image-tree.1.md) | Prints layer hierarchy of an image in a tree format. |
| trust | [podman-image-trust(1)](podman-image-trust.1.md)| Manage container registry image trust policy. |
diff --git a/docs/source/markdown/podman-untag.1.md b/docs/source/markdown/podman-untag.1.md
new file mode 100644
index 000000000..3a54283d6
--- /dev/null
+++ b/docs/source/markdown/podman-untag.1.md
@@ -0,0 +1,37 @@
+% podman-untag(1)
+
+## NAME
+podman\-untag - Removes one or more names from a locally-stored image
+
+## SYNOPSIS
+**podman untag** *image*[:*tag*] [*target-names*[:*tag*]] [*options*]
+
+**podman image untag** *image*[:*tag*] [target-names[:*tag*]] [*options*]
+
+## DESCRIPTION
+Removes one or all names of an image. A name refers to the entire image name,
+including the optional *tag* after the `:`. If no target image names are
+specified, `untag` will remove all tags for the image at once.
+
+## OPTIONS
+
+**--help**, **-h**
+
+Print usage statement
+
+## EXAMPLES
+
+```
+$ podman untag 0e3bbc2
+
+$ podman untag imageName:latest otherImageName:latest
+
+$ podman untag httpd myregistryhost:5000/fedora/httpd:v2
+```
+
+
+## SEE ALSO
+podman(1)
+
+## HISTORY
+December 2019, Originally compiled by Sascha Grunert <sgrunert@suse.com>
diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index 01c750144..0c9ec3d1c 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -201,6 +201,7 @@ the exit codes follow the `chroot` standard, see below:
| [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. |
| [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. |
| [podman-unshare(1)](podman-unshare.1.md) | Run a command inside of a modified user namespace. |
+| [podman-untag(1)](podman-untag.1.md) | Removes one or more names from a locally-stored image. |
| [podman-varlink(1)](podman-varlink.1.md) | Runs the varlink backend interface. |
| [podman-version(1)](podman-version.1.md) | Display the Podman version information. |
| [podman-volume(1)](podman-volume.1.md) | Simple management tool for volumes. |
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index fe5cc4fef..9c10b31c0 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -413,6 +413,12 @@ func (ci *ContainerImage) TagImage(tag string) error {
return err
}
+// UntagImage removes a single tag from an image
+func (ci *ContainerImage) UntagImage(tag string) error {
+ _, err := iopodman.UntagImage().Call(ci.Runtime.Conn, ci.ID(), tag)
+ return err
+}
+
// RemoveImage calls varlink to remove an image
func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, force bool) (*image.ImageDeleteResponse, error) {
ir := image.ImageDeleteResponse{}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index ac92343d0..bc644f87c 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -450,6 +450,18 @@ func (i *LibpodAPI) TagImage(call iopodman.VarlinkCall, name, tag string) error
return call.ReplyTagImage(newImage.ID())
}
+// UntagImage accepts an image name and tag as strings and removes the tag from the local store.
+func (i *LibpodAPI) UntagImage(call iopodman.VarlinkCall, name, tag string) error {
+ newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return call.ReplyImageNotFound(name, err.Error())
+ }
+ if err := newImage.UntagImage(tag); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyUntagImage(newImage.ID())
+}
+
// RemoveImage accepts a image name or ID as a string and force bool to determine if it should
// remove the image even if being used by stopped containers
func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bool) error {
diff --git a/test/e2e/untag_test.go b/test/e2e/untag_test.go
new file mode 100644
index 000000000..17171cd41
--- /dev/null
+++ b/test/e2e/untag_test.go
@@ -0,0 +1,73 @@
+package integration
+
+import (
+ "os"
+
+ . "github.com/containers/libpod/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman untag", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanTestCreate(tempdir)
+ podmanTest.Setup()
+ podmanTest.RestoreAllArtifacts()
+
+ for _, tag := range []string{"test", "foo", "bar"} {
+ session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, tag})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ }
+
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ processTestResult(f)
+
+ })
+
+ It("podman untag all", func() {
+ session := podmanTest.PodmanNoCache([]string{"untag", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ results := podmanTest.PodmanNoCache([]string{"images", ALPINE})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ Expect(results.OutputToStringArray()).To(HaveLen(1))
+ })
+
+ It("podman untag single", func() {
+ session := podmanTest.PodmanNoCache([]string{"untag", ALPINE, "localhost/test:latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ results := podmanTest.PodmanNoCache([]string{"images"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ Expect(results.OutputToStringArray()).To(HaveLen(5))
+ Expect(results.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue())
+ Expect(results.LineInOuputStartsWith("localhost/foo")).To(BeTrue())
+ Expect(results.LineInOuputStartsWith("localhost/bar")).To(BeTrue())
+ Expect(results.LineInOuputStartsWith("localhost/test")).To(BeFalse())
+ })
+
+ It("podman untag not enough arguments", func() {
+ session := podmanTest.PodmanNoCache([]string{"untag"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).NotTo(Equal(0))
+ })
+})