github.com/containers/podman/v4@v4.9.4/test/e2e/prune_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	. "github.com/containers/podman/v4/test/utils"
     9  	. "github.com/onsi/ginkgo/v2"
    10  	. "github.com/onsi/gomega"
    11  	. "github.com/onsi/gomega/gexec"
    12  )
    13  
    14  var pruneImage = fmt.Sprintf(`
    15  FROM  %s
    16  LABEL RUN podman --version
    17  RUN echo hello > /hello
    18  RUN echo hello2 > /hello2`, ALPINE)
    19  
    20  var emptyPruneImage = `
    21  FROM scratch
    22  ENV test1=test1
    23  ENV test2=test2`
    24  
    25  var _ = Describe("Podman prune", func() {
    26  
    27  	It("podman container prune containers", func() {
    28  		top := podmanTest.RunTopContainer("")
    29  		top.WaitWithDefaultTimeout()
    30  		Expect(top).Should(ExitCleanly())
    31  
    32  		top = podmanTest.RunTopContainer("")
    33  		top.WaitWithDefaultTimeout()
    34  		Expect(top).Should(ExitCleanly())
    35  		cid := top.OutputToString()
    36  
    37  		stop := podmanTest.Podman([]string{"stop", cid})
    38  		stop.WaitWithDefaultTimeout()
    39  		Expect(stop).Should(ExitCleanly())
    40  
    41  		prune := podmanTest.Podman([]string{"container", "prune", "-f"})
    42  		prune.WaitWithDefaultTimeout()
    43  		Expect(prune).Should(ExitCleanly())
    44  
    45  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
    46  	})
    47  
    48  	It("podman container prune after create containers", func() {
    49  		create := podmanTest.Podman([]string{"create", "--name", "test", BB})
    50  		create.WaitWithDefaultTimeout()
    51  		Expect(create).Should(ExitCleanly())
    52  
    53  		prune := podmanTest.Podman([]string{"container", "prune", "-f"})
    54  		prune.WaitWithDefaultTimeout()
    55  		Expect(prune).Should(ExitCleanly())
    56  
    57  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
    58  	})
    59  
    60  	It("podman container prune after create & init containers", func() {
    61  		create := podmanTest.Podman([]string{"create", "--name", "test", BB})
    62  		create.WaitWithDefaultTimeout()
    63  		Expect(create).Should(ExitCleanly())
    64  
    65  		init := podmanTest.Podman([]string{"init", "test"})
    66  		init.WaitWithDefaultTimeout()
    67  		Expect(init).Should(ExitCleanly())
    68  
    69  		prune := podmanTest.Podman([]string{"container", "prune", "-f"})
    70  		prune.WaitWithDefaultTimeout()
    71  		Expect(prune).Should(ExitCleanly())
    72  
    73  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
    74  	})
    75  
    76  	It("podman image prune - remove only dangling images", func() {
    77  		session := podmanTest.Podman([]string{"images", "-a"})
    78  		session.WaitWithDefaultTimeout()
    79  		Expect(session).Should(ExitCleanly())
    80  		Expect(session.OutputToString()).To(Not(ContainSubstring("<none>")))
    81  		numImages := len(session.OutputToStringArray())
    82  
    83  		// Since there's no dangling image, none should be removed.
    84  		session = podmanTest.Podman([]string{"image", "prune", "-f"})
    85  		session.WaitWithDefaultTimeout()
    86  		Expect(session).Should(ExitCleanly())
    87  		Expect(session.OutputToStringArray()).To(BeEmpty())
    88  
    89  		// Let's be extra sure that the same number of images is
    90  		// reported.
    91  		session = podmanTest.Podman([]string{"images", "-a"})
    92  		session.WaitWithDefaultTimeout()
    93  		Expect(session).Should(ExitCleanly())
    94  		Expect(session.OutputToStringArray()).To(HaveLen(numImages))
    95  
    96  		// Now build an image and untag it.  The (intermediate) images
    97  		// should be removed recursively during pruning.
    98  		podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
    99  		session = podmanTest.Podman([]string{"untag", "alpine_bash:latest"})
   100  		session.WaitWithDefaultTimeout()
   101  		Expect(session).Should(ExitCleanly())
   102  
   103  		session = podmanTest.Podman([]string{"images", "-a"})
   104  		session.WaitWithDefaultTimeout()
   105  		Expect(session).Should(ExitCleanly())
   106  		Expect(session.OutputToString()).To(ContainSubstring("<none>"))
   107  		numImages = len(session.OutputToStringArray())
   108  
   109  		// Since there's at least one dangling image, prune should
   110  		// remove them.
   111  		session = podmanTest.Podman([]string{"image", "prune", "-f"})
   112  		session.WaitWithDefaultTimeout()
   113  		Expect(session).Should(ExitCleanly())
   114  		numPrunedImages := len(session.OutputToStringArray())
   115  		Expect(numPrunedImages).To(BeNumerically(">=", 1), "numPrunedImages")
   116  
   117  		// Now make sure that exactly the number of pruned images has
   118  		// been removed.
   119  		session = podmanTest.Podman([]string{"images", "-a"})
   120  		session.WaitWithDefaultTimeout()
   121  		Expect(session).Should(ExitCleanly())
   122  		Expect(session.OutputToStringArray()).To(HaveLen(numImages - numPrunedImages))
   123  	})
   124  
   125  	It("podman image prune - handle empty images", func() {
   126  		// As shown in #10832, empty images were not treated correctly
   127  		// in Podman.
   128  		podmanTest.BuildImage(emptyPruneImage, "empty:scratch", "true")
   129  
   130  		session := podmanTest.Podman([]string{"images", "-a"})
   131  		session.WaitWithDefaultTimeout()
   132  		Expect(session).Should(ExitCleanly())
   133  		Expect(session.OutputToString()).To(ContainSubstring("<none>"))
   134  
   135  		// Nothing will be pruned.
   136  		session = podmanTest.Podman([]string{"image", "prune", "-f"})
   137  		session.WaitWithDefaultTimeout()
   138  		Expect(session).Should(ExitCleanly())
   139  		Expect(session.OutputToStringArray()).To(BeEmpty())
   140  
   141  		// Now the image will be untagged, and its parent images will
   142  		// be removed recursively.
   143  		session = podmanTest.Podman([]string{"untag", "empty:scratch"})
   144  		session.WaitWithDefaultTimeout()
   145  		Expect(session).Should(ExitCleanly())
   146  
   147  		session = podmanTest.Podman([]string{"image", "prune", "-f"})
   148  		session.WaitWithDefaultTimeout()
   149  		Expect(session).Should(ExitCleanly())
   150  		Expect(session.OutputToStringArray()).To(HaveLen(2))
   151  	})
   152  
   153  	It("podman image prune dangling images", func() {
   154  		podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
   155  		podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
   156  		none := podmanTest.Podman([]string{"images", "-a"})
   157  		none.WaitWithDefaultTimeout()
   158  		Expect(none).Should(ExitCleanly())
   159  		hasNone, result := none.GrepString("<none>")
   160  		Expect(result).To(HaveLen(2))
   161  		Expect(hasNone).To(BeTrue())
   162  
   163  		prune := podmanTest.Podman([]string{"image", "prune", "-f"})
   164  		prune.WaitWithDefaultTimeout()
   165  		Expect(prune).Should(ExitCleanly())
   166  
   167  		after := podmanTest.Podman([]string{"images", "-a"})
   168  		after.WaitWithDefaultTimeout()
   169  		Expect(after).Should(ExitCleanly())
   170  		hasNoneAfter, result := after.GrepString("<none>")
   171  		Expect(hasNoneAfter).To(BeTrue())
   172  		Expect(len(after.OutputToStringArray())).To(BeNumerically(">", 1))
   173  		Expect(result).ToNot(BeEmpty())
   174  	})
   175  
   176  	It("podman image prune unused images", func() {
   177  		podmanTest.AddImageToRWStore(ALPINE)
   178  		podmanTest.AddImageToRWStore(BB)
   179  
   180  		images := podmanTest.Podman([]string{"images", "-a"})
   181  		images.WaitWithDefaultTimeout()
   182  		Expect(images).Should(ExitCleanly())
   183  
   184  		prune := podmanTest.Podman([]string{"image", "prune", "-af"})
   185  		prune.WaitWithDefaultTimeout()
   186  		Expect(prune).Should(ExitCleanly())
   187  
   188  		images = podmanTest.Podman([]string{"images", "-aq"})
   189  		images.WaitWithDefaultTimeout()
   190  		Expect(images).Should(ExitCleanly())
   191  		// all images are unused, so they all should be deleted!
   192  		Expect(images.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES)))
   193  	})
   194  
   195  	It("podman system image prune unused images", func() {
   196  		useCustomNetworkDir(podmanTest, tempdir)
   197  		podmanTest.AddImageToRWStore(ALPINE)
   198  		podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
   199  		prune := podmanTest.Podman([]string{"system", "prune", "-a", "--force"})
   200  		prune.WaitWithDefaultTimeout()
   201  		Expect(prune).Should(ExitCleanly())
   202  
   203  		images := podmanTest.Podman([]string{"images", "-aq"})
   204  		images.WaitWithDefaultTimeout()
   205  		// all images are unused, so they all should be deleted!
   206  		Expect(images.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES)))
   207  	})
   208  
   209  	It("podman system prune pods", func() {
   210  		useCustomNetworkDir(podmanTest, tempdir)
   211  		session := podmanTest.Podman([]string{"pod", "create"})
   212  		session.WaitWithDefaultTimeout()
   213  		Expect(session).Should(ExitCleanly())
   214  
   215  		session = podmanTest.Podman([]string{"pod", "create"})
   216  		session.WaitWithDefaultTimeout()
   217  		Expect(session).Should(ExitCleanly())
   218  		podid1 := session.OutputToString()
   219  
   220  		session = podmanTest.Podman([]string{"pod", "start", podid1})
   221  		session.WaitWithDefaultTimeout()
   222  		Expect(session).Should(ExitCleanly())
   223  
   224  		session = podmanTest.Podman([]string{"pod", "stop", podid1})
   225  		session.WaitWithDefaultTimeout()
   226  		Expect(session).Should(ExitCleanly())
   227  
   228  		pods := podmanTest.Podman([]string{"pod", "ps"})
   229  		pods.WaitWithDefaultTimeout()
   230  		Expect(pods).Should(ExitCleanly())
   231  		Expect(pods.OutputToStringArray()).To(HaveLen(3))
   232  
   233  		prune := podmanTest.Podman([]string{"system", "prune", "-f"})
   234  		prune.WaitWithDefaultTimeout()
   235  		Expect(prune).Should(ExitCleanly())
   236  
   237  		pods = podmanTest.Podman([]string{"pod", "ps"})
   238  		pods.WaitWithDefaultTimeout()
   239  		Expect(pods).Should(ExitCleanly())
   240  		Expect(pods.OutputToStringArray()).To(HaveLen(2))
   241  	})
   242  
   243  	It("podman system prune networks", func() {
   244  		useCustomNetworkDir(podmanTest, tempdir)
   245  		// Create new network.
   246  		session := podmanTest.Podman([]string{"network", "create", "test"})
   247  		session.WaitWithDefaultTimeout()
   248  		Expect(session).Should(ExitCleanly())
   249  
   250  		// Remove all unused networks.
   251  		session = podmanTest.Podman([]string{"system", "prune", "-f"})
   252  		session.WaitWithDefaultTimeout()
   253  		Expect(session).Should(ExitCleanly())
   254  
   255  		// Default network should exists.
   256  		session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^podman$"})
   257  		session.WaitWithDefaultTimeout()
   258  		Expect(session).Should(ExitCleanly())
   259  		Expect(session.OutputToStringArray()).To(HaveLen(1))
   260  
   261  		// Unused networks removed.
   262  		session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^test$"})
   263  		session.WaitWithDefaultTimeout()
   264  		Expect(session).Should(ExitCleanly())
   265  		Expect(session.OutputToStringArray()).To(BeEmpty())
   266  
   267  		// Create new network.
   268  		session = podmanTest.Podman([]string{"network", "create", "test1", "--label", "foo"})
   269  		session.WaitWithDefaultTimeout()
   270  		Expect(session).Should(ExitCleanly())
   271  
   272  		// Remove all unused networks.
   273  		session = podmanTest.Podman([]string{"system", "prune", "-f", "--filter", "label!=foo"})
   274  		session.WaitWithDefaultTimeout()
   275  		Expect(session).Should(ExitCleanly())
   276  		Expect(session.OutputToString()).Should(Equal("Total reclaimed space: 0B"))
   277  
   278  		// Unused networks removed.
   279  		session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^test1$"})
   280  		session.WaitWithDefaultTimeout()
   281  		Expect(session).Should(ExitCleanly())
   282  		// label should make sure we do not remove this network
   283  		Expect(session.OutputToStringArray()).To(HaveLen(1))
   284  	})
   285  
   286  	It("podman system prune - pod,container stopped", func() {
   287  		useCustomNetworkDir(podmanTest, tempdir)
   288  		session := podmanTest.Podman([]string{"pod", "create"})
   289  		session.WaitWithDefaultTimeout()
   290  		Expect(session).Should(ExitCleanly())
   291  		podid1 := session.OutputToString()
   292  
   293  		// Start and stop a pod to get it in exited state.
   294  		session = podmanTest.Podman([]string{"pod", "start", podid1})
   295  		session.WaitWithDefaultTimeout()
   296  		Expect(session).Should(ExitCleanly())
   297  
   298  		session = podmanTest.Podman([]string{"pod", "stop", podid1})
   299  		session.WaitWithDefaultTimeout()
   300  		Expect(session).Should(ExitCleanly())
   301  
   302  		// Create a container. This container should be pruned.
   303  		create := podmanTest.Podman([]string{"create", "--name", "test", BB})
   304  		create.WaitWithDefaultTimeout()
   305  		Expect(create).Should(ExitCleanly())
   306  
   307  		prune := podmanTest.Podman([]string{"system", "prune", "-f"})
   308  		prune.WaitWithDefaultTimeout()
   309  		Expect(prune).Should(ExitCleanly())
   310  
   311  		pods := podmanTest.Podman([]string{"pod", "ps"})
   312  		pods.WaitWithDefaultTimeout()
   313  		Expect(pods).Should(ExitCleanly())
   314  		Expect(podmanTest.NumberOfPods()).To(Equal(0))
   315  
   316  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   317  	})
   318  
   319  	It("podman system prune with running, exited pod and volume prune set true", func() {
   320  		useCustomNetworkDir(podmanTest, tempdir)
   321  		// Start and stop a pod to get it in exited state.
   322  		session := podmanTest.Podman([]string{"pod", "create"})
   323  		session.WaitWithDefaultTimeout()
   324  		Expect(session).Should(ExitCleanly())
   325  		podid1 := session.OutputToString()
   326  
   327  		session = podmanTest.Podman([]string{"pod", "start", podid1})
   328  		session.WaitWithDefaultTimeout()
   329  		Expect(session).Should(ExitCleanly())
   330  
   331  		session = podmanTest.Podman([]string{"pod", "stop", podid1})
   332  		session.WaitWithDefaultTimeout()
   333  		Expect(session).Should(ExitCleanly())
   334  
   335  		// Start a pod and leave it running
   336  		session = podmanTest.Podman([]string{"pod", "create"})
   337  		session.WaitWithDefaultTimeout()
   338  		Expect(session).Should(ExitCleanly())
   339  		podid2 := session.OutputToString()
   340  
   341  		session = podmanTest.Podman([]string{"pod", "start", podid2})
   342  		session.WaitWithDefaultTimeout()
   343  		Expect(session).Should(ExitCleanly())
   344  
   345  		// Number of pod should be 2. One exited one running.
   346  		Expect(podmanTest.NumberOfPods()).To(Equal(2))
   347  
   348  		// Create a container. This container should be pruned.
   349  		_, ec, _ := podmanTest.RunLsContainer("test1")
   350  		Expect(ec).To(Equal(0))
   351  
   352  		// Number of containers should be three now.
   353  		// Two as pods infra container and one newly created.
   354  		Expect(podmanTest.NumberOfContainers()).To(Equal(3))
   355  
   356  		// image list current count should not be pruned if all flag isn't enabled
   357  		session = podmanTest.Podman([]string{"images"})
   358  		session.WaitWithDefaultTimeout()
   359  		numberOfImages := len(session.OutputToStringArray())
   360  
   361  		// Adding unused volume should be pruned
   362  		session = podmanTest.Podman([]string{"volume", "create"})
   363  		session.WaitWithDefaultTimeout()
   364  		Expect(session).Should(ExitCleanly())
   365  
   366  		session = podmanTest.Podman([]string{"create", "-v", "myvol:/myvol", ALPINE, "ls"})
   367  		session.WaitWithDefaultTimeout()
   368  		Expect(session).Should(ExitCleanly())
   369  
   370  		session = podmanTest.Podman([]string{"volume", "ls"})
   371  		session.WaitWithDefaultTimeout()
   372  		Expect(session).Should(ExitCleanly())
   373  		Expect(session.OutputToStringArray()).To(HaveLen(3))
   374  
   375  		session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes"})
   376  		session.WaitWithDefaultTimeout()
   377  		Expect(session).Should(ExitCleanly())
   378  
   379  		// Volumes should be pruned.
   380  		session = podmanTest.Podman([]string{"volume", "ls"})
   381  		session.WaitWithDefaultTimeout()
   382  		Expect(session).Should(ExitCleanly())
   383  		Expect(session.OutputToStringArray()).To(BeEmpty())
   384  
   385  		// One Pod should not be pruned as it was running
   386  		Expect(podmanTest.NumberOfPods()).To(Equal(1))
   387  
   388  		// Running pods infra container should not be pruned.
   389  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   390  
   391  		// Image should not be pruned and number should be same.
   392  		images := podmanTest.Podman([]string{"images"})
   393  		images.WaitWithDefaultTimeout()
   394  		Expect(images.OutputToStringArray()).To(HaveLen(numberOfImages))
   395  	})
   396  
   397  	It("podman system prune - with dangling images true", func() {
   398  		useCustomNetworkDir(podmanTest, tempdir)
   399  		session := podmanTest.Podman([]string{"pod", "create"})
   400  		session.WaitWithDefaultTimeout()
   401  		Expect(session).Should(ExitCleanly())
   402  		podid1 := session.OutputToString()
   403  
   404  		// Start and stop a pod to get it in exited state.
   405  		session = podmanTest.Podman([]string{"pod", "start", podid1})
   406  		session.WaitWithDefaultTimeout()
   407  		Expect(session).Should(ExitCleanly())
   408  
   409  		session = podmanTest.Podman([]string{"pod", "stop", podid1})
   410  		session.WaitWithDefaultTimeout()
   411  		Expect(session).Should(ExitCleanly())
   412  
   413  		// Create a container. This container should be pruned.
   414  		create := podmanTest.Podman([]string{"create", "--name", "test", BB})
   415  		create.WaitWithDefaultTimeout()
   416  		Expect(create).Should(ExitCleanly())
   417  
   418  		// Adding unused volume should not be pruned as volumes not set
   419  		session = podmanTest.Podman([]string{"volume", "create"})
   420  		session.WaitWithDefaultTimeout()
   421  		Expect(session).Should(ExitCleanly())
   422  
   423  		prune := podmanTest.Podman([]string{"system", "prune", "-f", "-a"})
   424  		prune.WaitWithDefaultTimeout()
   425  		Expect(prune).Should(ExitCleanly())
   426  
   427  		pods := podmanTest.Podman([]string{"pod", "ps"})
   428  		pods.WaitWithDefaultTimeout()
   429  		Expect(pods).Should(ExitCleanly())
   430  		Expect(podmanTest.NumberOfPods()).To(Equal(0))
   431  
   432  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   433  
   434  		// Volumes should not be pruned
   435  		session = podmanTest.Podman([]string{"volume", "ls"})
   436  		session.WaitWithDefaultTimeout()
   437  		Expect(session).Should(ExitCleanly())
   438  		Expect(session.OutputToStringArray()).To(HaveLen(2))
   439  
   440  		images := podmanTest.Podman([]string{"images", "-aq"})
   441  		images.WaitWithDefaultTimeout()
   442  		// all images are unused, so they all should be deleted!
   443  		Expect(images.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES)))
   444  	})
   445  
   446  	It("podman system prune --volumes --filter", func() {
   447  		useCustomNetworkDir(podmanTest, tempdir)
   448  		session := podmanTest.Podman([]string{"volume", "create", "--label", "label1=value1", "myvol1"})
   449  		session.WaitWithDefaultTimeout()
   450  		Expect(session).Should(ExitCleanly())
   451  
   452  		session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv1", "myvol2"})
   453  		session.WaitWithDefaultTimeout()
   454  		Expect(session).Should(ExitCleanly())
   455  
   456  		session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv2", "myvol3"})
   457  		session.WaitWithDefaultTimeout()
   458  		Expect(session).Should(ExitCleanly())
   459  
   460  		session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1", "myvol4"})
   461  		session.WaitWithDefaultTimeout()
   462  		Expect(session).Should(ExitCleanly())
   463  
   464  		session = podmanTest.Podman([]string{"create", "-v", "myvol5:/myvol5", ALPINE, "ls"})
   465  		session.WaitWithDefaultTimeout()
   466  		Expect(session).Should(ExitCleanly())
   467  
   468  		session = podmanTest.Podman([]string{"create", "-v", "myvol6:/myvol6", ALPINE, "ls"})
   469  		session.WaitWithDefaultTimeout()
   470  		Expect(session).Should(ExitCleanly())
   471  
   472  		session = podmanTest.Podman([]string{"volume", "ls"})
   473  		session.WaitWithDefaultTimeout()
   474  		Expect(session).Should(ExitCleanly())
   475  		Expect(session.OutputToStringArray()).To(HaveLen(7))
   476  
   477  		session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=label1=value1"})
   478  		session.WaitWithDefaultTimeout()
   479  		Expect(session).Should(ExitCleanly())
   480  
   481  		session = podmanTest.Podman([]string{"volume", "ls"})
   482  		session.WaitWithDefaultTimeout()
   483  		Expect(session).Should(ExitCleanly())
   484  		Expect(session.OutputToStringArray()).To(HaveLen(6))
   485  
   486  		session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=sharedlabel1=slv1"})
   487  		session.WaitWithDefaultTimeout()
   488  		Expect(session).Should(ExitCleanly())
   489  
   490  		session = podmanTest.Podman([]string{"volume", "ls"})
   491  		session.WaitWithDefaultTimeout()
   492  		Expect(session).Should(ExitCleanly())
   493  		Expect(session.OutputToStringArray()).To(HaveLen(5))
   494  
   495  		session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=sharedlabel1"})
   496  		session.WaitWithDefaultTimeout()
   497  		Expect(session).Should(ExitCleanly())
   498  
   499  		session = podmanTest.Podman([]string{"volume", "ls"})
   500  		session.WaitWithDefaultTimeout()
   501  		Expect(session).Should(ExitCleanly())
   502  		Expect(session.OutputToStringArray()).To(HaveLen(3))
   503  	})
   504  
   505  	It("podman system prune --all --external fails", func() {
   506  		prune := podmanTest.Podman([]string{"system", "prune", "--all", "--external"})
   507  		prune.WaitWithDefaultTimeout()
   508  		Expect(prune).Should(Exit(125))
   509  		Expect(prune.ErrorToString()).To(ContainSubstring("--external cannot be combined with other options"))
   510  	})
   511  
   512  	It("podman system prune --external leaves referenced containers", func() {
   513  		useCustomNetworkDir(podmanTest, tempdir)
   514  		containerStorageDir := filepath.Join(podmanTest.Root, podmanTest.ImageCacheFS+"-containers")
   515  
   516  		create := podmanTest.Podman([]string{"create", "--name", "test", BB})
   517  		create.WaitWithDefaultTimeout()
   518  		Expect(create).Should(ExitCleanly())
   519  
   520  		// Container should exist
   521  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   522  
   523  		// have: containers.json, containers.lock and container dir
   524  		dirents, err := os.ReadDir(containerStorageDir)
   525  		Expect(err).ToNot(HaveOccurred())
   526  		Expect(dirents).To(HaveLen(3))
   527  
   528  		prune := podmanTest.Podman([]string{"system", "prune", "--external", "-f"})
   529  		prune.WaitWithDefaultTimeout()
   530  		Expect(prune).Should(ExitCleanly())
   531  
   532  		// Container should still exist
   533  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   534  
   535  		// still have: containers.json, containers.lock and container dir
   536  		dirents, err = os.ReadDir(containerStorageDir)
   537  		Expect(err).ToNot(HaveOccurred())
   538  		Expect(dirents).To(HaveLen(3))
   539  
   540  	})
   541  
   542  	It("podman system prune --external removes unreferenced containers", func() {
   543  		SkipIfRemote("Can't drop database while daemon running")
   544  		useCustomNetworkDir(podmanTest, tempdir)
   545  
   546  		containerStorageDir := filepath.Join(podmanTest.Root, podmanTest.ImageCacheFS+"-containers")
   547  
   548  		// Create container 1
   549  		create := podmanTest.Podman([]string{"create", "--name", "test", BB})
   550  		create.WaitWithDefaultTimeout()
   551  		Expect(create).Should(ExitCleanly())
   552  
   553  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   554  
   555  		// containers.json, containers.lock and container 1 dir
   556  		dirents, err := os.ReadDir(containerStorageDir)
   557  		Expect(err).ToNot(HaveOccurred())
   558  		Expect(dirents).To(HaveLen(3))
   559  
   560  		// Drop podman database and storage, losing track of container 1 (but directory remains)
   561  		err = os.Remove(filepath.Join(containerStorageDir, "containers.json"))
   562  		Expect(err).ToNot(HaveOccurred())
   563  
   564  		if podmanTest.DatabaseBackend == "sqlite" {
   565  			err = os.Remove(filepath.Join(podmanTest.Root, "db.sql"))
   566  			Expect(err).ToNot(HaveOccurred())
   567  		} else {
   568  			dbDir := filepath.Join(podmanTest.Root, "libpod")
   569  			err = os.RemoveAll(dbDir)
   570  			Expect(err).ToNot(HaveOccurred())
   571  		}
   572  
   573  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   574  
   575  		// Create container 2
   576  		create = podmanTest.Podman([]string{"create", "--name", "test", BB})
   577  		create.WaitWithDefaultTimeout()
   578  		Expect(create).Should(ExitCleanly())
   579  
   580  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   581  
   582  		// containers.json, containers.lock and container 1&2 dir
   583  		dirents, err = os.ReadDir(containerStorageDir)
   584  		Expect(err).ToNot(HaveOccurred())
   585  		Expect(dirents).To(HaveLen(4))
   586  
   587  		prune := podmanTest.Podman([]string{"system", "prune", "--external", "-f"})
   588  		prune.WaitWithDefaultTimeout()
   589  		Expect(prune).Should(ExitCleanly())
   590  
   591  		// container 1 dir should be gone now
   592  		dirents, err = os.ReadDir(containerStorageDir)
   593  		Expect(err).ToNot(HaveOccurred())
   594  		Expect(dirents).To(HaveLen(3))
   595  	})
   596  })