Merge pull request #1912 from baude/prune

Add ability to prune containers and images
This commit is contained in:
OpenShift Merge Robot
2018-12-06 08:31:20 -08:00
committed by GitHub
13 changed files with 351 additions and 6 deletions

View File

@ -22,7 +22,7 @@ var (
mountCommand, mountCommand,
pauseCommand, pauseCommand,
portCommand, portCommand,
// pruneCommand, pruneContainersCommand,
refreshCommand, refreshCommand,
restartCommand, restartCommand,
restoreCommand, restoreCommand,

View File

@ -0,0 +1,74 @@
package main
import (
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var (
pruneContainersDescription = `
podman container prune
Removes all exited containers
`
pruneContainersCommand = cli.Command{
Name: "prune",
Usage: "Remove all stopped containers",
Description: pruneContainersDescription,
Action: pruneContainersCmd,
OnUsageError: usageErrorHandler,
}
)
func pruneContainersCmd(c *cli.Context) error {
var (
deleteFuncs []shared.ParallelWorkerInput
)
ctx := getContext()
runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
filter := func(c *libpod.Container) bool {
state, _ := c.State()
if state == libpod.ContainerStateStopped || (state == libpod.ContainerStateExited && err == nil && c.PodID() == "") {
return true
}
return false
}
delContainers, err := runtime.GetContainers(filter)
if err != nil {
return err
}
if len(delContainers) < 1 {
return nil
}
for _, container := range delContainers {
con := container
f := func() error {
return runtime.RemoveContainer(ctx, con, c.Bool("force"))
}
deleteFuncs = append(deleteFuncs, shared.ParallelWorkerInput{
ContainerID: con.ID(),
ParallelFunc: f,
})
}
maxWorkers := shared.Parallelize("rm")
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalInt("max-workers")
}
logrus.Debugf("Setting maximum workers to %d", maxWorkers)
// Run the parallel funcs
deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs)
return printParallelOutput(deleteErrors, errCount)
}

View File

