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 })