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.
|
||||
// If force is given, then running pods are also included in the pruning.
|
||||
func (r *Runtime) PrunePods() (map[string]error, error) {
|
||||
func (r *Runtime) PrunePods(ctx context.Context) (map[string]error, error) {
|
||||
response := make(map[string]error)
|
||||
states := []string{define.PodStateStopped, define.PodStateExited}
|
||||
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) {
|
||||
var (
|
||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
||||
reports []*entities.PodPruneReport
|
||||
)
|
||||
pruned, err := runtime.PrunePods()
|
||||
responses, err := runtime.PrunePods(r.Context())
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
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) {
|
||||
|
@ -70,6 +70,13 @@ type swagStartPodResponse struct {
|
||||
Body entities.PodStartReport
|
||||
}
|
||||
|
||||
// Prune pod
|
||||
// swagger:response PodPruneReport
|
||||
type swagPrunePodResponse struct {
|
||||
// in:body
|
||||
Body entities.PodPruneReport
|
||||
}
|
||||
|
||||
// Rm pod
|
||||
// swagger:response PodRmReport
|
||||
type swagRmPodResponse struct {
|
||||
|
@ -53,11 +53,7 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
|
||||
// - application/json
|
||||
// responses:
|
||||
// 200:
|
||||
// description: tbd
|
||||
// schema:
|
||||
// type: object
|
||||
// additionalProperties:
|
||||
// type: string
|
||||
// $ref: '#/responses/PodPruneReport'
|
||||
// 400:
|
||||
// $ref: "#/responses/BadParamError"
|
||||
// 409:
|
||||
|
@ -98,17 +98,19 @@ func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, erro
|
||||
return &report, response.Process(&report)
|
||||
}
|
||||
|
||||
// Prune removes all non-running pods in local storage.
|
||||
func Prune(ctx context.Context) error {
|
||||
// Prune by default removes all non-running pods in local storage.
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
response, err := conn.DoRequest(nil, http.MethodPost, "/pods/prune", 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
|
||||
|
@ -262,7 +262,7 @@ var _ = Describe("Podman pods", func() {
|
||||
var newpod2 string = "newpod2"
|
||||
bt.Podcreate(&newpod2)
|
||||
// No pods pruned since no pod in exited state
|
||||
err = pods.Prune(bt.conn)
|
||||
pruneResponse, err := pods.Prune(bt.conn)
|
||||
Expect(err).To(BeNil())
|
||||
podSummary, err := pods.List(bt.conn, nil)
|
||||
Expect(err).To(BeNil())
|
||||
@ -279,13 +279,19 @@ var _ = Describe("Podman pods", func() {
|
||||
Expect(err).To(BeNil())
|
||||
// FIXME sujil please fix this
|
||||
//Expect(response.State.Status).To(Equal(define.PodStateExited))
|
||||
err = pods.Prune(bt.conn)
|
||||
pruneResponse, err = pods.Prune(bt.conn)
|
||||
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)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(podSummary)).To(Equal(1))
|
||||
|
||||
// Test prune all pods in exited state.
|
||||
// Test prune multiple pods.
|
||||
bt.Podcreate(&newpod)
|
||||
_, err = pods.Start(bt.conn, newpod)
|
||||
Expect(err).To(BeNil())
|
||||
@ -311,7 +317,7 @@ var _ = Describe("Podman pods", func() {
|
||||
Expect(define.StringToContainerStatus(i.State)).
|
||||
To(Equal(define.ContainerStateStopped))
|
||||
}
|
||||
err = pods.Prune(bt.conn)
|
||||
_, err = pods.Prune(bt.conn)
|
||||
Expect(err).To(BeNil())
|
||||
podSummary, err = pods.List(bt.conn, nil)
|
||||
Expect(err).To(BeNil())
|
||||
|
@ -49,6 +49,7 @@ type ContainerEngine interface {
|
||||
PodPs(ctx context.Context, options PodPSOptions) ([]*ListPodsReport, error)
|
||||
PodRestart(ctx context.Context, namesOrIds []string, options PodRestartOptions) ([]*PodRestartReport, 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)
|
||||
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
|
||||
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
|
||||
|
@ -147,6 +147,15 @@ func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
|
||||
s.CgroupParent = p.CGroupParent
|
||||
}
|
||||
|
||||
type PodPruneOptions struct {
|
||||
Force bool `json:"force" schema:"force"`
|
||||
}
|
||||
|
||||
type PodPruneReport struct {
|
||||
Err error
|
||||
Id string
|
||||
}
|
||||
|
||||
type PodTopOptions struct {
|
||||
// CLI flags.
|
||||
ListDescriptors bool
|
||||
|
@ -25,9 +25,7 @@ type Report struct {
|
||||
}
|
||||
|
||||
type PodDeleteReport struct{ Report }
|
||||
type PodPruneOptions struct{}
|
||||
|
||||
type PodPruneReport struct{ Report }
|
||||
type VolumeDeleteOptions struct{}
|
||||
type VolumeDeleteReport struct{ Report }
|
||||
|
||||
|
@ -243,6 +243,23 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
|
||||
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) {
|
||||
podSpec := specgen.NewPodSpecGenerator()
|
||||
opts.ToPodSpecGen(podSpec)
|
||||
|
@ -173,6 +173,10 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
|
||||
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) {
|
||||
podSpec := specgen.NewPodSpecGenerator()
|
||||
opts.ToPodSpecGen(podSpec)
|
||||
|
@ -36,7 +36,7 @@ var _ = Describe("Podman pod prune", func() {
|
||||
_, ec, _ := podmanTest.CreatePod("")
|
||||
Expect(ec).To(Equal(0))
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "prune"})
|
||||
result := podmanTest.Podman([]string{"pod", "prune", "--force"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
})
|
||||
@ -49,7 +49,7 @@ var _ = Describe("Podman pod prune", func() {
|
||||
ec2.WaitWithDefaultTimeout()
|
||||
Expect(ec2.ExitCode()).To(Equal(0))
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "prune"})
|
||||
result := podmanTest.Podman([]string{"pod", "prune", "-f"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To((Equal(0)))
|
||||
|
||||
@ -65,7 +65,7 @@ var _ = Describe("Podman pod prune", func() {
|
||||
_, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
|
||||
Expect(ec2).To(Equal(0))
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "prune"})
|
||||
result := podmanTest.Podman([]string{"pod", "prune", "-f"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
|
||||
@ -73,21 +73,4 @@ var _ = Describe("Podman pod prune", func() {
|
||||
result.WaitWithDefaultTimeout()
|
||||
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