mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Merge pull request #23846 from flouthoc/prune-cleancachemount
prune: add `--build-cache` to support clearing build cache using `CleanCacheMount`
This commit is contained in:
@ -46,6 +46,7 @@ func init() {
|
|||||||
|
|
||||||
flags := pruneCmd.Flags()
|
flags := pruneCmd.Flags()
|
||||||
flags.BoolVarP(&pruneOpts.All, "all", "a", false, "Remove all images not in use by containers, not just dangling ones")
|
flags.BoolVarP(&pruneOpts.All, "all", "a", false, "Remove all images not in use by containers, not just dangling ones")
|
||||||
|
flags.BoolVarP(&pruneOpts.BuildCache, "build-cache", "", false, "Remove persistent build cache created by --mount=type=cache")
|
||||||
flags.BoolVarP(&pruneOpts.External, "external", "", false, "Remove images even when they are used by external containers (e.g., by build containers)")
|
flags.BoolVarP(&pruneOpts.External, "external", "", false, "Remove images even when they are used by external containers (e.g., by build containers)")
|
||||||
flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation")
|
flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation")
|
||||||
|
|
||||||
|
@ -17,6 +17,10 @@ The image prune command does not prune cache images that only use layers that ar
|
|||||||
|
|
||||||
Remove dangling images and images that have no associated containers.
|
Remove dangling images and images that have no associated containers.
|
||||||
|
|
||||||
|
#### **--build-cache**
|
||||||
|
|
||||||
|
Remove persistent build cache create for `--mount=type=cache`.
|
||||||
|
|
||||||
#### **--external**
|
#### **--external**
|
||||||
|
|
||||||
Remove images even when they are used by external containers (e.g., build containers).
|
Remove images even when they are used by external containers (e.g., build containers).
|
||||||
|
@ -118,8 +118,9 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
|
|||||||
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
External bool `schema:"external"`
|
External bool `schema:"external"`
|
||||||
|
BuildCache bool `schema:"buildcache"`
|
||||||
}{
|
}{
|
||||||
// override any golang type defaults
|
// override any golang type defaults
|
||||||
}
|
}
|
||||||
@ -157,9 +158,10 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
|
|||||||
imageEngine := abi.ImageEngine{Libpod: runtime}
|
imageEngine := abi.ImageEngine{Libpod: runtime}
|
||||||
|
|
||||||
pruneOptions := entities.ImagePruneOptions{
|
pruneOptions := entities.ImagePruneOptions{
|
||||||
All: query.All,
|
All: query.All,
|
||||||
External: query.External,
|
External: query.External,
|
||||||
Filter: libpodFilters,
|
Filter: libpodFilters,
|
||||||
|
BuildCache: query.BuildCache,
|
||||||
}
|
}
|
||||||
imagePruneReports, err := imageEngine.Prune(r.Context(), pruneOptions)
|
imagePruneReports, err := imageEngine.Prune(r.Context(), pruneOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1129,6 +1129,12 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
|
|||||||
// description: |
|
// description: |
|
||||||
// Remove images even when they are used by external containers (e.g, by build containers)
|
// Remove images even when they are used by external containers (e.g, by build containers)
|
||||||
// - in: query
|
// - in: query
|
||||||
|
// name: buildcache
|
||||||
|
// default: false
|
||||||
|
// type: boolean
|
||||||
|
// description: |
|
||||||
|
// Remove persistent build cache created by build instructions such as `--mount=type=cache`.
|
||||||
|
// - in: query
|
||||||
// name: filters
|
// name: filters
|
||||||
// type: string
|
// type: string
|
||||||
// description: |
|
// description: |
|
||||||
|
@ -93,6 +93,8 @@ type PruneOptions struct {
|
|||||||
All *bool
|
All *bool
|
||||||
// Prune images even when they're used by external containers
|
// Prune images even when they're used by external containers
|
||||||
External *bool
|
External *bool
|
||||||
|
// Prune persistent build cache
|
||||||
|
BuildCache *bool
|
||||||
// Filters to apply when pruning images
|
// Filters to apply when pruning images
|
||||||
Filters map[string][]string
|
Filters map[string][]string
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,21 @@ func (o *PruneOptions) GetExternal() bool {
|
|||||||
return *o.External
|
return *o.External
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithBuildCache set field BuildCache to given value
|
||||||
|
func (o *PruneOptions) WithBuildCache(value bool) *PruneOptions {
|
||||||
|
o.BuildCache = &value
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBuildCache returns value of field BuildCache
|
||||||
|
func (o *PruneOptions) GetBuildCache() bool {
|
||||||
|
if o.BuildCache == nil {
|
||||||
|
var z bool
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return *o.BuildCache
|
||||||
|
}
|
||||||
|
|
||||||
// WithFilters set field Filters to given value
|
// WithFilters set field Filters to given value
|
||||||
func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
|
func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
|
||||||
o.Filters = value
|
o.Filters = value
|
||||||
|
@ -249,9 +249,10 @@ type ImageListOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ImagePruneOptions struct {
|
type ImagePruneOptions struct {
|
||||||
All bool `json:"all" schema:"all"`
|
All bool `json:"all" schema:"all"`
|
||||||
External bool `json:"external" schema:"external"`
|
External bool `json:"external" schema:"external"`
|
||||||
Filter []string `json:"filter" schema:"filter"`
|
BuildCache bool `json:"buildcache" schema:"buildcache"`
|
||||||
|
Filter []string `json:"filter" schema:"filter"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageTagOptions struct{}
|
type ImageTagOptions struct{}
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
bdefine "github.com/containers/buildah/define"
|
bdefine "github.com/containers/buildah/define"
|
||||||
|
"github.com/containers/buildah/pkg/volumes"
|
||||||
"github.com/containers/common/libimage"
|
"github.com/containers/common/libimage"
|
||||||
"github.com/containers/common/libimage/filter"
|
"github.com/containers/common/libimage/filter"
|
||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
@ -107,6 +108,13 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
|
|||||||
numPreviouslyRemovedImages = numRemovedImages
|
numPreviouslyRemovedImages = numRemovedImages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.BuildCache || opts.All {
|
||||||
|
// Clean build cache if any
|
||||||
|
if err := volumes.CleanCacheMount(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return pruneReports, nil
|
return pruneReports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
|
|||||||
f := strings.Split(filter, "=")
|
f := strings.Split(filter, "=")
|
||||||
filters[f[0]] = f[1:]
|
filters[f[0]] = f[1:]
|
||||||
}
|
}
|
||||||
options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters).WithExternal(opts.External)
|
options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters).WithExternal(opts.External).WithBuildCache(opts.BuildCache)
|
||||||
reports, err := images.Prune(ir.ClientCtx, options)
|
reports, err := images.Prune(ir.ClientCtx, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
4
test/e2e/build/buildkit-mount/Containerfilecacheread
Normal file
4
test/e2e/build/buildkit-mount/Containerfilecacheread
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
FROM alpine
|
||||||
|
RUN mkdir /test
|
||||||
|
# use option z if selinux is enabled
|
||||||
|
RUN --mount=type=cache,target=/test,z cat /test/world
|
4
test/e2e/build/buildkit-mount/Containerfilecachewrite
Normal file
4
test/e2e/build/buildkit-mount/Containerfilecachewrite
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
FROM alpine
|
||||||
|
RUN mkdir /test
|
||||||
|
# use option z if selinux is enabled
|
||||||
|
RUN --mount=type=cache,target=/test,z echo hello > /test/world
|
@ -41,6 +41,37 @@ var _ = Describe("Podman build", func() {
|
|||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman image prune should clean build cache", Serial, func() {
|
||||||
|
// try writing something to persistent cache
|
||||||
|
session := podmanTest.Podman([]string{"build", "-f", "build/buildkit-mount/Containerfilecachewrite"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(ExitCleanly())
|
||||||
|
|
||||||
|
// try reading something from persistent cache
|
||||||
|
session = podmanTest.Podman([]string{"build", "-f", "build/buildkit-mount/Containerfilecacheread"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(ExitCleanly())
|
||||||
|
Expect(session.OutputToString()).To(ContainSubstring("hello"))
|
||||||
|
|
||||||
|
// Prune build cache
|
||||||
|
session = podmanTest.Podman([]string{"image", "prune", "-f", "--build-cache"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(ExitCleanly())
|
||||||
|
|
||||||
|
expectedErr := "open '/test/world': No such file or directory"
|
||||||
|
// try reading something from persistent cache should fail
|
||||||
|
session = podmanTest.Podman([]string{"build", "-f", "build/buildkit-mount/Containerfilecacheread"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
if IsRemote() {
|
||||||
|
// In the case of podman remote the error from build is not being propogated to `stderr` instead it appears
|
||||||
|
// on the `stdout` this could be a potential bug in `remote build` which needs to be fixed and visited.
|
||||||
|
Expect(session.OutputToString()).To(ContainSubstring(expectedErr))
|
||||||
|
Expect(session).Should(ExitWithError(1, "exit status 1"))
|
||||||
|
} else {
|
||||||
|
Expect(session).Should(ExitWithError(1, expectedErr))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
It("podman build and remove basic alpine with TMPDIR as relative", func() {
|
It("podman build and remove basic alpine with TMPDIR as relative", func() {
|
||||||
// preserve TMPDIR if it was originally set
|
// preserve TMPDIR if it was originally set
|
||||||
if cacheDir, found := os.LookupEnv("TMPDIR"); found {
|
if cacheDir, found := os.LookupEnv("TMPDIR"); found {
|
||||||
|
Reference in New Issue
Block a user