github.com/rawahars/moby@v24.0.4+incompatible/integration/image/pull_test.go (about) 1 package image 2 3 import ( 4 "context" 5 "encoding/json" 6 "io" 7 "os" 8 "path" 9 "testing" 10 11 "github.com/containerd/containerd" 12 "github.com/containerd/containerd/content" 13 "github.com/containerd/containerd/content/local" 14 "github.com/containerd/containerd/images" 15 "github.com/containerd/containerd/platforms" 16 "github.com/docker/docker/api/types" 17 "github.com/docker/docker/api/types/versions" 18 "github.com/docker/docker/errdefs" 19 "github.com/docker/docker/testutil/registry" 20 "github.com/opencontainers/go-digest" 21 "github.com/opencontainers/image-spec/specs-go" 22 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 23 "gotest.tools/v3/assert" 24 "gotest.tools/v3/skip" 25 ) 26 27 func TestImagePullPlatformInvalid(t *testing.T) { 28 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"), "experimental in older versions") 29 defer setupTest(t)() 30 client := testEnv.APIClient() 31 ctx := context.Background() 32 33 _, err := client.ImagePull(ctx, "docker.io/library/hello-world:latest", types.ImagePullOptions{Platform: "foobar"}) 34 assert.Assert(t, err != nil) 35 assert.ErrorContains(t, err, "unknown operating system or architecture") 36 assert.Assert(t, errdefs.IsInvalidParameter(err)) 37 } 38 39 func createTestImage(ctx context.Context, t testing.TB, store content.Store) ocispec.Descriptor { 40 w, err := store.Writer(ctx, content.WithRef("layer")) 41 assert.NilError(t, err) 42 defer w.Close() 43 44 // Empty layer with just a root dir 45 const layer = `./0000775000000000000000000000000014201045023007702 5ustar rootroot` 46 47 _, err = w.Write([]byte(layer)) 48 assert.NilError(t, err) 49 50 err = w.Commit(ctx, int64(len(layer)), digest.FromBytes([]byte(layer))) 51 assert.NilError(t, err) 52 53 layerDigest := w.Digest() 54 w.Close() 55 56 img := ocispec.Image{ 57 Platform: platforms.DefaultSpec(), 58 RootFS: ocispec.RootFS{Type: "layers", DiffIDs: []digest.Digest{layerDigest}}, 59 Config: ocispec.ImageConfig{WorkingDir: "/"}, 60 } 61 imgJSON, err := json.Marshal(img) 62 assert.NilError(t, err) 63 64 w, err = store.Writer(ctx, content.WithRef("config")) 65 assert.NilError(t, err) 66 defer w.Close() 67 _, err = w.Write(imgJSON) 68 assert.NilError(t, err) 69 assert.NilError(t, w.Commit(ctx, int64(len(imgJSON)), digest.FromBytes(imgJSON))) 70 71 configDigest := w.Digest() 72 w.Close() 73 74 info, err := store.Info(ctx, layerDigest) 75 assert.NilError(t, err) 76 77 manifest := ocispec.Manifest{ 78 Versioned: specs.Versioned{ 79 SchemaVersion: 2, 80 }, 81 MediaType: images.MediaTypeDockerSchema2Manifest, 82 Config: ocispec.Descriptor{ 83 MediaType: images.MediaTypeDockerSchema2Config, 84 Digest: configDigest, 85 Size: int64(len(imgJSON)), 86 }, 87 Layers: []ocispec.Descriptor{{ 88 MediaType: images.MediaTypeDockerSchema2Layer, 89 Digest: layerDigest, 90 Size: info.Size, 91 }}, 92 } 93 94 manifestJSON, err := json.Marshal(manifest) 95 assert.NilError(t, err) 96 97 w, err = store.Writer(ctx, content.WithRef("manifest")) 98 assert.NilError(t, err) 99 defer w.Close() 100 _, err = w.Write(manifestJSON) 101 assert.NilError(t, err) 102 assert.NilError(t, w.Commit(ctx, int64(len(manifestJSON)), digest.FromBytes(manifestJSON))) 103 104 manifestDigest := w.Digest() 105 w.Close() 106 107 return ocispec.Descriptor{ 108 MediaType: images.MediaTypeDockerSchema2Manifest, 109 Digest: manifestDigest, 110 Size: int64(len(manifestJSON)), 111 } 112 } 113 114 // Make sure that pulling by an already cached digest but for a different ref (that should not have that digest) 115 // verifies with the remote that the digest exists in that repo. 116 func TestImagePullStoredfDigestForOtherRepo(t *testing.T) { 117 skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") 118 skip.If(t, testEnv.OSType == "windows", "We don't run a test registry on Windows") 119 skip.If(t, testEnv.IsRootless, "Rootless has a different view of localhost (needed for test registry access)") 120 defer setupTest(t)() 121 122 reg := registry.NewV2(t, registry.WithStdout(os.Stdout), registry.WithStderr(os.Stderr)) 123 defer reg.Close() 124 reg.WaitReady(t) 125 126 ctx := context.Background() 127 128 // First create an image and upload it to our local registry 129 // Then we'll download it so that we can make sure the content is available in dockerd's manifest cache. 130 // Then we'll try to pull the same digest but with a different repo name. 131 132 dir := t.TempDir() 133 store, err := local.NewStore(dir) 134 assert.NilError(t, err) 135 136 desc := createTestImage(ctx, t, store) 137 138 remote := path.Join(registry.DefaultURL, "test:latest") 139 140 c8dClient, err := containerd.New("", containerd.WithServices(containerd.WithContentStore(store))) 141 assert.NilError(t, err) 142 143 c8dClient.Push(ctx, remote, desc) 144 assert.NilError(t, err) 145 146 client := testEnv.APIClient() 147 rdr, err := client.ImagePull(ctx, remote, types.ImagePullOptions{}) 148 assert.NilError(t, err) 149 defer rdr.Close() 150 io.Copy(io.Discard, rdr) 151 152 // Now, pull a totally different repo with a the same digest 153 rdr, err = client.ImagePull(ctx, path.Join(registry.DefaultURL, "other:image@"+desc.Digest.String()), types.ImagePullOptions{}) 154 if rdr != nil { 155 rdr.Close() 156 } 157 assert.Assert(t, err != nil, "Expected error, got none: %v", err) 158 assert.Assert(t, errdefs.IsNotFound(err), err) 159 }