Skip to content

Commit

Permalink
Merge pull request #5632 from jwhonce/wip/images
Browse files Browse the repository at this point in the history
V2 podman image prune
  • Loading branch information
openshift-merge-robot authored Mar 27, 2020
2 parents 4233250 + 581dd31 commit 2c5c198
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 33 deletions.
2 changes: 1 addition & 1 deletion cmd/podmanV2/images/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var (
Args: listCmd.Args,
Short: listCmd.Short,
Long: listCmd.Long,
PreRunE: listCmd.PreRunE,
PreRunE: preRunE,
RunE: listCmd.RunE,
Example: strings.Replace(listCmd.Example, "podman image list", "podman images", -1),
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/podmanV2/images/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func imageListFormat(flags listFlagType) (string, string) {
row += "\t{{.Digest}}"
}

hdr += "\tID"
hdr += "\tIMAGE ID"
if flags.noTrunc {
row += "\tsha256:{{.ID}}"
} else {
Expand Down
86 changes: 86 additions & 0 deletions cmd/podmanV2/images/prune.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package images

import (
"bufio"
"fmt"
"os"
"strings"

"github.com/containers/libpod/cmd/podmanV2/registry"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

var (
pruneDescription = `Removes all unnamed images from local storage.
If an image is not being used by a container, it will be removed from the system.`
pruneCmd = &cobra.Command{
Use: "prune",
Args: cobra.NoArgs,
Short: "Remove unused images",
Long: pruneDescription,
RunE: prune,
Example: `podman image prune`,
}

pruneOpts = entities.ImagePruneOptions{}
force bool
filter = []string{}
)

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: pruneCmd,
Parent: imageCmd,
})

flags := pruneCmd.Flags()
flags.BoolVarP(&pruneOpts.All, "all", "a", false, "Remove all unused images, not just dangling ones")
flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation")
flags.StringArrayVar(&filter, "filter", []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")

}

func prune(cmd *cobra.Command, args []string) error {
if !force {
reader := bufio.NewReader(os.Stdin)
fmt.Printf(`
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] `)
answer, err := reader.ReadString('\n')
if err != nil {
return errors.Wrapf(err, "error reading input")
}
if strings.ToLower(answer)[0] != 'y' {
return nil
}
}

// TODO Remove once filter refactor is finished and url.Values rules :)
for _, f := range filter {
t := strings.SplitN(f, "=", 2)
pruneOpts.Filters.Add(t[0], t[1])
}

results, err := registry.ImageEngine().Prune(registry.GetContext(), pruneOpts)
if err != nil {
return err
}

for _, i := range results.Report.Id {
fmt.Println(i)
}

for _, e := range results.Report.Err {
fmt.Fprint(os.Stderr, e.Error()+"\n")
}

if results.Size > 0 {
fmt.Fprintf(os.Stdout, "Size: %d\n", results.Size)
}

return nil
}
3 changes: 2 additions & 1 deletion pkg/api/handlers/compat/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)

