mirror of
https://github.com/containers/podman
synced 2024-10-19 16:54:07 +00:00
Rework pruning to report reclaimed space
This change adds code to report the reclaimed space after a prune. Reclaimed space from volumes, images, and containers is recorded during the prune call in a PruneReport struct. These structs are collected into a slice during a system prune and processed afterwards to calculate the total reclaimed space. Closes #8658 Signed-off-by: Baron Lenardson <lenardson.baron@gmail.com>
This commit is contained in:
parent
c6c9b45985
commit
b90f7f9095
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/containers/podman/v2/cmd/podman/validate"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
dfilters "github.com/containers/podman/v2/pkg/domain/filters"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -90,7 +91,7 @@ Are you sure you want to continue? [y/N] `, volumeString)
|
|||
return err
|
||||
}
|
||||
// Print container prune results
|
||||
err = utils.PrintContainerPruneResults(response.ContainerPruneReport, true)
|
||||
err = utils.PrintContainerPruneResults(response.ContainerPruneReports, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -101,11 +102,17 @@ Are you sure you want to continue? [y/N] `, volumeString)
|
|||
}
|
||||
// Print Volume prune results
|
||||
if pruneOptions.Volume {
|
||||
err = utils.PrintVolumePruneResults(response.VolumePruneReport, true)
|
||||
err = utils.PrintVolumePruneResults(response.VolumePruneReports, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Print Images prune results
|
||||
return utils.PrintImagePruneResults(response.ImagePruneReport, true)
|
||||
err = utils.PrintImagePruneResults(response.ImagePruneReports, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Total reclaimed space: %s\n", units.HumanSize((float64)(response.ReclaimedSpace)))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
)
|
||||
|
||||
// IsDir returns true if the specified path refers to a directory.
|
||||
|
@ -41,21 +42,21 @@ func PrintPodPruneResults(podPruneReports []*entities.PodPruneReport, heading bo
|
|||
return errs.PrintErrors()
|
||||
}
|
||||
|
||||
func PrintContainerPruneResults(containerPruneReport *entities.ContainerPruneReport, heading bool) error {
|
||||
func PrintContainerPruneResults(containerPruneReports []*reports.PruneReport, heading bool) error {
|
||||
var errs OutputErrors
|
||||
if heading && (len(containerPruneReport.ID) > 0 || len(containerPruneReport.Err) > 0) {
|
||||
if heading && (len(containerPruneReports) > 0) {
|
||||
fmt.Println("Deleted Containers")
|
||||
}
|
||||
for k := range containerPruneReport.ID {
|
||||
fmt.Println(k)
|
||||
}
|
||||
for _, v := range containerPruneReport.Err {
|
||||
errs = append(errs, v)
|
||||
for _, v := range containerPruneReports {
|
||||
fmt.Println(v.Id)
|
||||
if v.Err != nil {
|
||||
errs = append(errs, v.Err)
|
||||
}
|
||||
}
|
||||
return errs.PrintErrors()
|
||||
}
|
||||
|
||||
func PrintVolumePruneResults(volumePruneReport []*entities.VolumePruneReport, heading bool) error {
|
||||
func PrintVolumePruneResults(volumePruneReport []*reports.PruneReport, heading bool) error {
|
||||
var errs OutputErrors
|
||||
if heading && len(volumePruneReport) > 0 {
|
||||
fmt.Println("Deleted Volumes")
|
||||
|
@ -70,18 +71,16 @@ func PrintVolumePruneResults(volumePruneReport []*entities.VolumePruneReport, he
|
|||
return errs.PrintErrors()
|
||||
}
|
||||
|
||||
func PrintImagePruneResults(imagePruneReport *entities.ImagePruneReport, heading bool) error {
|
||||
if heading && (len(imagePruneReport.Report.Id) > 0 || len(imagePruneReport.Report.Err) > 0) {
|
||||
func PrintImagePruneResults(imagePruneReports []*reports.PruneReport, heading bool) error {
|
||||
if heading {
|
||||
fmt.Println("Deleted Images")
|
||||
}
|
||||
for _, i := range imagePruneReport.Report.Id {
|
||||
fmt.Println(i)
|
||||
}
|
||||
for _, e := range imagePruneReport.Report.Err {
|
||||
fmt.Fprint(os.Stderr, e.Error()+"\n")
|
||||
}
|
||||
if imagePruneReport.Size > 0 {
|
||||
fmt.Fprintf(os.Stdout, "Size: %d\n", imagePruneReport.Size)
|
||||
for _, r := range imagePruneReports {
|
||||
fmt.Println(r.Id)
|
||||
if r.Err != nil {
|
||||
fmt.Fprint(os.Stderr, r.Err.Error()+"\n")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containers/podman/v2/libpod/events"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/timetype"
|
||||
"github.com/containers/storage"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -110,7 +111,8 @@ func (ir *Runtime) GetPruneImages(ctx context.Context, all bool, filterFuncs []I
|
|||
|
||||
// PruneImages prunes dangling and optionally all unused images from the local
|
||||
// image store
|
||||
func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) {
|
||||
func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]*reports.PruneReport, error) {
|
||||
preports := make([]*reports.PruneReport, 0)
|
||||
filterFuncs := make([]ImageFilter, 0, len(filter))
|
||||
for _, f := range filter {
|
||||
filterSplit := strings.SplitN(f, "=", 2)
|
||||
|
@ -125,7 +127,6 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
|
|||
filterFuncs = append(filterFuncs, generatedFunc)
|
||||
}
|
||||
|
||||
pruned := []string{}
|
||||
prev := 0
|
||||
for {
|
||||
toPrune, err := ir.GetPruneImages(ctx, all, filterFuncs)
|
||||
|
@ -143,6 +144,13 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameOrID := img.ID()
|
||||
s, err := img.Size(ctx)
|
||||
imgSize := *s
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to collect image size for: %s, %s", nameOrID, err)
|
||||
imgSize = 0
|
||||
}
|
||||
if err := img.Remove(ctx, false); err != nil {
|
||||
if errors.Cause(err) == storage.ErrImageUsedByContainer {
|
||||
logrus.Warnf("Failed to prune image %s as it is in use: %v.\nA container associated with containers/storage (e.g., Buildah, CRI-O, etc.) maybe associated with this image.\nUsing the rmi command with the --force option will remove the container and image, but may cause failures for other dependent systems.", img.ID(), err)
|
||||
|
@ -151,13 +159,18 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
|
|||
return nil, errors.Wrap(err, "failed to prune image")
|
||||
}
|
||||
defer img.newImageEvent(events.Prune)
|
||||
nameOrID := img.ID()
|
||||
|
||||
if len(repotags) > 0 {
|
||||
nameOrID = repotags[0]
|
||||
}
|
||||
pruned = append(pruned, nameOrID)
|
||||
|
||||
preports = append(preports, &reports.PruneReport{
|
||||
Id: nameOrID,
|
||||
Err: nil,
|
||||
Size: uint64(imgSize),
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return pruned, nil
|
||||
return preports, nil
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod/events"
|
||||
"github.com/containers/podman/v2/libpod/shutdown"
|
||||
"github.com/containers/podman/v2/pkg/cgroups"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
|
@ -884,9 +885,8 @@ func (r *Runtime) GetExecSessionContainer(id string) (*Container, error) {
|
|||
|
||||
// PruneContainers removes stopped and exited containers from localstorage. A set of optional filters
|
||||
// can be provided to be more granular.
|
||||
func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int64, map[string]error, error) {
|
||||
pruneErrors := make(map[string]error)
|
||||
prunedContainers := make(map[string]int64)
|
||||
func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) ([]*reports.PruneReport, error) {
|
||||
preports := make([]*reports.PruneReport, 0)
|
||||
// We add getting the exited and stopped containers via a filter
|
||||
containerStateFilter := func(c *Container) bool {
|
||||
if c.PodID() != "" {
|
||||
|
@ -906,23 +906,28 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
|
|||
filterFuncs = append(filterFuncs, containerStateFilter)
|
||||
delContainers, err := r.GetContainers(filterFuncs...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
for _, c := range delContainers {
|
||||
ctr := c
|
||||
size, err := ctr.RWSize()
|
||||
report := new(reports.PruneReport)
|
||||
report.Id = c.ID()
|
||||
report.Err = nil
|
||||
report.Size = 0
|
||||
size, err := c.RWSize()
|
||||
if err != nil {
|
||||
pruneErrors[ctr.ID()] = err
|
||||
report.Err = err
|
||||
preports = append(preports, report)
|
||||
continue
|
||||
}
|
||||
err = r.RemoveContainer(context.Background(), ctr, false, false)
|
||||
err = r.RemoveContainer(context.Background(), c, false, false)
|
||||
if err != nil {
|
||||
pruneErrors[ctr.ID()] = err
|
||||
report.Err = err
|
||||
} else {
|
||||
prunedContainers[ctr.ID()] = size
|
||||
report.Size = (uint64)(size)
|
||||
}
|
||||
preports = append(preports, report)
|
||||
}
|
||||
return prunedContainers, pruneErrors, nil
|
||||
return preports, nil
|
||||
}
|
||||
|
||||
// MountStorageContainer mounts the storage container's root filesystem
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/libpod/events"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -133,22 +134,32 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
|
|||
}
|
||||
|
||||
// PruneVolumes removes unused volumes from the system
|
||||
func (r *Runtime) PruneVolumes(ctx context.Context, filterFuncs []VolumeFilter) (map[string]error, error) {
|
||||
reports := make(map[string]error)
|
||||
func (r *Runtime) PruneVolumes(ctx context.Context, filterFuncs []VolumeFilter) ([]*reports.PruneReport, error) {
|
||||
preports := make([]*reports.PruneReport, 0)
|
||||
vols, err := r.Volumes(filterFuncs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, vol := range vols {
|
||||
report := new(reports.PruneReport)
|
||||
volSize, err := vol.Size()
|
||||
if err != nil {
|
||||
volSize = 0
|
||||
}
|
||||
report.Size = volSize
|
||||
report.Id = vol.Name()
|
||||
if err := r.RemoveVolume(ctx, vol, false); err != nil {
|
||||
if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved {
|
||||
reports[vol.Name()] = err
|
||||
report.Err = err
|
||||
} else {
|
||||
// We didn't remove the volume for some reason
|
||||
continue
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
vol.newVolumeEvent(events.Prune)
|
||||
}
|
||||
vol.newVolumeEvent(events.Prune)
|
||||
reports[vol.Name()] = nil
|
||||
preports = append(preports, report)
|
||||
}
|
||||
return reports, nil
|
||||
return preports, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package libpod
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
|
@ -79,6 +81,18 @@ func (v *Volume) Name() string {
|
|||
return v.config.Name
|
||||
}
|
||||
|
||||
// Returns the size on disk of volume
|
||||
func (v *Volume) Size() (uint64, error) {
|
||||
var size uint64
|
||||
err := filepath.Walk(v.config.MountPoint, func(path string, info os.FileInfo, err error) error {
|
||||
if err == nil && !info.IsDir() {
|
||||
size += (uint64)(info.Size())
|
||||
}
|
||||
return err
|
||||
})
|
||||
return size, err
|
||||
}
|
||||
|
||||
// Driver retrieves the volume's driver.
|
||||
func (v *Volume) Driver() string {
|
||||
return v.config.Driver
|
||||
|
|
|
@ -5,18 +5,13 @@ import (
|
|||
|
||||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/domain/filters"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func PruneContainers(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
delContainers []string
|
||||
space int64
|
||||
)
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
|
||||
|
@ -49,36 +44,21 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
|
||||
report, err := runtime.PruneContainers(filterFuncs)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
for ctrID, size := range prunedContainers {
|
||||
if pruneErrors[ctrID] == nil {
|
||||
space += size
|
||||
delContainers = append(delContainers, ctrID)
|
||||
}
|
||||
}
|
||||
report := types.ContainersPruneReport{
|
||||
ContainersDeleted: delContainers,
|
||||
SpaceReclaimed: uint64(space),
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, report)
|
||||
}
|
||||
|
||||
func PruneContainersHelper(w http.ResponseWriter, r *http.Request, filterFuncs []libpod.ContainerFilter) (
|
||||
*entities.ContainerPruneReport, error) {
|
||||
[]*reports.PruneReport, error) {
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
|
||||
reports, err := runtime.PruneContainers(filterFuncs)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := &entities.ContainerPruneReport{
|
||||
Err: pruneErrors,
|
||||
ID: prunedContainers,
|
||||
}
|
||||
return report, nil
|
||||
return reports, nil
|
||||
}
|
||||
|
|
|
@ -99,21 +99,23 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
|
|||
filters = append(filters, fmt.Sprintf("%s=%s", k, val))
|
||||
}
|
||||
}
|
||||
pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
|
||||
imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
for _, p := range pruneCids {
|
||||
reclaimedSpace := uint64(0)
|
||||
for _, p := range imagePruneReports {
|
||||
idr = append(idr, types.ImageDeleteResponseItem{
|
||||
Deleted: p,
|
||||
Deleted: p.Id,
|
||||
})
|
||||
reclaimedSpace = reclaimedSpace + p.Size
|
||||
}
|
||||
|
||||
// FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
|
||||
ipr := types.ImagesPruneReport{
|
||||
ImagesDeleted: idr,
|
||||
SpaceReclaimed: 1, // TODO we cannot supply this right now
|
||||
SpaceReclaimed: reclaimedSpace,
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, handlers.ImagesPruneReport{ImagesPruneReport: ipr})
|
||||
}
|
||||
|
|
|
@ -269,9 +269,9 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
prunedIds := make([]string, 0, len(pruned))
|
||||
for k := range pruned {
|
||||
for _, v := range pruned {
|
||||
// XXX: This drops any pruning per-volume error messages on the floor
|
||||
prunedIds = append(prunedIds, k)
|
||||
prunedIds = append(prunedIds, v.Id)
|
||||
}
|
||||
pruneResponse := docker_api_types.VolumesPruneReport{
|
||||
VolumesDeleted: prunedIds,
|
||||
|
|
|
@ -156,12 +156,12 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
|
||||
imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
|
||||
if err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, cids)
|
||||
utils.WriteResponse(w, http.StatusOK, imagePruneReports)
|
||||
}
|
||||
|
||||
func ExportImage(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -38,35 +38,28 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
|
|||
systemPruneReport.PodPruneReport = podPruneReport
|
||||
|
||||
// We could parallelize this, should we?
|
||||
containerPruneReport, err := compat.PruneContainersHelper(w, r, nil)
|
||||
containerPruneReports, err := compat.PruneContainersHelper(w, r, nil)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
systemPruneReport.ContainerPruneReport = containerPruneReport
|
||||
systemPruneReport.ContainerPruneReports = containerPruneReports
|
||||
|
||||
results, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
|
||||
imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
report := entities.ImagePruneReport{
|
||||
Report: entities.Report{
|
||||
Id: results,
|
||||
Err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
systemPruneReport.ImagePruneReport = &report
|
||||
systemPruneReport.ImagePruneReports = imagePruneReports
|
||||
|
||||
if query.Volumes {
|
||||
volumePruneReport, err := pruneVolumesHelper(r)
|
||||
volumePruneReports, err := pruneVolumesHelper(r)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
systemPruneReport.VolumePruneReport = volumePruneReport
|
||||
systemPruneReport.VolumePruneReports = volumePruneReports
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, systemPruneReport)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/domain/filters"
|
||||
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
|
||||
"github.com/gorilla/schema"
|
||||
|
@ -178,7 +179,7 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
|
|||
utils.WriteResponse(w, http.StatusOK, reports)
|
||||
}
|
||||
|
||||
func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) {
|
||||
func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
|
||||
var (
|
||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
||||
|
@ -199,17 +200,10 @@ func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pruned, err := runtime.PruneVolumes(r.Context(), filterFuncs)
|
||||
reports, err := runtime.PruneVolumes(r.Context(), filterFuncs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reports := make([]*entities.VolumePruneReport, 0, len(pruned))
|
||||
for k, v := range pruned {
|
||||
reports = append(reports, &entities.VolumePruneReport{
|
||||
Err: v,
|
||||
Id: k,
|
||||
})
|
||||
}
|
||||
return reports, nil
|
||||
}
|
||||
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
)
|
||||
|
||||
// No such image
|
||||
|
@ -170,7 +171,7 @@ type ok struct {
|
|||
// swagger:response VolumePruneResponse
|
||||
type swagVolumePruneResponse struct {
|
||||
// in:body
|
||||
Body []entities.VolumePruneReport
|
||||
Body []reports.PruneReport
|
||||
}
|
||||
|
||||
// Volume create response
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/containers/podman/v2/pkg/api/handlers"
|
||||
"github.com/containers/podman/v2/pkg/bindings"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -49,11 +50,11 @@ func List(ctx context.Context, options *ListOptions) ([]entities.ListContainer,
|
|||
// used for more granular selection of containers. The main error returned indicates if there were runtime
|
||||
// errors like finding containers. Errors specific to the removal of a container are in the PruneContainerResponse
|
||||
// structure.
|
||||
func Prune(ctx context.Context, options *PruneOptions) (*entities.ContainerPruneReport, error) {
|
||||
func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
|
||||
if options == nil {
|
||||
options = new(PruneOptions)
|
||||
}
|
||||
var reports *entities.ContainerPruneReport
|
||||
var reports []*reports.PruneReport
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/containers/podman/v2/pkg/auth"
|
||||
"github.com/containers/podman/v2/pkg/bindings"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -163,9 +164,9 @@ func Export(ctx context.Context, nameOrIDs []string, w io.Writer, options *Expor
|
|||
|
||||
// Prune removes unused images from local storage. The optional filters can be used to further
|
||||
// define which images should be pruned.
|
||||
func Prune(ctx context.Context, options *PruneOptions) ([]string, error) {
|
||||
func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
|
||||
var (
|
||||
deleted []string
|
||||
deleted []*reports.PruneReport
|
||||
)
|
||||
if options == nil {
|
||||
options = new(PruneOptions)
|
||||
|
@ -182,7 +183,8 @@ func Prune(ctx context.Context, options *PruneOptions) ([]string, error) {
|
|||
if err != nil {
|
||||
return deleted, err
|
||||
}
|
||||
return deleted, response.Process(&deleted)
|
||||
err = response.Process(&deleted)
|
||||
return deleted, err
|
||||
}
|
||||
|
||||
// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/bindings"
|
||||
"github.com/containers/podman/v2/pkg/bindings/containers"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/specgen"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
@ -533,8 +534,8 @@ var _ = Describe("Podman containers ", func() {
|
|||
// Prune container should return no errors and one pruned container ID.
|
||||
pruneResponse, err := containers.Prune(bt.conn, nil)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(pruneResponse.Err)).To(Equal(0))
|
||||
Expect(len(pruneResponse.ID)).To(Equal(1))
|
||||
Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
|
||||
Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
|
||||
})
|
||||
|
||||
It("podman prune stopped containers with filters", func() {
|
||||
|
@ -558,8 +559,8 @@ var _ = Describe("Podman containers ", func() {
|
|||
}
|
||||
pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(pruneResponse.Err)).To(Equal(0))
|
||||
Expect(len(pruneResponse.ID)).To(Equal(0))
|
||||
Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(0))
|
||||
Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
|
||||
|
||||
// Valid filter params container should be pruned now.
|
||||
filters := map[string][]string{
|
||||
|
@ -567,8 +568,8 @@ var _ = Describe("Podman containers ", func() {
|
|||
}
|
||||
pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filters))
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(pruneResponse.Err)).To(Equal(0))
|
||||
Expect(len(pruneResponse.ID)).To(Equal(1))
|
||||
Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
|
||||
Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
|
||||
})
|
||||
|
||||
It("podman prune running containers", func() {
|
||||
|
@ -585,7 +586,7 @@ var _ = Describe("Podman containers ", func() {
|
|||
// Prune. Should return no error no prune response ID.
|
||||
pruneResponse, err := containers.Prune(bt.conn, nil)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(pruneResponse.ID)).To(Equal(0))
|
||||
Expect(len(pruneResponse)).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman inspect bogus container", func() {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/containers/podman/v2/pkg/bindings"
|
||||
"github.com/containers/podman/v2/pkg/bindings/containers"
|
||||
"github.com/containers/podman/v2/pkg/bindings/images"
|
||||
dreports "github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/gexec"
|
||||
|
@ -355,7 +356,7 @@ var _ = Describe("Podman images", func() {
|
|||
results, err := images.Prune(bt.conn, options)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(results)).To(BeNumerically(">", 0))
|
||||
Expect(results).To(ContainElement("docker.io/library/alpine:latest"))
|
||||
Expect(dreports.PruneReportsIds(results)).To(ContainElement("docker.io/library/alpine:latest"))
|
||||
})
|
||||
|
||||
// TODO: we really need to extent to pull tests once we have a more sophisticated CI.
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/containers/podman/v2/pkg/bindings/system"
|
||||
"github.com/containers/podman/v2/pkg/bindings/volumes"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/gexec"
|
||||
|
@ -80,12 +81,12 @@ var _ = Describe("Podman system", func() {
|
|||
systemPruneResponse, err := system.Prune(bt.conn, options)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
|
||||
Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReports)).
|
||||
To(BeNumerically(">", 0))
|
||||
Expect(systemPruneResponse.ImagePruneReport.Report.Id).
|
||||
Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
|
||||
To(ContainElement("docker.io/library/alpine:latest"))
|
||||
Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
|
||||
Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman system prune running alpine container", func() {
|
||||
|
@ -114,14 +115,14 @@ var _ = Describe("Podman system", func() {
|
|||
systemPruneResponse, err := system.Prune(bt.conn, options)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
|
||||
Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReports)).
|
||||
To(BeNumerically(">", 0))
|
||||
// Alpine image should not be pruned as used by running container
|
||||
Expect(systemPruneResponse.ImagePruneReport.Report.Id).
|
||||
Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
|
||||
ToNot(ContainElement("docker.io/library/alpine:latest"))
|
||||
// Though unused volume is available it should not be pruned as flag set to false.
|
||||
Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
|
||||
Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman system prune running alpine container volume prune", func() {
|
||||
|
@ -149,14 +150,14 @@ var _ = Describe("Podman system", func() {
|
|||
systemPruneResponse, err := system.Prune(bt.conn, options)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
|
||||
Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
|
||||
Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReports)).
|
||||
To(BeNumerically(">", 0))
|
||||
// Alpine image should not be pruned as used by running container
|
||||
Expect(systemPruneResponse.ImagePruneReport.Report.Id).
|
||||
Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
|
||||
ToNot(ContainElement("docker.io/library/alpine:latest"))
|
||||
// Volume should be pruned now as flag set true
|
||||
Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
|
||||
})
|
||||
|
||||
It("podman system prune running alpine container volume prune --filter", func() {
|
||||
|
@ -197,14 +198,14 @@ var _ = Describe("Podman system", func() {
|
|||
// This check **should** be "Equal(0)" since we are passing label
|
||||
// filters however the Prune function doesn't seem to pass filters
|
||||
// to each component.
|
||||
Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
|
||||
Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.ImagePruneReports)).
|
||||
To(BeNumerically(">", 0))
|
||||
// Alpine image should not be pruned as used by running container
|
||||
Expect(systemPruneResponse.ImagePruneReport.Report.Id).
|
||||
Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
|
||||
ToNot(ContainElement("docker.io/library/alpine:latest"))
|
||||
// Volume shouldn't be pruned because the PruneOptions filters doesn't match
|
||||
Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
|
||||
Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
|
||||
|
||||
// Fix filter and re prune
|
||||
f["label"] = []string{"label1=value1"}
|
||||
|
@ -213,6 +214,6 @@ var _ = Describe("Podman system", func() {
|
|||
Expect(err).To(BeNil())
|
||||
|
||||
// Volume should be pruned because the PruneOptions filters now match
|
||||
Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
|
||||
Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/containers/podman/v2/pkg/bindings/containers"
|
||||
"github.com/containers/podman/v2/pkg/bindings/volumes"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/gexec"
|
||||
|
@ -166,7 +167,7 @@ var _ = Describe("Podman volumes", func() {
|
|||
session.Wait(45)
|
||||
vols, err = volumes.Prune(connText, nil)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(vols)).To(BeNumerically("==", 1))
|
||||
Expect(len(reports.PruneReportsIds(vols))).To(BeNumerically("==", 1))
|
||||
_, err = volumes.Inspect(connText, "homer", nil)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/containers/podman/v2/pkg/bindings"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
|
@ -77,9 +78,9 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.VolumeListRepo
|
|||
}
|
||||
|
||||
// Prune removes unused volumes from the local filesystem.
|
||||
func Prune(ctx context.Context, options *PruneOptions) ([]*entities.VolumePruneReport, error) {
|
||||
func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
|
||||
var (
|
||||
pruned []*entities.VolumePruneReport
|
||||
pruned []*reports.PruneReport
|
||||
)
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
|
|
|
@ -390,13 +390,6 @@ type ContainerPruneOptions struct {
|
|||
Filters url.Values `json:"filters" schema:"filters"`
|
||||
}
|
||||
|
||||
// ContainerPruneReport describes the results after pruning the
|
||||
// stopped containers.
|
||||
type ContainerPruneReport struct {
|
||||
ID map[string]int64
|
||||
Err map[string]error
|
||||
}
|
||||
|
||||
// ContainerPortOptions describes the options to obtain
|
||||
// port information on containers
|
||||
type ContainerPortOptions struct {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/specgen"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -35,7 +36,7 @@ type ContainerEngine interface {
|
|||
ContainerMount(ctx context.Context, nameOrIDs []string, options ContainerMountOptions) ([]*ContainerMountReport, error)
|
||||
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
|
||||
ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error)
|
||||
ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error)
|
||||
ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error)
|
||||
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
|
||||
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
|
||||
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
|
||||
|
@ -85,6 +86,6 @@ type ContainerEngine interface {
|
|||
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
|
||||
VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
|
||||
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
|
||||
VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*VolumePruneReport, error)
|
||||
VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*reports.PruneReport, error)
|
||||
VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
)
|
||||
|
||||
type ImageEngine interface {
|
||||
|
@ -17,7 +18,7 @@ type ImageEngine interface {
|
|||
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
|
||||
Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
|
||||
Mount(ctx context.Context, images []string, options ImageMountOptions) ([]*ImageMountReport, error)
|
||||
Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
|
||||
Prune(ctx context.Context, opts ImagePruneOptions) ([]*reports.PruneReport, error)
|
||||
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error)
|
||||
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error
|
||||
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
|
||||
|
|
|
@ -247,11 +247,6 @@ type ImagePruneOptions struct {
|
|||
Filter []string `json:"filter" schema:"filter"`
|
||||
}
|
||||
|
||||
type ImagePruneReport struct {
|
||||
Report Report
|
||||
Size int64
|
||||
}
|
||||
|
||||
type ImageTagOptions struct{}
|
||||
type ImageUntagOptions struct{}
|
||||
|
||||
|
|
40
pkg/domain/entities/reports/prune.go
Normal file
40
pkg/domain/entities/reports/prune.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package reports
|
||||
|
||||
type PruneReport struct {
|
||||
Id string //nolint
|
||||
Err error
|
||||
Size uint64
|
||||
}
|
||||
|
||||
func PruneReportsIds(r []*PruneReport) []string {
|
||||
ids := make([]string, 0, len(r))
|
||||
for _, v := range r {
|
||||
if v == nil || v.Id == "" {
|
||||
continue
|
||||
}
|
||||
ids = append(ids, v.Id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func PruneReportsErrs(r []*PruneReport) []error {
|
||||
errs := make([]error, 0, len(r))
|
||||
for _, v := range r {
|
||||
if v == nil || v.Err == nil {
|
||||
continue
|
||||
}
|
||||
errs = append(errs, v.Err)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func PruneReportsSize(r []*PruneReport) uint64 {
|
||||
size := uint64(0)
|
||||
for _, v := range r {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
size = size + v.Size
|
||||
}
|
||||
return size
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -24,10 +25,11 @@ type SystemPruneOptions struct {
|
|||
|
||||
// SystemPruneReport provides report after system prune is executed.
|
||||
type SystemPruneReport struct {
|
||||
PodPruneReport []*PodPruneReport
|
||||
*ContainerPruneReport
|
||||
*ImagePruneReport
|
||||
VolumePruneReport []*VolumePruneReport
|
||||
PodPruneReport []*PodPruneReport
|
||||
ContainerPruneReports []*reports.PruneReport
|
||||
ImagePruneReports []*reports.PruneReport
|
||||
VolumePruneReports []*reports.PruneReport
|
||||
ReclaimedSpace uint64
|
||||
}
|
||||
|
||||
// SystemMigrateOptions describes the options needed for the
|
||||
|
|
|
@ -116,11 +116,6 @@ type VolumePruneOptions struct {
|
|||
Filters url.Values `json:"filters" schema:"filters"`
|
||||
}
|
||||
|
||||
type VolumePruneReport struct {
|
||||
Err error
|
||||
Id string //nolint
|
||||
}
|
||||
|
||||
type VolumeListOptions struct {
|
||||
Filter map[string][]string
|
||||
}
|
||||
|
|
|
@ -233,7 +233,6 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
|
|||
}
|
||||
return false
|
||||
}, nil
|
||||
|
||||
}
|
||||
return nil, errors.Errorf("%s is an invalid filter", filter)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/containers/podman/v2/pkg/cgroups"
|
||||
"github.com/containers/podman/v2/pkg/checkpoint"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
dfilters "github.com/containers/podman/v2/pkg/domain/filters"
|
||||
"github.com/containers/podman/v2/pkg/domain/infra/abi/terminal"
|
||||
parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr"
|
||||
|
@ -204,7 +205,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
|
|||
return reports, nil
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
|
||||
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
|
||||
filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
|
||||
for k, v := range options.Filters {
|
||||
generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
|
||||
|
@ -213,19 +214,7 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.
|
|||
}
|
||||
filterFuncs = append(filterFuncs, generatedFunc)
|
||||
}
|
||||
return ic.pruneContainersHelper(filterFuncs)
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) {
|
||||
prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
report := entities.ContainerPruneReport{
|
||||
ID: prunedContainers,
|
||||
Err: pruneErrors,
|
||||
}
|
||||
return &report, nil
|
||||
return ic.Libpod.PruneContainers(filterFuncs)
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod/image"
|
||||
libpodImage "github.com/containers/podman/v2/libpod/image"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
domainUtils "github.com/containers/podman/v2/pkg/domain/utils"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
|
@ -49,19 +50,12 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo
|
|||
return &entities.BoolReport{Value: err == nil}, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
|
||||
results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
|
||||
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
|
||||
reports, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImagePruneReport{
|
||||
Report: entities.Report{
|
||||
Id: results,
|
||||
Err: nil,
|
||||
},
|
||||
}
|
||||
return &report, nil
|
||||
return reports, err
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/cgroups"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
"github.com/containers/podman/v2/utils"
|
||||
|
@ -170,6 +171,7 @@ func checkInput() error { // nolint:deadcode,unused
|
|||
func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
|
||||
var systemPruneReport = new(entities.SystemPruneReport)
|
||||
var filters []string
|
||||
reclaimedSpace := (uint64)(0)
|
||||
found := true
|
||||
for found {
|
||||
found = false
|
||||
|
@ -186,42 +188,26 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
|
|||
containerPruneOptions := entities.ContainerPruneOptions{}
|
||||
containerPruneOptions.Filters = (url.Values)(options.Filters)
|
||||
|
||||
containerPruneReport, err := ic.ContainerPrune(ctx, containerPruneOptions)
|
||||
containerPruneReports, err := ic.ContainerPrune(ctx, containerPruneOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(containerPruneReport.ID) > 0 {
|
||||
found = true
|
||||
}
|
||||
if systemPruneReport.ContainerPruneReport == nil {
|
||||
systemPruneReport.ContainerPruneReport = containerPruneReport
|
||||
} else {
|
||||
for name, val := range containerPruneReport.ID {
|
||||
systemPruneReport.ContainerPruneReport.ID[name] = val
|
||||
}
|
||||
}
|
||||
reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(containerPruneReports)
|
||||
systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...)
|
||||
for k, v := range options.Filters {
|
||||
filters = append(filters, fmt.Sprintf("%s=%s", k, v[0]))
|
||||
}
|
||||
results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
|
||||
imagePruneReports, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
|
||||
reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(imagePruneReports)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(results) > 0 {
|
||||
if len(imagePruneReports) > 0 {
|
||||
found = true
|
||||
}
|
||||
|
||||
if systemPruneReport.ImagePruneReport == nil {
|
||||
systemPruneReport.ImagePruneReport = &entities.ImagePruneReport{
|
||||
Report: entities.Report{
|
||||
Id: results,
|
||||
Err: nil,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...)
|
||||
}
|
||||
systemPruneReport.ImagePruneReports = append(systemPruneReport.ImagePruneReports, imagePruneReports...)
|
||||
if options.Volume {
|
||||
volumePruneOptions := entities.VolumePruneOptions{}
|
||||
volumePruneOptions.Filters = (url.Values)(options.Filters)
|
||||
|
@ -232,9 +218,11 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
|
|||
if len(volumePruneReport) > 0 {
|
||||
found = true
|
||||
}
|
||||
systemPruneReport.VolumePruneReport = append(systemPruneReport.VolumePruneReport, volumePruneReport...)
|
||||
reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(volumePruneReport)
|
||||
systemPruneReport.VolumePruneReports = append(systemPruneReport.VolumePruneReports, volumePruneReport...)
|
||||
}
|
||||
}
|
||||
systemPruneReport.ReclaimedSpace = reclaimedSpace
|
||||
return systemPruneReport, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/domain/filters"
|
||||
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -127,7 +128,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
|
|||
return reports, errs, nil
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
|
||||
func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
|
||||
filterFuncs, err := filters.GenerateVolumeFilters(options.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -135,19 +136,12 @@ func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.Vol
|
|||
return ic.pruneVolumesHelper(ctx, filterFuncs)
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*entities.VolumePruneReport, error) {
|
||||
func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*reports.PruneReport, error) {
|
||||
pruned, err := ic.Libpod.PruneVolumes(ctx, filterFuncs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reports := make([]*entities.VolumePruneReport, 0, len(pruned))
|
||||
for k, v := range pruned {
|
||||
reports = append(reports, &entities.VolumePruneReport{
|
||||
Err: v,
|
||||
Id: k,
|
||||
})
|
||||
}
|
||||
return reports, nil
|
||||
return pruned, nil
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/containers/podman/v2/pkg/api/handlers"
|
||||
"github.com/containers/podman/v2/pkg/bindings/containers"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/errorhandling"
|
||||
"github.com/containers/podman/v2/pkg/specgen"
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
|
@ -196,7 +197,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
|
|||
return reports, nil
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
|
||||
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
|
||||
options := new(containers.PruneOptions).WithFilters(opts.Filters)
|
||||
return containers.Prune(ic.ClientCtx, options)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/containers/image/v5/docker/reference"
|
||||
images "github.com/containers/podman/v2/pkg/bindings/images"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/containers/podman/v2/pkg/domain/utils"
|
||||
utils2 "github.com/containers/podman/v2/utils"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -90,26 +91,18 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti
|
|||
return &history, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
|
||||
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
|
||||
filters := make(map[string][]string, len(opts.Filter))
|
||||
for _, filter := range opts.Filter {
|
||||
f := strings.Split(filter, "=")
|
||||
filters[f[0]] = f[1:]
|
||||
}
|
||||
options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters)
|
||||
results, err := images.Prune(ir.ClientCtx, options)
|
||||
reports, err := images.Prune(ir.ClientCtx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImagePruneReport{
|
||||
Report: entities.Report{
|
||||
Id: results,
|
||||
Err: nil,
|
||||
},
|
||||
Size: 0,
|
||||
}
|
||||
return &report, nil
|
||||
return reports, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/containers/podman/v2/pkg/bindings/volumes"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities/reports"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -69,7 +70,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
|
|||
return reports, errs, nil
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
|
||||
func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
|
||||
options := new(volumes.PruneOptions).WithFilters(opts.Filters)
|
||||
return volumes.Prune(ic.ClientCtx, options)
|
||||
}
|
||||
|
|
|
@ -58,10 +58,10 @@ t GET libpod/system/df 200 '.Volumes | length=3'
|
|||
|
||||
# -G --data-urlencode 'volumes=true&filters={"label":["testlabel1=testonly"]}'
|
||||
# only foo3 should be pruned because of filter
|
||||
t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D' params='' 200 .VolumePruneReport[0].Id=foo3
|
||||
t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D' params='' 200 .VolumePruneReports[0].Id=foo3
|
||||
# only foo2 should be pruned because of filter
|
||||
t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1%22%5D%7D' params='' 200 .VolumePruneReport[0].Id=foo2
|
||||
t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1%22%5D%7D' params='' 200 .VolumePruneReports[0].Id=foo2
|
||||
# foo1, the last remaining volume should be pruned without any filters applied
|
||||
t POST 'libpod/system/prune?volumes=true' params='' 200 .VolumePruneReport[0].Id=foo1
|
||||
t POST 'libpod/system/prune?volumes=true' params='' 200 .VolumePruneReports[0].Id=foo1
|
||||
|
||||
# TODO add other system prune tests for pods / images
|
||||
|
|
Loading…
Reference in a new issue