github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/rmi_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	. "github.com/containers/podman/v5/test/utils"
     8  	. "github.com/onsi/ginkgo/v2"
     9  	. "github.com/onsi/gomega"
    10  )
    11  
    12  var _ = Describe("Podman rmi", func() {
    13  
    14  	It("podman rmi bogus image", func() {
    15  		session := podmanTest.Podman([]string{"rmi", "debian:6.0.10"})
    16  		session.WaitWithDefaultTimeout()
    17  		Expect(session).Should(ExitWithError(1, "debian:6.0.10: image not known"))
    18  
    19  	})
    20  
    21  	It("podman rmi with fq name", func() {
    22  		podmanTest.AddImageToRWStore(ALPINE)
    23  		session := podmanTest.Podman([]string{"rmi", ALPINE})
    24  		session.WaitWithDefaultTimeout()
    25  		Expect(session).Should(ExitCleanly())
    26  
    27  	})
    28  
    29  	It("podman rmi with short name", func() {
    30  		podmanTest.AddImageToRWStore(CIRROS_IMAGE)
    31  		session := podmanTest.Podman([]string{"rmi", "cirros"})
    32  		session.WaitWithDefaultTimeout()
    33  		Expect(session).Should(ExitCleanly())
    34  
    35  	})
    36  
    37  	It("podman rmi all images", func() {
    38  		podmanTest.AddImageToRWStore(NGINX_IMAGE)
    39  		session := podmanTest.Podman([]string{"rmi", "-a"})
    40  		session.WaitWithDefaultTimeout()
    41  		images := podmanTest.Podman([]string{"images"})
    42  		images.WaitWithDefaultTimeout()
    43  		Expect(session).Should(ExitCleanly())
    44  
    45  	})
    46  
    47  	It("podman rmi all images forcibly with short options", func() {
    48  		podmanTest.AddImageToRWStore(NGINX_IMAGE)
    49  		session := podmanTest.Podman([]string{"rmi", "-fa"})
    50  		session.WaitWithDefaultTimeout()
    51  		Expect(session).Should(ExitCleanly())
    52  
    53  	})
    54  
    55  	It("podman rmi tagged image", func() {
    56  		podmanTest.AddImageToRWStore(CIRROS_IMAGE)
    57  		setup := podmanTest.Podman([]string{"images", "-q", CIRROS_IMAGE})
    58  		setup.WaitWithDefaultTimeout()
    59  		Expect(setup).Should(ExitCleanly())
    60  
    61  		session := podmanTest.Podman([]string{"tag", CIRROS_IMAGE, "foo:bar", "foo"})
    62  		session.WaitWithDefaultTimeout()
    63  		Expect(session).Should(ExitCleanly())
    64  
    65  		result := podmanTest.Podman([]string{"images", "-q", "foo"})
    66  		result.WaitWithDefaultTimeout()
    67  		Expect(result).Should(ExitCleanly())
    68  
    69  		Expect(result.OutputToString()).To(ContainSubstring(setup.OutputToString()))
    70  	})
    71  
    72  	It("podman rmi image with tags by ID cannot be done without force", func() {
    73  		podmanTest.AddImageToRWStore(CIRROS_IMAGE)
    74  		setup := podmanTest.Podman([]string{"images", "-q", "--no-trunc", CIRROS_IMAGE})
    75  		setup.WaitWithDefaultTimeout()
    76  		Expect(setup).Should(ExitCleanly())
    77  		cirrosID := setup.OutputToString()[7:]
    78  
    79  		session := podmanTest.Podman([]string{"tag", "cirros", "foo:bar", "foo"})
    80  		session.WaitWithDefaultTimeout()
    81  		Expect(session).Should(ExitCleanly())
    82  
    83  		// Trying without --force should fail
    84  		result := podmanTest.Podman([]string{"rmi", cirrosID})
    85  		result.WaitWithDefaultTimeout()
    86  		Expect(result).To(ExitWithError(125, fmt.Sprintf(`unable to delete image "%s" by ID with more than one tag ([localhost/foo:latest localhost/foo:bar %s]): please force removal`, cirrosID, CIRROS_IMAGE)))
    87  
    88  		// With --force it should work
    89  		resultForce := podmanTest.Podman([]string{"rmi", "-f", cirrosID})
    90  		resultForce.WaitWithDefaultTimeout()
    91  		Expect(resultForce).Should(ExitCleanly())
    92  	})
    93  
    94  	It("podman rmi image that is a parent of another image", func() {
    95  		podmanTest.AddImageToRWStore(CIRROS_IMAGE)
    96  		session := podmanTest.Podman([]string{"run", "--name", "c_test", CIRROS_IMAGE, "true"})
    97  		session.WaitWithDefaultTimeout()
    98  		Expect(session).Should(ExitCleanly())
    99  
   100  		session = podmanTest.Podman([]string{"commit", "-q", "c_test", "test"})
   101  		session.WaitWithDefaultTimeout()
   102  		Expect(session).Should(ExitCleanly())
   103  
   104  		session = podmanTest.Podman([]string{"rm", "c_test"})
   105  		session.WaitWithDefaultTimeout()
   106  		Expect(session).Should(ExitCleanly())
   107  
   108  		session = podmanTest.Podman([]string{"rmi", CIRROS_IMAGE})
   109  		session.WaitWithDefaultTimeout()
   110  		Expect(session).Should(ExitCleanly())
   111  		Expect(session.OutputToString()).To(Equal("Untagged: " + CIRROS_IMAGE))
   112  
   113  		session = podmanTest.Podman([]string{"images", "--sort", "created", "--format", "{{.Id}}", "--all"})
   114  		session.WaitWithDefaultTimeout()
   115  		Expect(session).Should(ExitCleanly())
   116  		Expect(session.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES)+1),
   117  			"Output from 'podman images'")
   118  		untaggedImg := session.OutputToStringArray()[1]
   119  
   120  		session = podmanTest.Podman([]string{"rmi", "-f", untaggedImg})
   121  		session.WaitWithDefaultTimeout()
   122  		Expect(session).Should(ExitWithError(125, fmt.Sprintf(`cannot remove read-only image "%s"`, untaggedImg)))
   123  	})
   124  
   125  	It("podman rmi image that is created from another named imaged", func() {
   126  		podmanTest.AddImageToRWStore(ALPINE)
   127  		session := podmanTest.Podman([]string{"create", "--name", "c_test1", ALPINE, "true"})
   128  		session.WaitWithDefaultTimeout()
   129  		Expect(session).Should(ExitCleanly())
   130  
   131  		session = podmanTest.Podman([]string{"commit", "-q", "c_test1", "test1"})
   132  		session.WaitWithDefaultTimeout()
   133  		Expect(session).Should(ExitCleanly())
   134  
   135  		session = podmanTest.Podman([]string{"create", "--name", "c_test2", "test1", "true"})
   136  		session.WaitWithDefaultTimeout()
   137  		Expect(session).Should(ExitCleanly())
   138  
   139  		session = podmanTest.Podman([]string{"commit", "-q", "c_test2", "test2"})
   140  		session.WaitWithDefaultTimeout()
   141  		Expect(session).Should(ExitCleanly())
   142  
   143  		session = podmanTest.Podman([]string{"rm", "-a"})
   144  		session.WaitWithDefaultTimeout()
   145  		Expect(session).Should(ExitCleanly())
   146  
   147  		session = podmanTest.Podman([]string{"rmi", "test2"})
   148  		session.WaitWithDefaultTimeout()
   149  		Expect(session).Should(ExitCleanly())
   150  
   151  		session = podmanTest.Podman([]string{"images", "-q"})
   152  		session.WaitWithDefaultTimeout()
   153  		Expect(session).Should(ExitCleanly())
   154  		Expect(session.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES) + 1))
   155  	})
   156  
   157  	It("podman rmi with cached images", func() {
   158  		podmanTest.AddImageToRWStore(CIRROS_IMAGE)
   159  		dockerfile := fmt.Sprintf(`FROM %s
   160  		RUN mkdir hello
   161  		RUN touch test.txt
   162  		ENV foo=bar
   163  		`, CIRROS_IMAGE)
   164  		podmanTest.BuildImage(dockerfile, "test", "true")
   165  
   166  		dockerfile = fmt.Sprintf(`FROM %s
   167  		RUN mkdir hello
   168  		RUN touch test.txt
   169  		RUN mkdir blah
   170  		ENV foo=bar
   171  		`, CIRROS_IMAGE)
   172  
   173  		podmanTest.BuildImage(dockerfile, "test2", "true")
   174  
   175  		session := podmanTest.Podman([]string{"images", "-q", "-a"})
   176  		session.WaitWithDefaultTimeout()
   177  		Expect(session).Should(ExitCleanly())
   178  		numOfImages := len(session.OutputToStringArray())
   179  
   180  		session = podmanTest.Podman([]string{"rmi", "test2"})
   181  		session.WaitWithDefaultTimeout()
   182  		Expect(session).Should(ExitCleanly())
   183  
   184  		session = podmanTest.Podman([]string{"images", "-q", "-a"})
   185  		session.WaitWithDefaultTimeout()
   186  		Expect(session).Should(ExitCleanly())
   187  		Expect(numOfImages - len(session.OutputToStringArray())).To(Equal(2))
   188  
   189  		session = podmanTest.Podman([]string{"rmi", "test"})
   190  		session.WaitWithDefaultTimeout()
   191  		Expect(session).Should(ExitCleanly())
   192  
   193  		session = podmanTest.Podman([]string{"images", "-q", "-a"})
   194  		session.WaitWithDefaultTimeout()
   195  		Expect(session).Should(ExitCleanly())
   196  		Expect(session.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES) + 1))
   197  
   198  		podmanTest.BuildImage(dockerfile, "test3", "true")
   199  
   200  		session = podmanTest.Podman([]string{"rmi", CIRROS_IMAGE})
   201  		session.WaitWithDefaultTimeout()
   202  		Expect(session).Should(ExitCleanly())
   203  
   204  		session = podmanTest.Podman([]string{"rmi", "test3"})
   205  		session.WaitWithDefaultTimeout()
   206  		Expect(session).Should(ExitCleanly())
   207  
   208  		session = podmanTest.Podman([]string{"images", "-q", "-a"})
   209  		session.WaitWithDefaultTimeout()
   210  		Expect(session).Should(ExitCleanly())
   211  		Expect(session.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES)))
   212  	})
   213  
   214  	It("podman rmi -a with no images should be exit 0", func() {
   215  		session := podmanTest.Podman([]string{"rmi", "-fa"})
   216  		session.WaitWithDefaultTimeout()
   217  		Expect(session).Should(ExitCleanly())
   218  
   219  		session2 := podmanTest.Podman([]string{"rmi", "-fa"})
   220  		session2.WaitWithDefaultTimeout()
   221  		Expect(session2).Should(ExitCleanly())
   222  	})
   223  
   224  	It("podman rmi -a with parent|child images", func() {
   225  		podmanTest.AddImageToRWStore(CIRROS_IMAGE)
   226  		dockerfile := fmt.Sprintf(`FROM %s AS base
   227  RUN touch /1
   228  ENV LOCAL=/1
   229  RUN find $LOCAL
   230  FROM base
   231  RUN find $LOCAL
   232  
   233  `, CIRROS_IMAGE)
   234  		podmanTest.BuildImage(dockerfile, "test", "true")
   235  		session := podmanTest.Podman([]string{"rmi", "-a"})
   236  		session.WaitWithDefaultTimeout()
   237  		Expect(session).Should(ExitCleanly())
   238  
   239  		images := podmanTest.Podman([]string{"images", "-aq"})
   240  		images.WaitWithDefaultTimeout()
   241  		Expect(images).Should(ExitCleanly())
   242  		Expect(images.OutputToStringArray()).To(HaveLen(len(CACHE_IMAGES)))
   243  	})
   244  
   245  	// Don't rerun all tests; just assume that if we get that diagnostic,
   246  	// we're getting rmi
   247  	It("podman image rm is the same as rmi", func() {
   248  		session := podmanTest.Podman([]string{"image", "rm"})
   249  		session.WaitWithDefaultTimeout()
   250  		Expect(session).Should(ExitWithError(125, "image name or ID must be specified"))
   251  	})
   252  
   253  	It("podman image rm - concurrent with shared layers", func() {
   254  		// #6510 has shown a fairly simple reproducer to force storage
   255  		// errors during parallel image removal.  Since it's subject to
   256  		// a race, we may not hit the condition a 100 percent of times
   257  		// but ocal reproducers hit it all the time.
   258  
   259  		podmanTest.AddImageToRWStore(CIRROS_IMAGE)
   260  		var wg sync.WaitGroup
   261  
   262  		// Prepare images
   263  		wg.Add(10)
   264  		for i := 0; i < 10; i++ {
   265  			go func(i int) {
   266  				defer GinkgoRecover()
   267  				defer wg.Done()
   268  				imageName := fmt.Sprintf("rmtest:%d", i)
   269  				containerfile := fmt.Sprintf(`FROM %s
   270  	RUN touch %s`, CIRROS_IMAGE, imageName)
   271  
   272  				podmanTest.BuildImage(containerfile, imageName, "false")
   273  			}(i)
   274  		}
   275  		wg.Wait()
   276  
   277  		// A herd of concurrent removals
   278  		wg.Add(10)
   279  		for i := 0; i < 10; i++ {
   280  			go func(i int) {
   281  				defer GinkgoRecover()
   282  				defer wg.Done()
   283  
   284  				imageName := fmt.Sprintf("rmtest:%d", i)
   285  				session := podmanTest.Podman([]string{"rmi", "-f", imageName})
   286  				session.WaitWithDefaultTimeout()
   287  				Expect(session).Should(ExitCleanly())
   288  			}(i)
   289  		}
   290  		wg.Wait()
   291  	})
   292  
   293  	It("podman rmi --no-prune with dangling parents", func() {
   294  		podmanTest.AddImageToRWStore(ALPINE)
   295  		session := podmanTest.Podman([]string{"create", "--name", "c_test1", ALPINE, "true"})
   296  		session.WaitWithDefaultTimeout()
   297  		Expect(session).Should(ExitCleanly())
   298  
   299  		session = podmanTest.Podman([]string{"commit", "-q", "c_test1", "test1"})
   300  		session.WaitWithDefaultTimeout()
   301  		Expect(session).Should(ExitCleanly())
   302  
   303  		session = podmanTest.Podman([]string{"create", "--name", "c_test2", "test1", "true"})
   304  		session.WaitWithDefaultTimeout()
   305  		Expect(session).Should(ExitCleanly())
   306  
   307  		session = podmanTest.Podman([]string{"commit", "-q", "c_test2", "test2"})
   308  		session.WaitWithDefaultTimeout()
   309  		Expect(session).Should(ExitCleanly())
   310  		imageID2 := session.OutputToString()
   311  
   312  		session = podmanTest.Podman([]string{"create", "--name", "c_test3", "test2", "true"})
   313  		session.WaitWithDefaultTimeout()
   314  		Expect(session).Should(ExitCleanly())
   315  
   316  		session = podmanTest.Podman([]string{"commit", "-q", "c_test3", "test3"})
   317  		session.WaitWithDefaultTimeout()
   318  		Expect(session).Should(ExitCleanly())
   319  		imageID3 := session.OutputToString()
   320  
   321  		session = podmanTest.Podman([]string{"untag", "test2"})
   322  		session.WaitWithDefaultTimeout()
   323  		Expect(session).Should(ExitCleanly())
   324  
   325  		session = podmanTest.Podman([]string{"untag", "test1"})
   326  		session.WaitWithDefaultTimeout()
   327  		Expect(session).Should(ExitCleanly())
   328  
   329  		session = podmanTest.Podman([]string{"rmi", "-f", "--no-prune", "test3"})
   330  		session.WaitWithDefaultTimeout()
   331  		Expect(session).Should(ExitCleanly())
   332  		Expect(session.OutputToString()).To(ContainSubstring(imageID3))
   333  		Expect(session.OutputToString()).NotTo(ContainSubstring(imageID2))
   334  	})
   335  
   336  	It("podman rmi --no-prune with undangling parents", func() {
   337  		podmanTest.AddImageToRWStore(ALPINE)
   338  		session := podmanTest.Podman([]string{"create", "--name", "c_test1", ALPINE, "true"})
   339  		session.WaitWithDefaultTimeout()
   340  		Expect(session).Should(ExitCleanly())
   341  
   342  		session = podmanTest.Podman([]string{"commit", "-q", "c_test1", "test1"})
   343  		session.WaitWithDefaultTimeout()
   344  		Expect(session).Should(ExitCleanly())
   345  
   346  		session = podmanTest.Podman([]string{"create", "--name", "c_test2", "test1", "true"})
   347  		session.WaitWithDefaultTimeout()
   348  		Expect(session).Should(ExitCleanly())
   349  
   350  		session = podmanTest.Podman([]string{"commit", "-q", "c_test2", "test2"})
   351  		session.WaitWithDefaultTimeout()
   352  		Expect(session).Should(ExitCleanly())
   353  		imageID2 := session.OutputToString()
   354  
   355  		session = podmanTest.Podman([]string{"create", "--name", "c_test3", "test2", "true"})
   356  		session.WaitWithDefaultTimeout()
   357  		Expect(session).Should(ExitCleanly())
   358  
   359  		session = podmanTest.Podman([]string{"commit", "-q", "c_test3", "test3"})
   360  		session.WaitWithDefaultTimeout()
   361  		Expect(session).Should(ExitCleanly())
   362  		imageID3 := session.OutputToString()
   363  
   364  		session = podmanTest.Podman([]string{"rmi", "-f", "--no-prune", "test3"})
   365  		session.WaitWithDefaultTimeout()
   366  		Expect(session).Should(ExitCleanly())
   367  		Expect(session.OutputToString()).To(ContainSubstring(imageID3))
   368  		Expect(session.OutputToString()).NotTo(ContainSubstring(imageID2))
   369  	})
   370  })