query := struct {
All bool
Filters map[string][]string `schema:"filters"`
}{
// This is where you can override the golang default value for one of fields
Expand All @@ -80,7 +81,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
filters = append(filters, fmt.Sprintf("%s=%s", k, val))
}
}
pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), false, filters)
pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
if err != nil {
utils.InternalServerError(w, err)
return
Expand Down
7 changes: 4 additions & 3 deletions pkg/api/handlers/libpod/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ func GetImages(w http.ResponseWriter, r *http.Request) {

func PruneImages(w http.ResponseWriter, r *http.Request) {
var (
all bool
err error
)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
All bool `schema:"all"`
Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
Expand All @@ -140,7 +140,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
if _, found := r.URL.Query()["filters"]; found {
dangling := query.Filters["all"]
if len(dangling) > 0 {
all, err = strconv.ParseBool(query.Filters["all"][0])
query.All, err = strconv.ParseBool(query.Filters["all"][0])
if err != nil {
utils.InternalServerError(w, err)
return
Expand All @@ -152,7 +152,8 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
}
}
cids, err := runtime.ImageRuntime().PruneImages(r.Context(), all, libpodFilters)

cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
Expand Down
7 changes: 5 additions & 2 deletions pkg/bindings/images/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c

// 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, filters map[string][]string) ([]string, error) {
func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]string, error) {
var (
deleted []string
)
Expand All @@ -163,6 +163,9 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
return nil, err
}
params := url.Values{}
if all != nil {
params.Set("all", strconv.FormatBool(*all))
}
if filters != nil {
stringFilter, err := bindings.FiltersToString(filters)
if err != nil {
Expand All @@ -174,7 +177,7 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
if err != nil {
return deleted, err
}
return deleted, response.Process(nil)
return deleted, response.Process(&deleted)
}

// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
Expand Down
40 changes: 25 additions & 15 deletions pkg/bindings/test/images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ import (

var _ = Describe("Podman images", func() {
var (
//tempdir string
//err error
//podmanTest *PodmanTestIntegration
// tempdir string
// err error
// podmanTest *PodmanTestIntegration
bt *bindingTest
s *gexec.Session
err error
)

BeforeEach(func() {
//tempdir, err = CreateTempDirInTempDir()
//if err != nil {
// tempdir, err = CreateTempDirInTempDir()
// if err != nil {
// os.Exit(1)
//}
//podmanTest = PodmanTestCreate(tempdir)
//podmanTest.Setup()
//podmanTest.SeedImages()
// }
// podmanTest = PodmanTestCreate(tempdir)
// podmanTest.Setup()
// podmanTest.SeedImages()
bt = newBindingTest()
bt.RestoreImagesFromCache()
s = bt.startAPIService()
Expand All @@ -41,12 +41,13 @@ var _ = Describe("Podman images", func() {
})

AfterEach(func() {
//podmanTest.Cleanup()
//f := CurrentGinkgoTestDescription()
//processTestResult(f)
// podmanTest.Cleanup()
// f := CurrentGinkgoTestDescription()
// processTestResult(f)
s.Kill()
bt.cleanup()
})

It("inspect image", func() {
// Inspect invalid image be 404
_, err = images.GetImage(bt.conn, "foobar5000", nil)
Expand All @@ -71,7 +72,7 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil())
// TODO it looks like the images API alwaays returns size regardless
// of bool or not. What should we do ?
//Expect(data.Size).To(BeZero())
// Expect(data.Size).To(BeZero())

// Enabling the size parameter should result in size being populated
data, err = images.GetImage(bt.conn, alpine.name, &bindings.PTrue)
Expand Down Expand Up @@ -142,7 +143,7 @@ var _ = Describe("Podman images", func() {
err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName)
Expect(err).To(BeNil())

//Validates if name updates when the image is retagged.
// Validates if name updates when the image is retagged.
_, err := images.GetImage(bt.conn, "alpine:demo", nil)
Expect(err).To(BeNil())

Expand All @@ -165,7 +166,7 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil())
Expect(len(imageSummary)).To(Equal(3))

//Validate the image names.
// Validate the image names.
var names []string
for _, i := range imageSummary {
names = append(names, i.RepoTags...)
Expand Down Expand Up @@ -289,6 +290,7 @@ var _ = Describe("Podman images", func() {
Expect(data.Comment).To(Equal(testMessage))

})

It("History Image", func() {
// a bogus name should return a 404
_, err := images.History(bt.conn, "foobar")
Expand Down Expand Up @@ -343,4 +345,12 @@ var _ = Describe("Podman images", func() {
Expect(len(imgs)).To(BeNumerically(">=", 1))
})

It("Prune images", func() {
trueBoxed := true
results, err := images.Prune(bt.conn, &trueBoxed, nil)
Expect(err).NotTo(HaveOccurred())
Expect(len(results)).To(BeNumerically(">", 0))
Expect(results).To(ContainElement("docker.io/library/alpine:latest"))
})

})
7 changes: 4 additions & 3 deletions pkg/domain/entities/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ type ImageInspectOptions struct {

type ImageListOptions struct {
All bool `json:"all" schema:"all"`
Filter []string `json:",omitempty"`
Filter []string `json:"Filter,omitempty"`
Filters url.Values `json:"filters" schema:"filters"`
}

Expand All @@ -128,8 +128,9 @@ type ImageListOptions struct {
// }

type ImagePruneOptions struct {
All bool
Filter ImageFilter
All bool `json:"all" schema:"all"`
Filter []string `json:"filter" schema:"filter"`
Filters url.Values `json:"filters" schema:"filters"`
}

type ImagePruneReport struct {
Expand Down
11 changes: 8 additions & 3 deletions pkg/domain/infra/abi/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,18 @@ func (ir *ImageEngine) deleteImage(ctx context.Context, img *libpodImage.Image,
}

func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, []string{})
results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
if err != nil {
return nil, err
}

report := entities.ImagePruneReport{}
copy(report.Report.Id, results)
report := entities.ImagePruneReport{
Report: entities.Report{
Id: results,
Err: nil,
},
Size: 0,
}
return &report, nil
}

Expand Down
12 changes: 8 additions & 4 deletions pkg/domain/infra/tunnel/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package tunnel

import (
"context"
"net/url"

images "github.com/containers/libpod/pkg/bindings/images"
"github.com/containers/libpod/pkg/domain/entities"
Expand Down Expand Up @@ -72,12 +71,17 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entiti
}

func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
results, err := images.Prune(ir.ClientCxt, url.Values{})
results, err := images.Prune(ir.ClientCxt, &opts.All, opts.Filters)
if err != nil {
return nil, err
}

report := entities.ImagePruneReport{}
copy(report.Report.Id, results)
report := entities.ImagePruneReport{
Report: entities.Report{
Id: results,
Err: nil,
},
Size: 0,
}
return &report, nil
}

0 comments on commit 2c5c198

Please sign in to comment.