From 0b34b4a59cf090a47a2a13cc4814954c497b3d49 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Fri, 15 Mar 2019 17:41:03 -0400 Subject: Add podman pod prune podman system prune would leave pods be, and not prune them if they were stopped. Fix this by adding a `podman pod prune` command that prunes stopped pods similarly to containers. Signed-off-by: Peter Hunt --- cmd/podman/pods_prune.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 cmd/podman/pods_prune.go (limited to 'cmd/podman/pods_prune.go') diff --git a/cmd/podman/pods_prune.go b/cmd/podman/pods_prune.go new file mode 100644 index 000000000..4ffe6fc27 --- /dev/null +++ b/cmd/podman/pods_prune.go @@ -0,0 +1,91 @@ +package main + +import ( + "context" + + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/adapter" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var ( + prunePodsCommand cliconfig.PrunePodsValues + prunePodsDescription = ` + podman pod prune + + Removes all exited pods +` + _prunePodsCommand = &cobra.Command{ + Use: "prune", + Args: noSubArgs, + Short: "Remove all stopped pods", + Long: prunePodsDescription, + RunE: func(cmd *cobra.Command, args []string) error { + prunePodsCommand.InputArgs = args + prunePodsCommand.GlobalFlags = MainGlobalOpts + return prunePodsCmd(&prunePodsCommand) + }, + } +) + +func init() { + prunePodsCommand.Command = _prunePodsCommand + prunePodsCommand.SetHelpTemplate(HelpTemplate()) + prunePodsCommand.SetUsageTemplate(UsageTemplate()) + flags := prunePodsCommand.Flags() + flags.BoolVarP(&prunePodsCommand.Force, "force", "f", false, "Force removal of a running pods. The default is false") +} + +func prunePods(runtime *adapter.LocalRuntime, ctx context.Context, maxWorkers int, force bool) error { + var deleteFuncs []shared.ParallelWorkerInput + + filter := func(p *libpod.Pod) bool { + state, err := shared.GetPodStatus(p) + // pod states should be the same + if state == shared.PodStateStopped || (state == shared.PodStateExited && err == nil) { + return true + } + return false + } + delPods, err := runtime.Pods(filter) + if err != nil { + return err + } + if len(delPods) < 1 { + return nil + } + for _, pod := range delPods { + p := pod + f := func() error { + return runtime.RemovePod(ctx, p, force, force) + } + + deleteFuncs = append(deleteFuncs, shared.ParallelWorkerInput{ + ContainerID: p.ID(), + ParallelFunc: f, + }) + } + // Run the parallel funcs + deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) + return printParallelOutput(deleteErrors, errCount) +} + +func prunePodsCmd(c *cliconfig.PrunePodsValues) error { + runtime, err := adapter.GetRuntime(&c.PodmanCommand) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + maxWorkers := shared.Parallelize("rm") + if c.GlobalIsSet("max-workers") { + maxWorkers = c.GlobalFlags.MaxWorks + } + logrus.Debugf("Setting maximum workers to %d", maxWorkers) + + return prunePods(runtime, getContext(), maxWorkers, c.Bool("force")) +} -- cgit v1.2.3-54-g00ecf From 4319552cf89e72925a80c63f427e5ef0a6376046 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Mon, 15 Apr 2019 15:44:32 -0400 Subject: Added remote pod prune Signed-off-by: Peter Hunt --- cmd/podman/pods_prune.go | 12 ++---------- cmd/podman/varlink/io.podman.varlink | 3 +++ pkg/adapter/pods.go | 2 +- pkg/adapter/pods_remote.go | 31 +++++++++++++++++++++++++++++++ pkg/adapter/runtime.go | 36 ++++++++++++++++++++++++++++++++++++ pkg/adapter/runtime_remote.go | 18 ------------------ pkg/varlinkapi/pods.go | 22 ++++++++++++++++++++++ 7 files changed, 95 insertions(+), 29 deletions(-) (limited to 'cmd/podman/pods_prune.go') diff --git a/cmd/podman/pods_prune.go b/cmd/podman/pods_prune.go index 4ffe6fc27..89401a98a 100644 --- a/cmd/podman/pods_prune.go +++ b/cmd/podman/pods_prune.go @@ -5,7 +5,6 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -43,15 +42,8 @@ func init() { func prunePods(runtime *adapter.LocalRuntime, ctx context.Context, maxWorkers int, force bool) error { var deleteFuncs []shared.ParallelWorkerInput - filter := func(p *libpod.Pod) bool { - state, err := shared.GetPodStatus(p) - // pod states should be the same - if state == shared.PodStateStopped || (state == shared.PodStateExited && err == nil) { - return true - } - return false - } - delPods, err := runtime.Pods(filter) + states := []string{shared.PodStateStopped, shared.PodStateExited} + delPods, err := runtime.GetPodsByStatus(states) if err != nil { return err } diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index b5295273a..497f130bc 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -1053,6 +1053,9 @@ method TopPod(pod: string, latest: bool, descriptors: []string) -> (stats: []str # ~~~ method GetPodStats(name: string) -> (pod: string, containers: []ContainerStats) +# GetPodsByStatus searches for pods whose status is included in statuses +method GetPodsByStatus(statuses: []string) -> (pods: []string) + # ImageExists talks a full or partial image ID or name and returns an int as to whether # the image exists in local storage. An int result of 0 means the image does exist in # local storage; whereas 1 indicates the image does not exists in local storage. diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 669971789..901c1857b 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -38,7 +38,7 @@ func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValue } for _, p := range pods { - if err := r.RemovePod(ctx, p, cli.Force, cli.Force); err != nil { + if err := r.Runtime.RemovePod(ctx, p, cli.Force, cli.Force); err != nil { errs = append(errs, err) } else { podids = append(podids, p.ID()) diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go index 4a32607a2..00a5d9a32 100644 --- a/pkg/adapter/pods_remote.go +++ b/pkg/adapter/pods_remote.go @@ -214,6 +214,23 @@ func (r *LocalRuntime) GetAllPods() ([]*Pod, error) { return pods, nil } +// GetPodsByStatus returns a slice of pods filtered by a libpod status +func (r *LocalRuntime) GetPodsByStatus(statuses []string) ([]*Pod, error) { + podIDs, err := iopodman.GetPodsByStatus().Call(r.Conn, statuses) + if err != nil { + return nil, err + } + pods := make([]*Pod, 0, len(podIDs)) + for _, p := range podIDs { + pod, err := r.LookupPod(p) + if err != nil { + return nil, err + } + pods = append(pods, pod) + } + return pods, nil +} + // ID returns the id of a remote pod func (p *Pod) ID() string { return p.config.ID @@ -508,3 +525,17 @@ func (p *Pod) GetPodStats(previousContainerStats map[string]*libpod.ContainerSta } return newContainerStats, nil } + +// RemovePod removes a pod +// If removeCtrs is specified, containers will be removed +// Otherwise, a pod that is not empty will return an error and not be removed +// If force is specified with removeCtrs, all containers will be stopped before +// being removed +// Otherwise, the pod will not be removed if any containers are running +func (r *LocalRuntime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error { + _, err := iopodman.RemovePod().Call(r.Conn, p.ID(), force) + if err != nil { + return err + } + return nil +} diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index b5ec9f7a9..6ed9cee77 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -369,3 +369,39 @@ func (r *LocalRuntime) Diff(c *cliconfig.DiffValues, to string) ([]archive.Chang func (r *LocalRuntime) GenerateKube(c *cliconfig.GenerateKubeValues) (*v1.Pod, *v1.Service, error) { return shared.GenerateKube(c.InputArgs[0], c.Service, r.Runtime) } + +// GetPodsByStatus returns a slice of pods filtered by a libpod status +func (r *LocalRuntime) GetPodsByStatus(statuses []string) ([]*Pod, error) { + var adapterPods []*Pod + + filterFunc := func(p *libpod.Pod) bool { + state, _ := shared.GetPodStatus(p) + for _, status := range statuses { + if state == status { + return true + } + } + return false + } + pods, err := r.Runtime.Pods(filterFunc) + if err != nil { + return nil, err + } + for _, p := range pods { + adapterPod := Pod{ + p, + } + adapterPods = append(adapterPods, &adapterPod) + } + return adapterPods, nil +} + +// RemovePod removes a pod +// If removeCtrs is specified, containers will be removed +// Otherwise, a pod that is not empty will return an error and not be removed +// If force is specified with removeCtrs, all containers will be stopped before +// being removed +// Otherwise, the pod will not be removed if any containers are running +func (r *LocalRuntime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error { + return r.Runtime.RemovePod(ctx, p.Pod, removeCtrs, force) +} diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index 08f421595..71f7380db 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -527,24 +527,6 @@ func (r *LocalRuntime) RemoveContainer(ctx context.Context, c *libpod.Container, return libpod.ErrNotImplemented } -// Pods retrieves all pods -// Filters can be provided which will determine which pods are included in the -// output. Multiple filters are handled by ANDing their output, so only pods -// matching all filters are returned -func (r *LocalRuntime) Pods(filters ...libpod.PodFilter) ([]*libpod.Pod, error) { - return nil, libpod.ErrNotImplemented -} - -// RemovePod removes a pod -// If removeCtrs is specified, containers will be removed -// Otherwise, a pod that is not empty will return an error and not be removed -// If force is specified with removeCtrs, all containers will be stopped before -// being removed -// Otherwise, the pod will not be removed if any containers are running -func (r *LocalRuntime) RemovePod(ctx context.Context, p *libpod.Pod, removeCtrs, force bool) error { - return libpod.ErrNotImplemented -} - // CreateVolume creates a volume over a varlink connection for the remote client func (r *LocalRuntime) CreateVolume(ctx context.Context, c *cliconfig.VolumeCreateValues, labels, opts map[string]string) (string, error) { cvOpts := iopodman.VolumeCreateOpts{ diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go index ac8e24747..f34375bf5 100644 --- a/pkg/varlinkapi/pods.go +++ b/pkg/varlinkapi/pods.go @@ -101,6 +101,28 @@ func (i *LibpodAPI) GetPod(call iopodman.VarlinkCall, name string) error { return call.ReplyGetPod(listPod) } +// GetPodsByStatus returns a slice of pods filtered by a libpod status +func (i *LibpodAPI) GetPodsByStatus(call iopodman.VarlinkCall, statuses []string) error { + filterFuncs := func(p *libpod.Pod) bool { + state, _ := shared.GetPodStatus(p) + for _, status := range statuses { + if state == status { + return true + } + } + return false + } + filteredPods, err := i.Runtime.Pods(filterFuncs) + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + podIDs := make([]string, 0, len(filteredPods)) + for _, p := range filteredPods { + podIDs = append(podIDs, p.ID()) + } + return call.ReplyGetPodsByStatus(podIDs) +} + // InspectPod ... func (i *LibpodAPI) InspectPod(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) -- cgit v1.2.3-54-g00ecf