Merge pull request #4596 from kunalkushwaha/container-prune

container prune command fixed as per docker prune command
This commit is contained in:
OpenShift Merge Robot
2019-12-02 18:33:58 -08:00
committed by GitHub
9 changed files with 92 additions and 13 deletions

View File

@ -183,7 +183,8 @@ type PruneImagesValues struct {
type PruneContainersValues struct {
PodmanCommand
Force bool
Force bool
Filter []string
}
type PodPruneValues struct {

View File

@ -1,6 +1,11 @@
package main
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/define"
@ -36,9 +41,23 @@ func init() {
pruneContainersCommand.SetUsageTemplate(UsageTemplate())
flags := pruneContainersCommand.Flags()
flags.BoolVarP(&pruneContainersCommand.Force, "force", "f", false, "Force removal of a running container. The default is false")
flags.StringArrayVar(&pruneContainersCommand.Filter, "filter", []string{}, "Provide filter values (e.g. 'until=<timestamp>')")
}
func pruneContainersCmd(c *cliconfig.PruneContainersValues) error {
if !c.Force {
reader := bufio.NewReader(os.Stdin)
fmt.Printf(`WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] `)
ans, err := reader.ReadString('\n')
if err != nil {
return errors.Wrapf(err, "error reading input")
}
if strings.ToLower(ans)[0] != 'y' {
return nil
}
}
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
@ -49,7 +68,7 @@ func pruneContainersCmd(c *cliconfig.PruneContainersValues) error {
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalFlags.MaxWorks
}
ok, failures, err := runtime.Prune(getContext(), maxWorkers, c.Force)
ok, failures, err := runtime.Prune(getContext(), maxWorkers, c.Force, c.Filter)
if err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
if len(c.InputArgs) > 1 {

View File

@ -17,6 +17,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/timetype"
"github.com/containers/libpod/pkg/util"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-units"
@ -274,7 +275,8 @@ func worker(wg *sync.WaitGroup, jobs <-chan workerInput, results chan<- PsContai
}
}
func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
// GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
func GenerateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
switch filter {
case "id":
return func(c *libpod.Container) bool {
@ -396,6 +398,22 @@ func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime)
}
return hcStatus == filterValue
}, nil
case "until":
ts, err := timetype.GetTimestamp(filterValue, time.Now())
if err != nil {
return nil, err
}
seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
if err != nil {
return nil, err
}
until := time.Unix(seconds, nanoseconds)
return func(c *libpod.Container) bool {
if !until.IsZero() && c.CreatedTime().After((until)) {
return true
}
return false
}, nil
}
return nil, errors.Errorf("%s is an invalid filter", filter)
}
@ -413,7 +431,7 @@ func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, m
if len(filterSplit) < 2 {
return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
}
generatedFunc, err := generateContainerFilterFuncs(filterSplit[0], filterSplit[1], r)
generatedFunc, err := GenerateContainerFilterFuncs(filterSplit[0], filterSplit[1], r)
if err != nil {
return nil, errors.Wrapf(err, "invalid filter")
}

View File

@ -92,7 +92,7 @@ Are you sure you want to continue? [y/N] `, volumeString)
rmWorkers := shared.Parallelize("rm")
fmt.Println("Deleted Containers")
ok, failures, err = runtime.Prune(ctx, rmWorkers, false)
ok, failures, err = runtime.Prune(ctx, rmWorkers, false, []string{})
if err != nil {
if lasterr != nil {
logrus.Errorf("%q", err)

View File

@ -2832,9 +2832,12 @@ _podman_images_prune() {
_podman_container_prune() {
local options_with_args="
--filter
"
local boolean_options="
-f
--force
-h
--help
"

View File

@ -20,6 +20,8 @@ Print usage statement
Remove all stopped containers from local storage
```
$ sudo podman container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
878392adf2e6c5c9bb1fc19b69d37d2e98c8abf9d539c0bce4b15b46bbcce471
37664467fbe3618bf9479c34393ac29c02696675addf1750f9e346581636cde7
ed0c6468b8e1cb641b4621d1fe30cb477e1fefc5c0bceb66feaf2f7cb50e5962
@ -28,6 +30,26 @@ fff1c5b6c3631746055ec40598ce8ecaa4b82aef122f9e3a85b03b55c0d06c23
602d343cd47e7cb3dfc808282a9900a3e4555747787ec6723bb68cedab8384d5
```
Remove all stopped containers from local storage without confirmation.
```
$ sudo podman container prune -f
878392adf2e6c5c9bb1fc19b69d37d2e98c8abf9d539c0bce4b15b46bbcce471
37664467fbe3618bf9479c34393ac29c02696675addf1750f9e346581636cde7
ed0c6468b8e1cb641b4621d1fe30cb477e1fefc5c0bceb66feaf2f7cb50e5962
6ac6c8f0067b7a4682e6b8e18902665b57d1a0e07e885d9abcd382232a543ccd
fff1c5b6c3631746055ec40598ce8ecaa4b82aef122f9e3a85b03b55c0d06c23
602d343cd47e7cb3dfc808282a9900a3e4555747787ec6723bb68cedab8384d5
```
Remove all stopped containers from local storage created within last 10 minutes
```
$ sudo podman container prune --filter until="10m"
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
3d366295e33d8cc612c4d873199bacadd55088d90d17dcafaa9a2d317ad50b4e
```
## SEE ALSO
podman(1), podman-ps

View File

@ -1009,16 +1009,30 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal
}
// Prune removes stopped containers
func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool) ([]string, map[string]error, error) {
func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool, filters []string) ([]string, map[string]error, error) {
var (
ok = []string{}
failures = map[string]error{}
err error
ok = []string{}
failures = map[string]error{}
err error
filterFunc []libpod.ContainerFilter
)
logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
filter := func(c *libpod.Container) bool {
for _, filter := range filters {
filterSplit := strings.SplitN(filter, "=", 2)
if len(filterSplit) < 2 {
return ok, failures, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", filter)
}
f, err := shared.GenerateContainerFilterFuncs(filterSplit[0], filterSplit[1], r.Runtime)
if err != nil {
return ok, failures, err
}
filterFunc = append(filterFunc, f)
}
containerStateFilter := func(c *libpod.Container) bool {
state, err := c.State()
if err != nil {
logrus.Error(err)
@ -1032,7 +1046,9 @@ func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool) ([
}
return false
}
delContainers, err := r.Runtime.GetContainers(filter)
filterFunc = append(filterFunc, containerStateFilter)
delContainers, err := r.Runtime.GetContainers(filterFunc...)
if err != nil {
return ok, failures, err
}

View File

@ -922,7 +922,7 @@ func (r *LocalRuntime) Top(cli *cliconfig.TopValues) ([]string, error) {
}
// Prune removes stopped containers
func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool) ([]string, map[string]error, error) {
func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool, filter []string) ([]string, map[string]error, error) {
var (
ok = []string{}

View File

@ -52,7 +52,7 @@ var _ = Describe("Podman prune", func() {
stop.WaitWithDefaultTimeout()
Expect(stop.ExitCode()).To(Equal(0))
prune := podmanTest.Podman([]string{"container", "prune"})
prune := podmanTest.Podman([]string{"container", "prune", "-f"})
prune.WaitWithDefaultTimeout()
Expect(prune.ExitCode()).To(Equal(0))