github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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 imagespec "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) imagespec.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 platform := platforms.DefaultSpec() 57 58 img := imagespec.Image{ 59 Architecture: platform.Architecture, 60 OS: platform.OS, 61 RootFS: imagespec.RootFS{Type: "layers", DiffIDs: []digest.Digest{layerDigest}}, 62 Config: imagespec.ImageConfig{WorkingDir: "/"}, 63 } 64 imgJSON, err := json.Marshal(img) 65 assert.NilError(t, err) 66 67 w, err = store.Writer(ctx, content.WithRef("config")) 68 assert.NilError(t, err) 69 defer w.Close() 70 _, err = w.Write(imgJSON) 71 assert.NilError(t, err) 72 assert.NilError(t, w.Commit(ctx, int64(len(imgJSON)), digest.FromBytes(imgJSON))) 73 74 configDigest := w.Digest() 75 w.Close() 76 77 info, err := store.Info(ctx, layerDigest) 78 assert.NilError(t, err) 79 80 manifest := imagespec.Manifest{ 81 Versioned: specs.Versioned{ 82 SchemaVersion: 2, 83 }, 84 MediaType: images.MediaTypeDockerSchema2Manifest, 85 Config: imagespec.Descriptor{ 86 MediaType: images.MediaTypeDockerSchema2Config, 87 Digest: configDigest, 88 Size: int64(len(imgJSON)), 89 }, 90 Layers: []imagespec.Descriptor{{ 91 MediaType: images.MediaTypeDockerSchema2Layer, 92 Digest: layerDigest, 93 Size: info.Size, 94 }}, 95 } 96 97 manifestJSON, err := json.Marshal(manifest) 98 assert.NilError(t, err) 99 100 w, err = store.Writer(ctx, content.WithRef("manifest")) 101 assert.NilError(t, err) 102 defer w.Close() 103 _, err = w.Write(manifestJSON) 104 assert.NilError(t, err) 105 assert.NilError(t, w.Commit(ctx, int64(len(manifestJSON)), digest.FromBytes(manifestJSON))) 106 107 manifestDigest := w.Digest() 108 w.Close() 109 110 return imagespec.Descriptor{ 111 MediaType: images.MediaTypeDockerSchema2Manifest, 112 Digest: manifestDigest, 113 Size: int64(len(manifestJSON)), 114 } 115 } 116 117 // Make sure that pulling by an already cached digest but for a different ref (that should not have that digest) 118 // verifies with the remote that the digest exists in that repo. 119 func TestImagePullStoredfDigestForOtherRepo(t *testing.T) { 120 skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") 121 skip.If(t, testEnv.OSType == "windows", "We don't run a test registry on Windows") 122 skip.If(t, testEnv.IsRootless, "Rootless has a different view of localhost (needed for test registry access)") 123 defer setupTest(t)() 124 125 reg := registry.NewV2(t, registry.WithStdout(os.Stdout), registry.WithStderr(os.Stderr)) 126 defer reg.Close() 127 reg.WaitReady(t) 128 129 ctx := context.Background() 130 131 // First create an image and upload it to our local registry 132 // Then we'll download it so that we can make sure the content is available in dockerd's manifest cache. 133 // Then we'll try to pull the same digest but with a different repo name. 134 135 dir := t.TempDir() 136 store, err := local.NewStore(dir) 137 assert.NilError(t, err) 138 139 desc := createTestImage(ctx, t, store) 140 141 remote := path.Join(registry.DefaultURL, "test:latest") 142 143 c8dClient, err := containerd.New("", containerd.WithServices(containerd.WithContentStore(store))) 144 assert.NilError(t, err) 145 146 c8dClient.Push(ctx, remote, desc) 147 assert.NilError(t, err) 148 149 client := testEnv.APIClient() 150 rdr, err := client.ImagePull(ctx, remote, types.ImagePullOptions{}) 151 assert.NilError(t, err) 152 defer rdr.Close() 153 io.Copy(io.Discard, rdr) 154 155 // Now, pull a totally different repo with a the same digest 156 rdr, err = client.ImagePull(ctx, path.Join(registry.DefaultURL, "other:image@"+desc.Digest.String()), types.ImagePullOptions{}) 157 if rdr != nil { 158 rdr.Close() 159 } 160 assert.Assert(t, err != nil, "Expected error, got none: %v", err) 161 assert.Assert(t, errdefs.IsNotFound(err), err) 162 }