diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go index 93b4a1157c..87bb947ed8 100644 --- a/cmd/podman/system/prune.go +++ b/cmd/podman/system/prune.go @@ -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 } diff --git a/cmd/podman/utils/utils.go b/cmd/podman/utils/utils.go index 2ca2c4c925..f42243f697 100644 --- a/cmd/podman/utils/utils.go +++ b/cmd/podman/utils/utils.go @@ -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 } diff --git a/libpod/image/prune.go b/libpod/image/prune.go index b38265a7ef..3c06a89c2e 100644 --- a/libpod/image/prune.go +++ b/libpod/image/prune.go @@ -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 } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 14b537ca2e..f22e48746e 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -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 diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go index 10c32a1196..9d985f9057 100644 --- a/libpod/runtime_volume.go +++ b/libpod/runtime_volume.go @@ -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 } diff --git a/libpod/volume.go b/libpod/volume.go index 0535bf4dbf..ed08d375f5 100644 --- a/libpod/volume.go +++ b/libpod/volume.go @@ -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 diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go index a1e35dd972..b3d26b8f4a 100644 --- a/pkg/api/handlers/compat/containers_prune.go +++ b/pkg/api/handlers/compat/containers_prune.go @@ -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 } diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index dc72500e48..9d7503aba5 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -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}) } diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go index f49f06b178..1188d8f847 100644 --- a/pkg/api/handlers/compat/volumes.go +++ b/pkg/api/handlers/compat/volumes.go @@ -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, diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 0b8712f166..979a8adc48 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -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) { diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go index b157dfc7b5..130e563aee 100644 --- a/pkg/api/handlers/libpod/system.go +++ b/pkg/api/handlers/libpod/system.go @@ -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) } diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index b02a6a8ce9..6f95375152 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -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) { diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index 6d349bb7d0..45253e01a6 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -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 diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 650aa9ac51..1081a0e61c 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -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 diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go index 9beb493c85..ecdd1f5532 100644 --- a/pkg/bindings/images/images.go +++ b/pkg/bindings/images/images.go @@ -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. diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index 2ab5e45d0b..fa601e7e5c 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -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() { diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index e178f42195..c6b9c20f90 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -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. diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go index 25fda55750..44067b61d7 100644 --- a/pkg/bindings/test/system_test.go +++ b/pkg/bindings/test/system_test.go @@ -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)) }) }) diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go index e0d854b667..1f1da3cfae 100644 --- a/pkg/bindings/test/volumes_test.go +++ b/pkg/bindings/test/volumes_test.go @@ -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()) diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go index 626f52d390..fe081eb469 100644 --- a/pkg/bindings/volumes/volumes.go +++ b/pkg/bindings/volumes/volumes.go @@ -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 { diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index b8d49d0679..05b9b774eb 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -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 { diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 80127ea457..7d38a97f2c 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -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) } diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go index 7f33d8e9d2..26a136f139 100644 --- a/pkg/domain/entities/engine_image.go +++ b/pkg/domain/entities/engine_image.go @@ -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) diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 67910a34c1..d5f88502a4 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -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{} diff --git a/pkg/domain/entities/reports/prune.go b/pkg/domain/entities/reports/prune.go new file mode 100644 index 0000000000..5494ac3ae5 --- /dev/null +++ b/pkg/domain/entities/reports/prune.go @@ -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 +} diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go index d5118f6a85..99fa947f07 100644 --- a/pkg/domain/entities/system.go +++ b/pkg/domain/entities/system.go @@ -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 diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go index e6b29e374a..06438f5e9e 100644 --- a/pkg/domain/entities/volumes.go +++ b/pkg/domain/entities/volumes.go @@ -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 } diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go index 6abdd6b577..ce6c12b715 100644 --- a/pkg/domain/filters/containers.go +++ b/pkg/domain/filters/containers.go @@ -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) } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index cfb3421bae..9d7c2daea5 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -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) { diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 394ba359ca..19f081abb3 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -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) { diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 5f6c95d4f9..67c0181222 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -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 } diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go index 515e52754f..3c9dd9fc02 100644 --- a/pkg/domain/infra/abi/volumes.go +++ b/pkg/domain/infra/abi/volumes.go @@ -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) { diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 0db985dffb..3366cb4252 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -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) } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 10bf9682c8..fba60235ec 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -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) { diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go index e6ad4e0c5a..10e8d7da85 100644 --- a/pkg/domain/infra/tunnel/volumes.go +++ b/pkg/domain/infra/tunnel/volumes.go @@ -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) } diff --git a/test/apiv2/45-system.at b/test/apiv2/45-system.at index 7d14fd4b36..44cd05a134 100644 --- a/test/apiv2/45-system.at +++ b/test/apiv2/45-system.at @@ -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