@ -13,7 +13,7 @@ var (
inspectCommand, inspectCommand,
loadCommand, loadCommand,
lsImagesCommand, lsImagesCommand,
// pruneCommand, pruneImagesCommand,
pullCommand, pullCommand,
pushCommand, pushCommand,
rmImageCommand, rmImageCommand,

View File

@ -0,0 +1,34 @@
package main
import (
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
var (
pruneImagesDescription = `
podman image prune
Removes all unnamed images from local storage
`
pruneImagesCommand = cli.Command{
Name: "prune",
Usage: "Remove unused images",
Description: pruneImagesDescription,
Action: pruneImagesCmd,
OnUsageError: usageErrorHandler,
}
)
func pruneImagesCmd(c *cli.Context) error {
runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
return shared.Prune(runtime.ImageRuntime())
}

View File

@ -0,0 +1,24 @@
package shared
import (
"fmt"
"github.com/pkg/errors"
"github.com/containers/libpod/libpod/image"
)
// Prune removes all unnamed and unused images from the local store
func Prune(ir *image.Runtime) error {
pruneImages, err := ir.GetPruneImages()
if err != nil {
return err
}
for _, i := range pruneImages {
if err := i.Remove(true); err != nil {
return errors.Wrapf(err, "failed to remove %s", i.ID())
}
fmt.Println(i.ID())
}
return nil
}

View File

@ -871,6 +871,7 @@ _podman_container() {
create create
diff diff
exec exec
exists
export export
inspect inspect
kill kill
@ -879,6 +880,7 @@ _podman_container() {
mount mount
pause pause
port port
prune
refresh refresh
restart restart
restore restore
@ -1210,11 +1212,13 @@ _podman_image() {
" "
subcommands=" subcommands="
build build
exists
history history
import import
inspect inspect
load load
ls ls
prune
pull pull
push push
rm rm
@ -2228,6 +2232,26 @@ _podman_container_runlabel() {
esac esac
} }
_podman_images_prune() {
local options_with_args="
"
local boolean_options="
-h
--help
"
}
_podman_container_prune() {
local options_with_args="
"
local boolean_options="
-h
--help
"
}
_podman_container_exists() { _podman_container_exists() {
local options_with_args=" local options_with_args="
" "

View File

@ -0,0 +1,31 @@
% PODMAN(1) Podman Man Pages
% Brent Baude
% December 2018
# NAME
podman-container-prune - Remove all stopped containers
# SYNOPSIS
**podman container prune**
[**-h**|**--help**]
# DESCRIPTION
**podman container prune** removes all stopped containers from local storage.
## Examples ##
Remove all stopped containers from local storage
```
$ sudo podman container prune
878392adf2e6c5c9bb1fc19b69d37d2e98c8abf9d539c0bce4b15b46bbcce471
37664467fbe3618bf9479c34393ac29c02696675addf1750f9e346581636cde7
ed0c6468b8e1cb641b4621d1fe30cb477e1fefc5c0bceb66feaf2f7cb50e5962
6ac6c8f0067b7a4682e6b8e18902665b57d1a0e07e885d9abcd382232a543ccd
fff1c5b6c3631746055ec40598ce8ecaa4b82aef122f9e3a85b03b55c0d06c23
602d343cd47e7cb3dfc808282a9900a3e4555747787ec6723bb68cedab8384d5
```
## SEE ALSO
podman(1), podman-ps
# HISTORY
December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)

View File

@ -29,6 +29,7 @@ The container command allows you to manage containers
| mount | [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. | | mount | [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. |
| pause | [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. | | pause | [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. |
| port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. | | port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. |
| prune | [podman-container-prune(1)](podman-container-prune.1.md) | Remove all stopped containers from local storage |
| refresh | [podman-refresh(1)](podman-container-refresh.1.md) | Refresh the state of all containers | | refresh | [podman-refresh(1)](podman-container-refresh.1.md) | Refresh the state of all containers |
| restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. | | restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
| restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. | | restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. |

View File

@ -0,0 +1,32 @@
% PODMAN(1) Podman Man Pages
% Brent Baude
% December 2018
# NAME
podman-image-prune - Remove all unused images
# SYNOPSIS
**podman image prune**
[**-h**|**--help**]
# DESCRIPTION
**podman image prune** removes all unused images from local storage. An unused image
is defined as an image that does not have any containers based on it.
## Examples ##
Remove all unused images from local storage
```
$ sudo podman image prune
f3e20dc537fb04cb51672a5cb6fdf2292e61d411315549391a0d1f64e4e3097e
324a7a3b2e0135f4226ffdd473e4099fd9e477a74230cdc35de69e84c0f9d907
6125002719feb1ddf3030acab1df6156da7ce0e78e571e9b6e9c250424d6220c
91e732da5657264c6f4641b8d0c4001c218ae6c1adb9dcef33ad00cafd37d8b6
e4e5109420323221f170627c138817770fb64832da7d8fe2babd863148287fca
77a57fa8285e9656dbb7b23d9efa837a106957409ddd702f995605af27a45ebe
```
## SEE ALSO
podman(1), podman-images
# HISTORY
December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)

View File

@ -21,6 +21,7 @@ The image command allows you to manage images
| load | [podman-load(1)](podman-load.1.md) | Load an image from the docker archive. | | load | [podman-load(1)](podman-load.1.md) | Load an image from the docker archive. |
| ls | [podman-images(1)](podman-images.1.md) | Prints out information about images. | | ls | [podman-images(1)](podman-images.1.md) | Prints out information about images. |
| pull | [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. | | pull | [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
| prune| [podman-container-prune(1)](podman-container-prune.1.md) | Removed all unused images from the local store |
| push | [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. | | push | [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
| rm | [podman-rm(1)](podman-rmi.1.md) | Removes one or more locally stored images. | | rm | [podman-rm(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
| save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. | | save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. |

View File

@ -19,15 +19,25 @@ Remove all images in the local storage.
This option will cause podman to remove all containers that are using the image before removing the image from the system. This option will cause podman to remove all containers that are using the image before removing the image from the system.
## EXAMPLE
podman rmi imageID
Remove an image by its short ID
```
podman rmi c0ed59d05ff7
```
Remove an image and its associated containers.
```
podman rmi --force imageID podman rmi --force imageID
````
podman rmi imageID1 imageID2 imageID3 Remove multiple images by their shortened IDs.
```
podman rmi c4dfb1609ee2 93fd78260bd1 c0ed59d05ff7
```
Remove all images and containers.
```
podman rmi -a -f podman rmi -a -f
```
## SEE ALSO ## SEE ALSO
podman(1) podman(1)

26
libpod/image/prune.go Normal file
View File

@ -0,0 +1,26 @@
package image
// GetPruneImages returns a slice of images that have no names/unused
func (ir *Runtime) GetPruneImages() ([]*Image, error) {
var (
unamedImages []*Image
)
allImages, err := ir.GetImages()
if err != nil {
return nil, err
}
for _, i := range allImages {
if len(i.Names()) == 0 {
unamedImages = append(unamedImages, i)
continue
}
containers, err := i.Containers()
if err != nil {
return nil, err
}
if len(containers) < 1 {
unamedImages = append(unamedImages, i)
}
}
return unamedImages, nil
}

88
test/e2e/prune_test.go Normal file
View File

@ -0,0 +1,88 @@
package integration
import (
"fmt"
"os"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var pruneImage = `
FROM alpine:latest
LABEL RUN podman --version
RUN apk update
RUN apk add bash`
var _ = Describe("Podman rm", 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 container prune containers", func() {
top := podmanTest.RunTopContainer("")
top.WaitWithDefaultTimeout()
Expect(top.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"run", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
prune := podmanTest.Podman([]string{"container", "prune"})
prune.WaitWithDefaultTimeout()
Expect(prune.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
})
It("podman image prune none images", func() {
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
none := podmanTest.Podman([]string{"images", "-a"})
none.WaitWithDefaultTimeout()
Expect(none.ExitCode()).To(Equal(0))
hasNone, _ := none.GrepString("<none>")
Expect(hasNone).To(BeTrue())
prune := podmanTest.Podman([]string{"image", "prune"})
prune.WaitWithDefaultTimeout()
Expect(prune.ExitCode()).To(Equal(0))
after := podmanTest.Podman([]string{"images", "-a"})
after.WaitWithDefaultTimeout()
Expect(none.ExitCode()).To(Equal(0))
hasNoneAfter, _ := after.GrepString("<none>")
Expect(hasNoneAfter).To(BeFalse())
})
It("podman image prune unused images", func() {
prune := podmanTest.Podman([]string{"image", "prune"})
prune.WaitWithDefaultTimeout()
Expect(prune.ExitCode()).To(Equal(0))
images := podmanTest.Podman([]string{"images", "-a"})
images.WaitWithDefaultTimeout()
// all images are unused, so they all should be deleted!
Expect(len(images.OutputToStringArray())).To(Equal(0))
})
})