github.com/containers/podman/v4@v4.9.4/test/e2e/pull_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "runtime" 8 9 . "github.com/containers/podman/v4/test/utils" 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 . "github.com/onsi/gomega/gexec" 13 ) 14 15 var _ = Describe("Podman pull", func() { 16 17 It("podman pull multiple images with/without tag/digest", func() { 18 session := podmanTest.Podman([]string{"pull", "-q", "busybox:musl", "alpine", "alpine:latest", "quay.io/libpod/cirros", "quay.io/libpod/testdigest_v2s2@sha256:755f4d90b3716e2bf57060d249e2cd61c9ac089b1233465c5c2cb2d7ee550fdb"}) 19 session.WaitWithDefaultTimeout() 20 Expect(session).Should(ExitCleanly()) 21 22 session = podmanTest.Podman([]string{"pull", "busybox:latest", "docker.io/library/ibetthisdoesnotexistfr:random", "alpine"}) 23 session.WaitWithDefaultTimeout() 24 Expect(session).Should(Exit(125)) 25 expectedError := "initializing source docker://ibetthisdoesnotexistfr:random" 26 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 27 28 session = podmanTest.Podman([]string{"rmi", "busybox:musl", "alpine", "quay.io/libpod/cirros", "testdigest_v2s2@sha256:755f4d90b3716e2bf57060d249e2cd61c9ac089b1233465c5c2cb2d7ee550fdb"}) 29 session.WaitWithDefaultTimeout() 30 Expect(session).Should(ExitCleanly()) 31 }) 32 33 It("podman pull bogus image", func() { 34 session := podmanTest.Podman([]string{"pull", "quay.io/libpod/ibetthisdoesntexist:there"}) 35 session.WaitWithDefaultTimeout() 36 Expect(session).To(ExitWithError()) 37 // "Not authorized", not "Not Found", because that's how registries roll?? 38 Expect(session.ErrorToString()).To(ContainSubstring("unauthorized: access to the requested resource is not authorized")) 39 }) 40 41 It("podman pull with tag --quiet", func() { 42 session := podmanTest.Podman([]string{"pull", "-q", "quay.io/libpod/testdigest_v2s2:20200210"}) 43 session.WaitWithDefaultTimeout() 44 Expect(session).Should(ExitCleanly()) 45 quietOutput := session.OutputToString() 46 47 session = podmanTest.Podman([]string{"inspect", "testdigest_v2s2:20200210", "--format", "{{.ID}}"}) 48 session.WaitWithDefaultTimeout() 49 Expect(session).Should(ExitCleanly()) 50 Expect(session.OutputToString()).To(Equal(quietOutput)) 51 52 session = podmanTest.Podman([]string{"rmi", "testdigest_v2s2:20200210"}) 53 session.WaitWithDefaultTimeout() 54 Expect(session).Should(ExitCleanly()) 55 }) 56 57 It("podman pull without tag", func() { 58 session := podmanTest.Podman([]string{"pull", "-q", "quay.io/libpod/testdigest_v2s2"}) 59 session.WaitWithDefaultTimeout() 60 Expect(session).Should(ExitCleanly()) 61 62 session = podmanTest.Podman([]string{"rmi", "testdigest_v2s2"}) 63 session.WaitWithDefaultTimeout() 64 Expect(session).Should(ExitCleanly()) 65 }) 66 67 It("podman pull and run on split imagestore", func() { 68 SkipIfRemote("podman-remote does not support setting external imagestore") 69 imgName := "splitstoretest" 70 71 // Make alpine write-able 72 session := podmanTest.Podman([]string{"build", "--pull=never", "--tag", imgName, "build/basicalpine"}) 73 session.WaitWithDefaultTimeout() 74 Expect(session).Should(ExitCleanly()) 75 76 tmpDir := filepath.Join(podmanTest.TempDir, "splitstore") 77 outfile := filepath.Join(podmanTest.TempDir, "image.tar") 78 79 save := podmanTest.Podman([]string{"save", "-q", "-o", outfile, "--format", "oci-archive", imgName}) 80 save.WaitWithDefaultTimeout() 81 Expect(save).Should(ExitCleanly()) 82 83 rmi := podmanTest.Podman([]string{"rmi", imgName}) 84 rmi.WaitWithDefaultTimeout() 85 Expect(rmi).Should(ExitCleanly()) 86 87 // load to splitstore 88 result := podmanTest.Podman([]string{"load", "-q", "--imagestore", tmpDir, "-q", "-i", outfile}) 89 result.WaitWithDefaultTimeout() 90 Expect(result).Should(ExitCleanly()) 91 92 // tag busybox to busybox-test in graphroot since we can delete readonly busybox 93 session = podmanTest.Podman([]string{"tag", "quay.io/libpod/busybox:latest", "busybox-test"}) 94 session.WaitWithDefaultTimeout() 95 Expect(session).Should(ExitCleanly()) 96 97 session = podmanTest.Podman([]string{"images", "--imagestore", tmpDir}) 98 session.WaitWithDefaultTimeout() 99 Expect(session).Should(ExitCleanly()) 100 Expect(session.OutputToString()).To(ContainSubstring(imgName)) 101 Expect(session.OutputToString()).To(ContainSubstring("busybox-test")) 102 103 // Test deleting image in graphroot even when `--imagestore` is set 104 session = podmanTest.Podman([]string{"rmi", "--imagestore", tmpDir, "busybox-test"}) 105 session.WaitWithDefaultTimeout() 106 Expect(session).Should(ExitCleanly()) 107 108 // Images without --imagestore should not contain alpine 109 session = podmanTest.Podman([]string{"images"}) 110 session.WaitWithDefaultTimeout() 111 Expect(session).Should(ExitCleanly()) 112 Expect(session.OutputToString()).To(Not(ContainSubstring(imgName))) 113 114 // Set `imagestore` in `storage.conf` and container should run. 115 configPath := filepath.Join(podmanTest.TempDir, ".config", "containers", "storage.conf") 116 os.Setenv("CONTAINERS_STORAGE_CONF", configPath) 117 defer func() { 118 os.Unsetenv("CONTAINERS_STORAGE_CONF") 119 }() 120 121 err = os.MkdirAll(filepath.Dir(configPath), os.ModePerm) 122 Expect(err).ToNot(HaveOccurred()) 123 storageConf := []byte(fmt.Sprintf("[storage]\nimagestore=\"%s\"", tmpDir)) 124 err = os.WriteFile(configPath, storageConf, os.ModePerm) 125 Expect(err).ToNot(HaveOccurred()) 126 127 session = podmanTest.Podman([]string{"run", "--name", "test", "--rm", 128 imgName, "echo", "helloworld"}) 129 session.WaitWithDefaultTimeout() 130 Expect(session).Should(Exit(0)) 131 Expect(session.OutputToString()).To(ContainSubstring("helloworld")) 132 Expect(session.ErrorToString()).To(ContainSubstring("The storage 'driver' option should be set in ")) 133 Expect(session.ErrorToString()).To(ContainSubstring("A driver was picked automatically.")) 134 }) 135 136 It("podman pull by digest", func() { 137 session := podmanTest.Podman([]string{"pull", "-q", "quay.io/libpod/testdigest_v2s2@sha256:755f4d90b3716e2bf57060d249e2cd61c9ac089b1233465c5c2cb2d7ee550fdb"}) 138 session.WaitWithDefaultTimeout() 139 Expect(session).Should(ExitCleanly()) 140 141 // Without a tag/digest the input is normalized with the "latest" tag, see #11964 142 session = podmanTest.Podman([]string{"rmi", "testdigest_v2s2"}) 143 session.WaitWithDefaultTimeout() 144 Expect(session).Should(Exit(1)) 145 146 session = podmanTest.Podman([]string{"rmi", "testdigest_v2s2@sha256:755f4d90b3716e2bf57060d249e2cd61c9ac089b1233465c5c2cb2d7ee550fdb"}) 147 session.WaitWithDefaultTimeout() 148 Expect(session).Should(ExitCleanly()) 149 }) 150 151 It("podman pull check all tags", func() { 152 session := podmanTest.Podman([]string{"pull", "-q", "--all-tags", "quay.io/libpod/testdigest_v2s2"}) 153 session.WaitWithDefaultTimeout() 154 Expect(session).Should(ExitCleanly()) 155 156 session = podmanTest.Podman([]string{"images"}) 157 session.WaitWithDefaultTimeout() 158 Expect(session).Should(ExitCleanly()) 159 Expect(len(session.OutputToStringArray())).To(BeNumerically(">=", 2), "Expected at least two images") 160 161 session = podmanTest.Podman([]string{"pull", "-q", "-a", "quay.io/libpod/testdigest_v2s2"}) 162 session.WaitWithDefaultTimeout() 163 Expect(session).Should(ExitCleanly()) 164 165 session = podmanTest.Podman([]string{"images"}) 166 session.WaitWithDefaultTimeout() 167 Expect(session).Should(ExitCleanly()) 168 Expect(len(session.OutputToStringArray())).To(BeNumerically(">=", 2), "Expected at least two images") 169 }) 170 171 It("podman pull from docker with nonexistent --authfile", func() { 172 session := podmanTest.Podman([]string{"pull", "-q", "--authfile", "/tmp/nonexistent", ALPINE}) 173 session.WaitWithDefaultTimeout() 174 Expect(session).To(ExitWithError()) 175 Expect(session.ErrorToString()).To(Equal("Error: credential file is not accessible: stat /tmp/nonexistent: no such file or directory")) 176 }) 177 178 It("podman pull by digest (image list)", func() { 179 session := podmanTest.Podman([]string{"pull", "-q", "--arch=arm64", ALPINELISTDIGEST}) 180 session.WaitWithDefaultTimeout() 181 Expect(session).Should(ExitCleanly()) 182 // inspect using the digest of the list 183 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINELISTDIGEST}) 184 session.WaitWithDefaultTimeout() 185 Expect(session).Should(ExitCleanly()) 186 Expect(string(session.Out.Contents())).To(HavePrefix("[]")) 187 // inspect using the digest of the list 188 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINELISTDIGEST}) 189 session.WaitWithDefaultTimeout() 190 Expect(session).Should(ExitCleanly()) 191 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTDIGEST)) 192 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 193 // inspect using the digest of the arch-specific image's manifest 194 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINEARM64DIGEST}) 195 session.WaitWithDefaultTimeout() 196 Expect(session).Should(ExitCleanly()) 197 Expect(string(session.Out.Contents())).To(HavePrefix("[]")) 198 // inspect using the digest of the arch-specific image's manifest 199 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINEARM64DIGEST}) 200 session.WaitWithDefaultTimeout() 201 Expect(session).Should(ExitCleanly()) 202 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTDIGEST)) 203 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 204 // inspect using the image ID 205 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINEARM64ID}) 206 session.WaitWithDefaultTimeout() 207 Expect(session).Should(ExitCleanly()) 208 Expect(string(session.Out.Contents())).To(HavePrefix("[]")) 209 // inspect using the image ID 210 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINEARM64ID}) 211 session.WaitWithDefaultTimeout() 212 Expect(session).Should(ExitCleanly()) 213 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTDIGEST)) 214 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 215 // remove using the digest of the list 216 session = podmanTest.Podman([]string{"rmi", ALPINELISTDIGEST}) 217 session.WaitWithDefaultTimeout() 218 Expect(session).Should(ExitCleanly()) 219 }) 220 221 It("podman pull by instance digest (image list)", func() { 222 session := podmanTest.Podman([]string{"pull", "-q", "--arch=arm64", ALPINEARM64DIGEST}) 223 session.WaitWithDefaultTimeout() 224 Expect(session).Should(ExitCleanly()) 225 // inspect using the digest of the list 226 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINELISTDIGEST}) 227 session.WaitWithDefaultTimeout() 228 Expect(session).To(ExitWithError()) 229 // inspect using the digest of the list 230 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINELISTDIGEST}) 231 session.WaitWithDefaultTimeout() 232 Expect(session).To(ExitWithError()) 233 // inspect using the digest of the arch-specific image's manifest 234 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINEARM64DIGEST}) 235 session.WaitWithDefaultTimeout() 236 Expect(session).Should(ExitCleanly()) 237 Expect(string(session.Out.Contents())).To(HavePrefix("[]")) 238 // inspect using the digest of the arch-specific image's manifest 239 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINEARM64DIGEST}) 240 session.WaitWithDefaultTimeout() 241 Expect(session).Should(ExitCleanly()) 242 Expect(string(session.Out.Contents())).To(Not(ContainSubstring(ALPINELISTDIGEST))) 243 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 244 // inspect using the image ID 245 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINEARM64ID}) 246 session.WaitWithDefaultTimeout() 247 Expect(session).Should(ExitCleanly()) 248 Expect(string(session.Out.Contents())).To(HavePrefix("[]")) 249 // inspect using the image ID 250 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINEARM64ID}) 251 session.WaitWithDefaultTimeout() 252 Expect(session).Should(ExitCleanly()) 253 Expect(string(session.Out.Contents())).To(Not(ContainSubstring(ALPINELISTDIGEST))) 254 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 255 // remove using the digest of the instance 256 session = podmanTest.Podman([]string{"rmi", ALPINEARM64DIGEST}) 257 session.WaitWithDefaultTimeout() 258 Expect(session).Should(ExitCleanly()) 259 }) 260 261 It("podman pull by tag (image list)", func() { 262 session := podmanTest.Podman([]string{"pull", "-q", "--arch=arm64", ALPINELISTTAG}) 263 session.WaitWithDefaultTimeout() 264 Expect(session).Should(ExitCleanly()) 265 // inspect using the tag we used for pulling 266 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINELISTTAG}) 267 session.WaitWithDefaultTimeout() 268 Expect(session).Should(ExitCleanly()) 269 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTTAG)) 270 // inspect using the tag we used for pulling 271 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINELISTTAG}) 272 session.WaitWithDefaultTimeout() 273 Expect(session).Should(ExitCleanly()) 274 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTDIGEST)) 275 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 276 // inspect using the digest of the list 277 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINELISTDIGEST}) 278 session.WaitWithDefaultTimeout() 279 Expect(session).Should(ExitCleanly()) 280 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTTAG)) 281 // inspect using the digest of the list 282 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINELISTDIGEST}) 283 session.WaitWithDefaultTimeout() 284 Expect(session).Should(ExitCleanly()) 285 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTDIGEST)) 286 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 287 // inspect using the digest of the arch-specific image's manifest 288 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINEARM64DIGEST}) 289 session.WaitWithDefaultTimeout() 290 Expect(session).Should(ExitCleanly()) 291 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTTAG)) 292 // inspect using the digest of the arch-specific image's manifest 293 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINEARM64DIGEST}) 294 session.WaitWithDefaultTimeout() 295 Expect(session).Should(ExitCleanly()) 296 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTDIGEST)) 297 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 298 // inspect using the image ID 299 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoTags}}", ALPINEARM64ID}) 300 session.WaitWithDefaultTimeout() 301 Expect(session).Should(ExitCleanly()) 302 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTTAG)) 303 // inspect using the image ID 304 session = podmanTest.Podman([]string{"inspect", "--format", "{{.RepoDigests}}", ALPINEARM64ID}) 305 session.WaitWithDefaultTimeout() 306 Expect(session).Should(ExitCleanly()) 307 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINELISTDIGEST)) 308 Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST)) 309 // remove using the tag 310 session = podmanTest.Podman([]string{"rmi", ALPINELISTTAG}) 311 session.WaitWithDefaultTimeout() 312 Expect(session).Should(ExitCleanly()) 313 }) 314 315 It("podman pull from docker-archive", func() { 316 SkipIfRemote("podman-remote does not support pulling from docker-archive") 317 318 podmanTest.AddImageToRWStore(CIRROS_IMAGE) 319 tarfn := filepath.Join(podmanTest.TempDir, "cirros.tar") 320 session := podmanTest.Podman([]string{"save", "-q", "-o", tarfn, "cirros"}) 321 session.WaitWithDefaultTimeout() 322 323 Expect(session).Should(ExitCleanly()) 324 session = podmanTest.Podman([]string{"rmi", "cirros"}) 325 session.WaitWithDefaultTimeout() 326 Expect(session).Should(ExitCleanly()) 327 session = podmanTest.Podman([]string{"pull", "-q", fmt.Sprintf("docker-archive:%s", tarfn)}) 328 session.WaitWithDefaultTimeout() 329 Expect(session).Should(ExitCleanly()) 330 session = podmanTest.Podman([]string{"rmi", "cirros"}) 331 session.WaitWithDefaultTimeout() 332 Expect(session).Should(ExitCleanly()) 333 334 // Pulling a multi-image archive without further specifying 335 // which image _must_ error out. Pulling is restricted to one 336 // image. 337 session = podmanTest.Podman([]string{"pull", "-q", "docker-archive:./testdata/docker-two-images.tar.xz"}) 338 session.WaitWithDefaultTimeout() 339 Expect(session).Should(Exit(125)) 340 expectedError := "Unexpected tar manifest.json: expected 1 item, got 2" 341 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 342 343 // Now pull _one_ image from a multi-image archive via the name 344 // and index syntax. 345 session = podmanTest.Podman([]string{"pull", "-q", "docker-archive:./testdata/docker-two-images.tar.xz:@0"}) 346 session.WaitWithDefaultTimeout() 347 Expect(session).Should(ExitCleanly()) 348 349 session = podmanTest.Podman([]string{"pull", "-q", "docker-archive:./testdata/docker-two-images.tar.xz:example.com/empty:latest"}) 350 session.WaitWithDefaultTimeout() 351 Expect(session).Should(ExitCleanly()) 352 353 session = podmanTest.Podman([]string{"pull", "-q", "docker-archive:./testdata/docker-two-images.tar.xz:@1"}) 354 session.WaitWithDefaultTimeout() 355 Expect(session).Should(ExitCleanly()) 356 357 session = podmanTest.Podman([]string{"pull", "-q", "docker-archive:./testdata/docker-two-images.tar.xz:example.com/empty/but:different"}) 358 session.WaitWithDefaultTimeout() 359 Expect(session).Should(ExitCleanly()) 360 361 // Now check for some errors. 362 session = podmanTest.Podman([]string{"pull", "-q", "docker-archive:./testdata/docker-two-images.tar.xz:foo.com/does/not/exist:latest"}) 363 session.WaitWithDefaultTimeout() 364 Expect(session).Should(Exit(125)) 365 expectedError = "Tag \"foo.com/does/not/exist:latest\" not found" 366 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 367 368 session = podmanTest.Podman([]string{"pull", "-q", "docker-archive:./testdata/docker-two-images.tar.xz:@2"}) 369 session.WaitWithDefaultTimeout() 370 Expect(session).Should(Exit(125)) 371 expectedError = "Invalid source index @2, only 2 manifest items available" 372 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 373 }) 374 375 It("podman pull from oci-archive", func() { 376 SkipIfRemote("podman-remote does not support pulling from oci-archive") 377 378 podmanTest.AddImageToRWStore(CIRROS_IMAGE) 379 tarfn := filepath.Join(podmanTest.TempDir, "oci-cirrus.tar") 380 session := podmanTest.Podman([]string{"save", "-q", "--format", "oci-archive", "-o", tarfn, "cirros"}) 381 session.WaitWithDefaultTimeout() 382 383 Expect(session).Should(ExitCleanly()) 384 session = podmanTest.Podman([]string{"rmi", "cirros"}) 385 session.WaitWithDefaultTimeout() 386 Expect(session).Should(ExitCleanly()) 387 session = podmanTest.Podman([]string{"pull", "-q", fmt.Sprintf("oci-archive:%s", tarfn)}) 388 session.WaitWithDefaultTimeout() 389 Expect(session).Should(ExitCleanly()) 390 session = podmanTest.Podman([]string{"rmi", "cirros"}) 391 session.WaitWithDefaultTimeout() 392 Expect(session).Should(ExitCleanly()) 393 }) 394 395 It("podman pull from local directory", func() { 396 SkipIfRemote("podman-remote does not support pulling from local directory") 397 398 podmanTest.AddImageToRWStore(CIRROS_IMAGE) 399 dirpath := filepath.Join(podmanTest.TempDir, "cirros") 400 err = os.MkdirAll(dirpath, os.ModePerm) 401 Expect(err).ToNot(HaveOccurred()) 402 imgPath := fmt.Sprintf("dir:%s", dirpath) 403 404 session := podmanTest.Podman([]string{"push", "-q", "cirros", imgPath}) 405 session.WaitWithDefaultTimeout() 406 Expect(session).Should(ExitCleanly()) 407 session = podmanTest.Podman([]string{"rmi", "cirros"}) 408 session.WaitWithDefaultTimeout() 409 Expect(session).Should(ExitCleanly()) 410 session = podmanTest.Podman([]string{"run", imgPath, "ls"}) 411 session.WaitWithDefaultTimeout() 412 Expect(session).Should(Exit(0)) 413 Expect(session.ErrorToString()).To(ContainSubstring("Copying blob"), "Image is pulled on run") 414 415 // Note that reference is not preserved in dir. 416 session = podmanTest.Podman([]string{"image", "exists", "cirros"}) 417 session.WaitWithDefaultTimeout() 418 Expect(session).Should(Exit(1)) 419 }) 420 421 It("podman pull from local OCI directory", func() { 422 SkipIfRemote("podman-remote does not support pulling from OCI directory") 423 424 podmanTest.AddImageToRWStore(CIRROS_IMAGE) 425 dirpath := filepath.Join(podmanTest.TempDir, "cirros") 426 err = os.MkdirAll(dirpath, os.ModePerm) 427 Expect(err).ToNot(HaveOccurred()) 428 imgName := "localhost/name:tag" 429 imgPath := fmt.Sprintf("oci:%s:%s", dirpath, imgName) 430 431 session := podmanTest.Podman([]string{"push", "-q", "cirros", imgPath}) 432 session.WaitWithDefaultTimeout() 433 Expect(session).Should(ExitCleanly()) 434 session = podmanTest.Podman([]string{"rmi", "cirros"}) 435 session.WaitWithDefaultTimeout() 436 Expect(session).Should(ExitCleanly()) 437 session = podmanTest.Podman([]string{"pull", "-q", imgPath}) 438 session.WaitWithDefaultTimeout() 439 Expect(session).Should(ExitCleanly()) 440 session = podmanTest.Podman([]string{"image", "exists", imgName}) 441 session.WaitWithDefaultTimeout() 442 Expect(session).Should(ExitCleanly()) 443 }) 444 445 It("podman pull + inspect from unqualified-search registry", func() { 446 // Regression test for #6381: 447 // Make sure that `pull shortname` and `inspect shortname` 448 // refer to the same image. 449 450 // We already tested pulling, so we can save some energy and 451 // just restore local artifacts and tag them. 452 err := podmanTest.RestoreArtifact(ALPINE) 453 Expect(err).ToNot(HaveOccurred()) 454 err = podmanTest.RestoreArtifact(BB) 455 Expect(err).ToNot(HaveOccurred()) 456 457 // What we want is at least two images which have the same name 458 // and are prefixed with two different unqualified-search 459 // registries from ../registries.conf. 460 // 461 // A `podman inspect $name` must yield the one from the _first_ 462 // matching registry in the registries.conf. 463 getID := func(image string) string { 464 setup := podmanTest.Podman([]string{"image", "inspect", image}) 465 setup.WaitWithDefaultTimeout() 466 Expect(setup).Should(ExitCleanly()) 467 468 data := setup.InspectImageJSON() // returns []inspect.ImageData 469 Expect(data).To(HaveLen(1)) 470 return data[0].ID 471 } 472 473 untag := func(image string) { 474 setup := podmanTest.Podman([]string{"untag", image}) 475 setup.WaitWithDefaultTimeout() 476 Expect(setup).Should(ExitCleanly()) 477 478 setup = podmanTest.Podman([]string{"image", "inspect", image}) 479 setup.WaitWithDefaultTimeout() 480 Expect(setup).Should(ExitCleanly()) 481 482 data := setup.InspectImageJSON() // returns []inspect.ImageData 483 Expect(data).To(HaveLen(1)) 484 Expect(data[0].RepoTags).To(BeEmpty()) 485 } 486 487 tag := func(image, tag string) { 488 setup := podmanTest.Podman([]string{"tag", image, tag}) 489 setup.WaitWithDefaultTimeout() 490 Expect(setup).Should(ExitCleanly()) 491 setup = podmanTest.Podman([]string{"image", "exists", tag}) 492 setup.WaitWithDefaultTimeout() 493 Expect(setup).Should(ExitCleanly()) 494 } 495 496 image1 := getID(ALPINE) 497 image2 := getID(BB) 498 499 // $ head -n2 ../registries.conf 500 // [registries.search] 501 // registries = ['docker.io', 'quay.io', 'registry.fedoraproject.org'] 502 registries := []string{"docker.io", "quay.io", "registry.fedoraproject.org"} 503 name := "foo/test:tag" 504 tests := []struct { 505 // tag1 has precedence (see list above) over tag2 when 506 // doing an inspect on "test:tag". 507 tag1, tag2 string 508 }{ 509 { 510 fmt.Sprintf("%s/%s", registries[0], name), 511 fmt.Sprintf("%s/%s", registries[1], name), 512 }, 513 { 514 fmt.Sprintf("%s/%s", registries[0], name), 515 fmt.Sprintf("%s/%s", registries[2], name), 516 }, 517 { 518 fmt.Sprintf("%s/%s", registries[1], name), 519 fmt.Sprintf("%s/%s", registries[2], name), 520 }, 521 } 522 523 for _, t := range tests { 524 // 1) untag both images 525 // 2) tag them according to `t` 526 // 3) make sure that an inspect of `name` returns `image1` with `tag1` 527 untag(image1) 528 untag(image2) 529 tag(image1, t.tag1) 530 tag(image2, t.tag2) 531 532 setup := podmanTest.Podman([]string{"image", "inspect", name}) 533 setup.WaitWithDefaultTimeout() 534 Expect(setup).Should(ExitCleanly()) 535 536 data := setup.InspectImageJSON() // returns []inspect.ImageData 537 Expect(data).To(HaveLen(1)) 538 Expect(data[0].RepoTags).To(HaveLen(1)) 539 Expect(data[0].RepoTags[0]).To(Equal(t.tag1)) 540 Expect(data[0]).To(HaveField("ID", image1)) 541 } 542 }) 543 544 It("podman pull --platform", func() { 545 session := podmanTest.Podman([]string{"pull", "-q", "--platform=linux/bogus", ALPINE}) 546 session.WaitWithDefaultTimeout() 547 Expect(session).Should(Exit(125)) 548 expectedError := "no image found in manifest list for architecture bogus" 549 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 550 551 session = podmanTest.Podman([]string{"pull", "-q", "--platform=linux/arm64", "--os", "windows", ALPINE}) 552 session.WaitWithDefaultTimeout() 553 Expect(session).Should(Exit(125)) 554 expectedError = "--platform option can not be specified with --arch or --os" 555 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 556 557 session = podmanTest.Podman([]string{"pull", "-q", "--platform=linux/arm64", ALPINE}) 558 session.WaitWithDefaultTimeout() 559 Expect(session).Should(ExitCleanly()) 560 561 setup := podmanTest.Podman([]string{"image", "inspect", session.OutputToString()}) 562 setup.WaitWithDefaultTimeout() 563 Expect(setup).Should(ExitCleanly()) 564 565 data := setup.InspectImageJSON() // returns []inspect.ImageData 566 Expect(data).To(HaveLen(1)) 567 Expect(data[0]).To(HaveField("Os", runtime.GOOS)) 568 Expect(data[0]).To(HaveField("Architecture", "arm64")) 569 }) 570 571 It("podman pull --arch", func() { 572 session := podmanTest.Podman([]string{"pull", "-q", "--arch=bogus", ALPINE}) 573 session.WaitWithDefaultTimeout() 574 Expect(session).Should(Exit(125)) 575 expectedError := "no image found in manifest list for architecture bogus" 576 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 577 578 session = podmanTest.Podman([]string{"pull", "-q", "--arch=arm64", "--os", "windows", ALPINE}) 579 session.WaitWithDefaultTimeout() 580 Expect(session).Should(Exit(125)) 581 expectedError = "no image found in manifest list for architecture" 582 Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) 583 584 session = podmanTest.Podman([]string{"pull", "-q", "--arch=arm64", ALPINE}) 585 session.WaitWithDefaultTimeout() 586 Expect(session).Should(ExitCleanly()) 587 588 setup := podmanTest.Podman([]string{"image", "inspect", session.OutputToString()}) 589 setup.WaitWithDefaultTimeout() 590 Expect(setup).Should(ExitCleanly()) 591 592 data := setup.InspectImageJSON() // returns []inspect.ImageData 593 Expect(data).To(HaveLen(1)) 594 Expect(data[0]).To(HaveField("Os", runtime.GOOS)) 595 Expect(data[0]).To(HaveField("Architecture", "arm64")) 596 }) 597 598 It("podman pull progress", func() { 599 session := podmanTest.Podman([]string{"pull", ALPINE}) 600 session.WaitWithDefaultTimeout() 601 Expect(session).Should(Exit(0)) 602 output := session.ErrorToString() 603 Expect(output).To(ContainSubstring("Getting image source signatures")) 604 Expect(output).To(ContainSubstring("Copying blob ")) 605 606 session = podmanTest.Podman([]string{"pull", "-q", ALPINE}) 607 session.WaitWithDefaultTimeout() 608 Expect(session).Should(ExitCleanly()) 609 }) 610 611 Describe("podman pull and decrypt", func() { 612 613 decryptionTestHelper := func(imgPath string) *PodmanSessionIntegration { 614 bitSize := 1024 615 keyFileName := filepath.Join(podmanTest.TempDir, "key") 616 publicKeyFileName, privateKeyFileName, err := WriteRSAKeyPair(keyFileName, bitSize) 617 Expect(err).ToNot(HaveOccurred()) 618 619 wrongKeyFileName := filepath.Join(podmanTest.TempDir, "wrong_key") 620 _, wrongPrivateKeyFileName, err := WriteRSAKeyPair(wrongKeyFileName, bitSize) 621 Expect(err).ToNot(HaveOccurred()) 622 623 session := podmanTest.Podman([]string{"push", "-q", "--encryption-key", "jwe:" + publicKeyFileName, "--tls-verify=false", "--remove-signatures", ALPINE, imgPath}) 624 session.WaitWithDefaultTimeout() 625 626 session = podmanTest.Podman([]string{"rmi", ALPINE}) 627 session.WaitWithDefaultTimeout() 628 Expect(session).Should(ExitCleanly()) 629 630 // Pulling encrypted image without key should fail 631 session = podmanTest.Podman([]string{"pull", imgPath}) 632 session.WaitWithDefaultTimeout() 633 Expect(session).Should(Exit(125)) 634 635 // Pulling encrypted image with wrong key should fail 636 session = podmanTest.Podman([]string{"pull", "-q", "--decryption-key", wrongPrivateKeyFileName, imgPath}) 637 session.WaitWithDefaultTimeout() 638 Expect(session).Should(Exit(125)) 639 640 // Pulling encrypted image with correct key should pass 641 session = podmanTest.Podman([]string{"pull", "-q", "--decryption-key", privateKeyFileName, imgPath}) 642 session.WaitWithDefaultTimeout() 643 Expect(session).Should(ExitCleanly()) 644 session = podmanTest.Podman([]string{"images"}) 645 session.WaitWithDefaultTimeout() 646 Expect(session).Should(ExitCleanly()) 647 648 return session 649 } 650 651 It("From oci", func() { 652 SkipIfRemote("Remote pull neither supports oci transport, nor decryption") 653 654 podmanTest.AddImageToRWStore(ALPINE) 655 656 bbdir := filepath.Join(podmanTest.TempDir, "busybox-oci") 657 imgName := "localhost/name:tag" 658 imgPath := fmt.Sprintf("oci:%s:%s", bbdir, imgName) 659 660 session := decryptionTestHelper(imgPath) 661 662 Expect(session.LineInOutputContainsTag("localhost/name", "tag")).To(BeTrue()) 663 }) 664 665 It("From local registry", func() { 666 SkipIfRemote("Remote pull does not support decryption") 667 668 if podmanTest.Host.Arch == "ppc64le" { 669 Skip("No registry image for ppc64le") 670 } 671 672 podmanTest.AddImageToRWStore(ALPINE) 673 674 if isRootless() { 675 err := podmanTest.RestoreArtifact(REGISTRY_IMAGE) 676 Expect(err).ToNot(HaveOccurred()) 677 } 678 lock := GetPortLock("5000") 679 defer lock.Unlock() 680 session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) 681 session.WaitWithDefaultTimeout() 682 Expect(session).Should(ExitCleanly()) 683 684 if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) { 685 Skip("Cannot start docker registry.") 686 } 687 688 imgPath := "localhost:5000/my-alpine" 689 690 session = decryptionTestHelper(imgPath) 691 692 Expect(session.LineInOutputContainsTag(imgPath, "latest")).To(BeTrue()) 693 }) 694 }) 695 696 })