Merge pull request #23846 from flouthoc/prune-cleancachemount

prune: add `--build-cache` to support clearing build cache using `CleanCacheMount`
This commit is contained in:
openshift-merge-bot[bot]
2024-09-05 18:47:56 +00:00
committed by GitHub
12 changed files with 87 additions and 9 deletions

View File

@ -46,6 +46,7 @@ func init() {
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.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(&force, "force", "f", false, "Do not prompt for confirmation")

View File

@ -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.
#### **--build-cache**
Remove persistent build cache create for `--mount=type=cache`.
#### **--external**
Remove images even when they are used by external containers (e.g., build containers).

View File

@ -120,6 +120,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
query := struct {
All bool `schema:"all"`
External bool `schema:"external"`
BuildCache bool `schema:"buildcache"`
}{
// override any golang type defaults
}
@ -160,6 +161,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
All: query.All,
External: query.External,
Filter: libpodFilters,
BuildCache: query.BuildCache,
}
imagePruneReports, err := imageEngine.Prune(r.Context(), pruneOptions)
if err != nil {

View File

@ -1129,6 +1129,12 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: |
// Remove images even when they are used by external containers (e.g, by build containers)
// - 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
// type: string
// description: |

View File

@ -93,6 +93,8 @@ type PruneOptions struct {
All *bool
// Prune images even when they're used by external containers
External *bool
// Prune persistent build cache
BuildCache *bool
// Filters to apply when pruning images
Filters map[string][]string
}

View File

@ -47,6 +47,21 @@ func (o *PruneOptions) GetExternal() bool {
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
func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
o.Filters = value

View File

@ -251,6 +251,7 @@ type ImageListOptions struct {
type ImagePruneOptions struct {
All bool `json:"all" schema:"all"`
External bool `json:"external" schema:"external"`
BuildCache bool `json:"buildcache" schema:"buildcache"`
Filter []string `json:"filter" schema:"filter"`
}

View File

@ -19,6 +19,7 @@ import (
"time"
bdefine "github.com/containers/buildah/define"
"github.com/containers/buildah/pkg/volumes"
"github.com/containers/common/libimage"
"github.com/containers/common/libimage/filter"
"github.com/containers/common/pkg/config"
@ -107,6 +108,13 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
numPreviouslyRemovedImages = numRemovedImages
}
if opts.BuildCache || opts.All {
// Clean build cache if any
if err := volumes.CleanCacheMount(); err != nil {
return nil, err
}
}
return pruneReports, nil
}

View File

@ -102,7 +102,7 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
f := strings.Split(filter, "=")
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)
if err != nil {
return nil, err

View 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

View 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

View File

@ -41,6 +41,37 @@ var _ = Describe("Podman build", func() {
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() {
// preserve TMPDIR if it was originally set
if cacheDir, found := os.LookupEnv("TMPDIR"); found {