Merge pull request #5733 from sujil02/v2-pod-prune
Add pod prune for api v2
This commit is contained in:
		
						commit
						e4e42b28df
					
				| 
						 | 
				
			
			@ -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())
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue