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