mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Merge pull request #5733 from sujil02/v2-pod-prune
Add pod prune for api v2
This commit is contained in:
75
cmd/podman/pods/prune.go
Normal file
75
cmd/podman/pods/prune.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package pods
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/cmd/podman/registry"
|
||||||
|
"github.com/containers/libpod/cmd/podman/utils"
|
||||||
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pruneOptions = entities.PodPruneOptions{}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pruneDescription = fmt.Sprintf(`podman pod prune Removes all exited pods`)
|
||||||
|
|
||||||
|
pruneCommand = &cobra.Command{
|
||||||
|
Use: "prune [flags]",
|
||||||
|
Short: "Remove all stopped pods and their containers",
|
||||||
|
Long: pruneDescription,
|
||||||
|
RunE: prune,
|
||||||
|
Example: `podman pod prune`,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||||
|
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||||
|
Command: pruneCommand,
|
||||||
|
Parent: podCmd,
|
||||||
|
})
|
||||||
|
flags := pruneCommand.Flags()
|
||||||
|
flags.BoolVarP(&pruneOptions.Force, "force", "f", false, "Do not prompt for confirmation. The default is false")
|
||||||
|
}
|
||||||
|
|
||||||
|
func prune(cmd *cobra.Command, args []string) error {
|
||||||
|
var (
|
||||||
|
errs utils.OutputErrors
|
||||||
|
)
|
||||||
|
if len(args) > 0 {
|
||||||
|
return errors.Errorf("`%s` takes no arguments", cmd.CommandPath())
|
||||||
|
}
|
||||||
|
if !pruneOptions.Force {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
fmt.Println("WARNING! This will remove all stopped/exited pods..")
|
||||||
|
fmt.Print("Are you sure you want to continue? [y/N] ")
|
||||||
|
answer, err := reader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error reading input")
|
||||||
|
}
|
||||||
|
if strings.ToLower(answer)[0] != 'y' {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responses, err := registry.ContainerEngine().PodPrune(context.Background(), pruneOptions)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, r := range responses {
|
||||||
|
if r.Err == nil {
|
||||||
|
fmt.Println(r.Id)
|
||||||
|
} else {
|
||||||
|
errs = append(errs, r.Err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errs.PrintErrors()
|
||||||
|
}
|
@ -176,8 +176,7 @@ func (r *Runtime) GetRunningPods() ([]*Pod, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PrunePods removes unused pods and their containers from local storage.
|
// PrunePods removes unused pods and their containers from local storage.
|
||||||
// If force is given, then running pods are also included in the pruning.
|
func (r *Runtime) PrunePods(ctx context.Context) (map[string]error, error) {
|
||||||
func (r *Runtime) PrunePods() (map[string]error, error) {
|
|
||||||
response := make(map[string]error)
|
response := make(map[string]error)
|
||||||
states := []string{define.PodStateStopped, define.PodStateExited}
|
states := []string{define.PodStateStopped, define.PodStateExited}
|
||||||
filterFunc := func(p *Pod) bool {
|
filterFunc := func(p *Pod) bool {
|
||||||
|
@ -232,13 +232,20 @@ func PodRestart(w http.ResponseWriter, r *http.Request) {
|
|||||||
func PodPrune(w http.ResponseWriter, r *http.Request) {
|
func PodPrune(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
|
reports []*entities.PodPruneReport
|
||||||
)
|
)
|
||||||
pruned, err := runtime.PrunePods()
|
responses, err := runtime.PrunePods(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WriteResponse(w, http.StatusOK, pruned)
|
for k, v := range responses {
|
||||||
|
reports = append(reports, &entities.PodPruneReport{
|
||||||
|
Err: v,
|
||||||
|
Id: k,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
utils.WriteResponse(w, http.StatusOK, reports)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodPause(w http.ResponseWriter, r *http.Request) {
|
func PodPause(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -70,6 +70,13 @@ type swagStartPodResponse struct {
|
|||||||
Body entities.PodStartReport
|
Body entities.PodStartReport
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prune pod
|
||||||
|
// swagger:response PodPruneReport
|
||||||
|
type swagPrunePodResponse struct {
|
||||||
|
// in:body
|
||||||
|
Body entities.PodPruneReport
|
||||||
|
}
|
||||||
|
|
||||||
// Rm pod
|
// Rm pod
|
||||||
// swagger:response PodRmReport
|
// swagger:response PodRmReport
|
||||||
type swagRmPodResponse struct {
|
type swagRmPodResponse struct {
|
||||||
|
@ -53,11 +53,7 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
|
|||||||
// - application/json
|
// - application/json
|
||||||
// responses:
|
// responses:
|
||||||
// 200:
|
// 200:
|
||||||
// description: tbd
|
// $ref: '#/responses/PodPruneReport'
|
||||||
// schema:
|
|
||||||
// type: object
|
|
||||||
// additionalProperties:
|
|
||||||
// type: string
|
|
||||||
// 400:
|
// 400:
|
||||||
// $ref: "#/responses/BadParamError"
|
// $ref: "#/responses/BadParamError"
|
||||||
// 409:
|
// 409:
|
||||||
|
@ -98,17 +98,19 @@ func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, erro
|
|||||||
return &report, response.Process(&report)
|
return &report, response.Process(&report)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune removes all non-running pods in local storage.
|
// Prune by default removes all non-running pods in local storage.
|
||||||
func Prune(ctx context.Context) error {
|
// And with force set true removes all pods.
|
||||||
|
func Prune(ctx context.Context) ([]*entities.PodPruneReport, error) {
|
||||||
|
var reports []*entities.PodPruneReport
|
||||||
conn, err := bindings.GetClient(ctx)
|
conn, err := bindings.GetClient(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
response, err := conn.DoRequest(nil, http.MethodPost, "/pods/prune", nil)
|
response, err := conn.DoRequest(nil, http.MethodPost, "/pods/prune", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
return response.Process(nil)
|
return reports, response.Process(&reports)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List returns all pods in local storage. The optional filters parameter can
|
// List returns all pods in local storage. The optional filters parameter can
|
||||||
|
@ -262,7 +262,7 @@ var _ = Describe("Podman pods", func() {
|
|||||||
var newpod2 string = "newpod2"
|
var newpod2 string = "newpod2"
|
||||||
bt.Podcreate(&newpod2)
|
bt.Podcreate(&newpod2)
|
||||||
// No pods pruned since no pod in exited state
|
// No pods pruned since no pod in exited state
|
||||||
err = pods.Prune(bt.conn)
|
pruneResponse, err := pods.Prune(bt.conn)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
podSummary, err := pods.List(bt.conn, nil)
|
podSummary, err := pods.List(bt.conn, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
@ -279,13 +279,19 @@ var _ = Describe("Podman pods", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// FIXME sujil please fix this
|
// FIXME sujil please fix this
|
||||||
//Expect(response.State.Status).To(Equal(define.PodStateExited))
|
//Expect(response.State.Status).To(Equal(define.PodStateExited))
|
||||||
err = pods.Prune(bt.conn)
|
pruneResponse, err = pods.Prune(bt.conn)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
// Validate status and record pod id of pod to be pruned
|
||||||
|
//Expect(response.State.Status).To(Equal(define.PodStateExited))
|
||||||
|
//podID := response.Config.ID
|
||||||
|
// Check if right pod was pruned
|
||||||
|
Expect(len(pruneResponse)).To(Equal(1))
|
||||||
|
// One pod is pruned hence only one pod should be active.
|
||||||
podSummary, err = pods.List(bt.conn, nil)
|
podSummary, err = pods.List(bt.conn, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(len(podSummary)).To(Equal(1))
|
Expect(len(podSummary)).To(Equal(1))
|
||||||
|
|
||||||
// Test prune all pods in exited state.
|
// Test prune multiple pods.
|
||||||
bt.Podcreate(&newpod)
|
bt.Podcreate(&newpod)
|
||||||
_, err = pods.Start(bt.conn, newpod)
|
_, err = pods.Start(bt.conn, newpod)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
@ -311,7 +317,7 @@ var _ = Describe("Podman pods", func() {
|
|||||||
Expect(define.StringToContainerStatus(i.State)).
|
Expect(define.StringToContainerStatus(i.State)).
|
||||||
To(Equal(define.ContainerStateStopped))
|
To(Equal(define.ContainerStateStopped))
|
||||||
}
|
}
|
||||||
err = pods.Prune(bt.conn)
|
_, err = pods.Prune(bt.conn)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
podSummary, err = pods.List(bt.conn, nil)
|
podSummary, err = pods.List(bt.conn, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
@ -49,6 +49,7 @@ type ContainerEngine interface {
|
|||||||
PodPs(ctx context.Context, options PodPSOptions) ([]*ListPodsReport, error)
|
PodPs(ctx context.Context, options PodPSOptions) ([]*ListPodsReport, error)
|
||||||
PodRestart(ctx context.Context, namesOrIds []string, options PodRestartOptions) ([]*PodRestartReport, error)
|
PodRestart(ctx context.Context, namesOrIds []string, options PodRestartOptions) ([]*PodRestartReport, error)
|
||||||
PodRm(ctx context.Context, namesOrIds []string, options PodRmOptions) ([]*PodRmReport, error)
|
PodRm(ctx context.Context, namesOrIds []string, options PodRmOptions) ([]*PodRmReport, error)
|
||||||
|
PodPrune(ctx context.Context, options PodPruneOptions) ([]*PodPruneReport, error)
|
||||||
PodStart(ctx context.Context, namesOrIds []string, options PodStartOptions) ([]*PodStartReport, error)
|
PodStart(ctx context.Context, namesOrIds []string, options PodStartOptions) ([]*PodStartReport, error)
|
||||||
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
|
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
|
||||||
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
|
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
|
||||||
|
@ -147,6 +147,15 @@ func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
|
|||||||
s.CgroupParent = p.CGroupParent
|
s.CgroupParent = p.CGroupParent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PodPruneOptions struct {
|
||||||
|
Force bool `json:"force" schema:"force"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PodPruneReport struct {
|
||||||
|
Err error
|
||||||
|
Id string
|
||||||
|
}
|
||||||
|
|
||||||
type PodTopOptions struct {
|
type PodTopOptions struct {
|
||||||
// CLI flags.
|
// CLI flags.
|
||||||
ListDescriptors bool
|
ListDescriptors bool
|
||||||
|
@ -25,9 +25,7 @@ type Report struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PodDeleteReport struct{ Report }
|
type PodDeleteReport struct{ Report }
|
||||||
type PodPruneOptions struct{}
|
|
||||||
|
|
||||||
type PodPruneReport struct{ Report }
|
|
||||||
type VolumeDeleteOptions struct{}
|
type VolumeDeleteOptions struct{}
|
||||||
type VolumeDeleteReport struct{ Report }
|
type VolumeDeleteReport struct{ Report }
|
||||||
|
|
||||||
|
@ -243,6 +243,23 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
|
|||||||
return reports, nil
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ic *ContainerEngine) PodPrune(ctx context.Context, options entities.PodPruneOptions) ([]*entities.PodPruneReport, error) {
|
||||||
|
var (
|
||||||
|
reports []*entities.PodPruneReport
|
||||||
|
)
|
||||||
|
response, err := ic.Libpod.PrunePods(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range response {
|
||||||
|
reports = append(reports, &entities.PodPruneReport{
|
||||||
|
Err: v,
|
||||||
|
Id: k,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return reports, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
|
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
|
||||||
podSpec := specgen.NewPodSpecGenerator()
|
podSpec := specgen.NewPodSpecGenerator()
|
||||||
opts.ToPodSpecGen(podSpec)
|
opts.ToPodSpecGen(podSpec)
|
||||||
|
@ -173,6 +173,10 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
|
|||||||
return reports, nil
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ic *ContainerEngine) PodPrune(ctx context.Context, opts entities.PodPruneOptions) ([]*entities.PodPruneReport, error) {
|
||||||
|
return pods.Prune(ic.ClientCxt)
|
||||||
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
|
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
|
||||||
podSpec := specgen.NewPodSpecGenerator()
|
podSpec := specgen.NewPodSpecGenerator()
|
||||||
opts.ToPodSpecGen(podSpec)
|
opts.ToPodSpecGen(podSpec)
|
||||||
|
@ -36,7 +36,7 @@ var _ = Describe("Podman pod prune", func() {
|
|||||||
_, ec, _ := podmanTest.CreatePod("")
|
_, ec, _ := podmanTest.CreatePod("")
|
||||||
Expect(ec).To(Equal(0))
|
Expect(ec).To(Equal(0))
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"pod", "prune"})
|
result := podmanTest.Podman([]string{"pod", "prune", "--force"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result.ExitCode()).To(Equal(0))
|
Expect(result.ExitCode()).To(Equal(0))
|
||||||
})
|
})
|
||||||
@ -49,7 +49,7 @@ var _ = Describe("Podman pod prune", func() {
|
|||||||
ec2.WaitWithDefaultTimeout()
|
ec2.WaitWithDefaultTimeout()
|
||||||
Expect(ec2.ExitCode()).To(Equal(0))
|
Expect(ec2.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"pod", "prune"})
|
result := podmanTest.Podman([]string{"pod", "prune", "-f"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result.ExitCode()).To((Equal(0)))
|
Expect(result.ExitCode()).To((Equal(0)))
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ var _ = Describe("Podman pod prune", func() {
|
|||||||
_, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
|
_, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
|
||||||
Expect(ec2).To(Equal(0))
|
Expect(ec2).To(Equal(0))
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"pod", "prune"})
|
result := podmanTest.Podman([]string{"pod", "prune", "-f"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result.ExitCode()).To(Equal(0))
|
Expect(result.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
@ -73,21 +73,4 @@ var _ = Describe("Podman pod prune", func() {
|
|||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(len(result.OutputToStringArray())).To(Equal(0))
|
Expect(len(result.OutputToStringArray())).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman pod prune -f does remove a running container", func() {
|
|
||||||
_, ec, podid := podmanTest.CreatePod("")
|
|
||||||
Expect(ec).To(Equal(0))
|
|
||||||
|
|
||||||
session := podmanTest.RunTopContainerInPod("", podid)
|
|
||||||
session.WaitWithDefaultTimeout()
|
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"pod", "prune", "-f"})
|
|
||||||
result.WaitWithDefaultTimeout()
|
|
||||||
Expect(result.ExitCode()).To(Equal(0))
|
|
||||||
|
|
||||||
result = podmanTest.Podman([]string{"ps", "-q"})
|
|
||||||
result.WaitWithDefaultTimeout()
|
|
||||||
Expect(result.OutputToString()).To(BeEmpty())
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user