Merge pull request #4712 from openSUSE/untag-command

Add `untag` sub-command
This commit is contained in:
OpenShift Merge Robot
2020-01-08 15:05:06 +01:00
committed by GitHub
13 changed files with 220 additions and 0 deletions

10
API.md
View File

@ -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;">

View File

@ -681,3 +681,7 @@ type SystemDfValues struct {
Verbose bool
Format string
}
type UntagValues struct {
PodmanCommand
}

View File

@ -74,6 +74,7 @@ var imageSubCommands = []*cobra.Command{
_saveCommand,
_tagCommand,
_treeCommand,
_untagCommand,
}
func init() {

View File

@ -68,6 +68,7 @@ var mainCommands = []*cobra.Command{
imageCommand.Command,
_startCommand,
systemCommand.Command,
_untagCommand,
}
var rootCmd = &cobra.Command{

67
cmd/podman/untag.go Normal file
View File

@ -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
}

View File

@ -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).

View File

@ -0,0 +1 @@
.so man1/podman-untag.1

View File

@ -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. |

View File

@ -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>

View File

@ -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. |

View File

@ -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{}

View File

@ -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 {

73
test/e2e/untag_test.go Normal file
View File

@ -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))
})
})