From 356668389682ea765d2717760d6f5329ff99aff6 Mon Sep 17 00:00:00 2001 From: Aditya R Date: Mon, 2 Jan 2023 12:42:55 +0530 Subject: [PATCH] buildah: add prune command and expose CleanCacheMount API * Just like buildkit buildah must allow cleaning the buildcache and cache generated on host by `--mount=type=cache` just like buildkit's `prune` command. * Also expose `CleanCacheMount` API so other tools like `podman` can use it. See: https://github.com/moby/buildkit#cache Closes: https://github.com/containers/buildah/issues/4486 Signed-off-by: Aditya R --- cmd/buildah/prune.go | 95 +++++++++++++++++++++++++++++++++++++++++ docs/buildah-prune.1.md | 33 ++++++++++++++ docs/buildah.1.md | 1 + internal/parse/parse.go | 6 +++ tests/bud.bats | 15 +++++++ 5 files changed, 150 insertions(+) create mode 100644 cmd/buildah/prune.go create mode 100644 docs/buildah-prune.1.md diff --git a/cmd/buildah/prune.go b/cmd/buildah/prune.go new file mode 100644 index 000000000..d97a06db6 --- /dev/null +++ b/cmd/buildah/prune.go @@ -0,0 +1,95 @@ +package main + +import ( + "context" + "fmt" + + internalParse "github.com/containers/buildah/internal/parse" + buildahcli "github.com/containers/buildah/pkg/cli" + "github.com/containers/buildah/pkg/parse" + "github.com/containers/common/libimage" + "github.com/hashicorp/go-multierror" + "github.com/spf13/cobra" +) + +type pruneOptions struct { + force bool + all bool +} + +func init() { + var ( + pruneDescription = ` +Cleanup intermediate images as well as build and mount cache.` + opts pruneOptions + ) + pruneCommand := &cobra.Command{ + Use: "prune", + Short: "Cleanup intermediate images as well as build and mount cache", + Long: pruneDescription, + RunE: func(cmd *cobra.Command, args []string) error { + return pruneCmd(cmd, args, opts) + }, + Example: `buildah prune + buildah prune`, + } + pruneCommand.SetUsageTemplate(UsageTemplate()) + + flags := pruneCommand.Flags() + flags.SetInterspersed(false) + + flags.BoolVarP(&opts.all, "all", "a", false, "remove all unused images") + flags.BoolVarP(&opts.force, "force", "f", false, "force removal of the image and any containers using the image") + + rootCmd.AddCommand(pruneCommand) +} + +func pruneCmd(c *cobra.Command, args []string, iopts pruneOptions) error { + if err := buildahcli.VerifyFlagsArgsOrder(args); err != nil { + return err + } + + store, err := getStore(c) + if err != nil { + return err + } + + systemContext, err := parse.SystemContextFromOptions(c) + if err != nil { + return err + } + runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext}) + if err != nil { + return err + } + + err = internalParse.CleanCacheMount() + if err != nil { + return err + } + + options := &libimage.RemoveImagesOptions{ + Filters: []string{"readonly=false"}, + } + if !iopts.all { + options.Filters = append(options.Filters, "dangling=true") + options.Filters = append(options.Filters, "intermediate=true") + } + options.Force = iopts.force + + rmiReports, rmiErrors := runtime.RemoveImages(context.Background(), args, options) + for _, r := range rmiReports { + for _, u := range r.Untagged { + fmt.Printf("untagged: %s\n", u) + } + } + for _, r := range rmiReports { + if r.Removed { + fmt.Printf("%s\n", r.ID) + } + } + + var multiE *multierror.Error + multiE = multierror.Append(multiE, rmiErrors...) + return multiE.ErrorOrNil() +} diff --git a/docs/buildah-prune.1.md b/docs/buildah-prune.1.md new file mode 100644 index 000000000..5c5cfb325 --- /dev/null +++ b/docs/buildah-prune.1.md @@ -0,0 +1,33 @@ +# buildah-rmi "1" "Jan 2023" "buildah" + +## NAME + +buildah\-prune - Cleanup intermediate images as well as build and mount cache. + +## SYNOPSIS + +**buildah prune** + +## DESCRIPTION + +Cleanup intermediate images as well as build and mount cache. + +## OPTIONS + +**--all**, **-a** + +All local images will be removed from the system that do not have containers using the image as a reference image. + +**--force**, **-f** + +This option will cause Buildah to remove all containers that are using the image before removing the image from the system. + +## EXAMPLE + +buildah prune + +buildah prune --force + +## SEE ALSO + +buildah(1), containers-registries.conf(5), containers-storage.conf(5) diff --git a/docs/buildah.1.md b/docs/buildah.1.md index 7dbc9f15d..156b5f56e 100644 --- a/docs/buildah.1.md +++ b/docs/buildah.1.md @@ -159,6 +159,7 @@ Buildah can set up environment variables from the env entry in the [engine] tabl | logout | [buildah-logout(1)](buildah-logout.1.md) | Logout of a container registry | | manifest | [buildah-manifest(1)](buildah-manifest.1.md) | Create and manipulate manifest lists and image indexes. | | mount | [buildah-mount(1)](buildah-mount.1.md) | Mount the working container's root filesystem. | +| prune | [buildah-prune(1)](buildah-prune.1.md) | Cleanup intermediate images as well as build and mount cache. | | pull | [buildah-pull(1)](buildah-pull.1.md) | Pull an image from the specified location. | | push | [buildah-push(1)](buildah-push.1.md) | Push an image from local storage to elsewhere. | | rename | [buildah-rename(1)](buildah-rename.1.md) | Rename a local container. | diff --git a/internal/parse/parse.go b/internal/parse/parse.go index 156ef8253..5050be38b 100644 --- a/internal/parse/parse.go +++ b/internal/parse/parse.go @@ -191,6 +191,12 @@ func GetBindMount(ctx *types.SystemContext, args []string, contextDir string, st return newMount, fromImage, nil } +// CleanCacheMount gets the cache parent created by `--mount=type=cache` and removes it. +func CleanCacheMount() error { + cacheParent := filepath.Join(internalUtil.GetTempDir(), BuildahCacheDir+"-"+strconv.Itoa(unshare.GetRootlessUID())) + return os.RemoveAll(cacheParent) +} + // GetCacheMount parses a single cache mount entry from the --mount flag. // // If this function succeeds and returns a non-nil *lockfile.LockFile, the caller must unlock it (when??). diff --git a/tests/bud.bats b/tests/bud.bats index c3a877fe2..3814308af 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -5549,6 +5549,21 @@ _EOF run_buildah rmi -f testbud2 } +@test "bud-with-mount-cache-like-buildkit with buildah prune should clear the cache" { + skip_if_no_runtime + skip_if_in_container + local contextdir=${TEST_SCRATCH_DIR}/buildkit-mount + cp -R $BUDFILES/buildkit-mount $contextdir + # try writing something to persistent cache + run_buildah build -t testbud $WITH_POLICY_JSON -f $contextdir/Dockerfilecachewrite + # prune the mount cache + run_buildah prune + # try reading something from persistent cache in a different build + run_buildah 1 build -t testbud2 $WITH_POLICY_JSON -f $contextdir/Dockerfilecacheread + expect_output --substring "No such file or directory" + run_buildah rmi -f testbud +} + @test "bud-with-mount-cache-like-buildkit-verify-default-selinux-option" { skip_if_no_runtime skip_if_in_container