github.com/lalkh/containerd@v1.4.3/image_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package containerd 18 19 import ( 20 "context" 21 "fmt" 22 "runtime" 23 "strings" 24 "testing" 25 26 "github.com/containerd/containerd/errdefs" 27 "github.com/containerd/containerd/images" 28 "github.com/containerd/containerd/platforms" 29 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 30 ) 31 32 func TestImageIsUnpacked(t *testing.T) { 33 if runtime.GOOS == "windows" { 34 t.Skip() 35 } 36 37 const imageName = "docker.io/library/busybox:latest" 38 ctx, cancel := testContext(t) 39 defer cancel() 40 41 client, err := newClient(t, address) 42 if err != nil { 43 t.Fatal(err) 44 } 45 defer client.Close() 46 47 // Cleanup 48 opts := []images.DeleteOpt{images.SynchronousDelete()} 49 err = client.ImageService().Delete(ctx, imageName, opts...) 50 if err != nil && !errdefs.IsNotFound(err) { 51 t.Fatal(err) 52 } 53 54 // By default pull does not unpack an image 55 image, err := client.Pull(ctx, imageName, WithPlatform("linux/amd64")) 56 if err != nil { 57 t.Fatal(err) 58 } 59 60 // Check that image is not unpacked 61 unpacked, err := image.IsUnpacked(ctx, DefaultSnapshotter) 62 if err != nil { 63 t.Fatal(err) 64 } 65 if unpacked { 66 t.Fatalf("image should not be unpacked") 67 } 68 69 // Check that image is unpacked 70 err = image.Unpack(ctx, DefaultSnapshotter) 71 if err != nil { 72 t.Fatal(err) 73 } 74 unpacked, err = image.IsUnpacked(ctx, DefaultSnapshotter) 75 if err != nil { 76 t.Fatal(err) 77 } 78 if !unpacked { 79 t.Fatalf("image should be unpacked") 80 } 81 } 82 83 func TestImagePullWithDistSourceLabel(t *testing.T) { 84 var ( 85 source = "docker.io" 86 repoName = "library/busybox" 87 tag = "latest" 88 ) 89 90 ctx, cancel := testContext(t) 91 defer cancel() 92 93 client, err := newClient(t, address) 94 if err != nil { 95 t.Fatal(err) 96 } 97 defer client.Close() 98 99 imageName := fmt.Sprintf("%s/%s:%s", source, repoName, tag) 100 pMatcher := platforms.Default() 101 102 // pull content without unpack and add distribution source label 103 image, err := client.Pull(ctx, imageName, WithPlatformMatcher(pMatcher)) 104 if err != nil { 105 t.Fatal(err) 106 } 107 defer client.ImageService().Delete(ctx, imageName) 108 109 cs := client.ContentStore() 110 key := fmt.Sprintf("containerd.io/distribution.source.%s", source) 111 112 // only check the target platform 113 childrenHandler := images.FilterPlatforms(images.ChildrenHandler(cs), pMatcher) 114 115 checkLabelHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { 116 children, err := childrenHandler(ctx, desc) 117 if err != nil { 118 return nil, err 119 } 120 121 info, err := cs.Info(ctx, desc.Digest) 122 if err != nil { 123 return nil, err 124 } 125 126 // check the label 127 if got := info.Labels[key]; !strings.Contains(got, repoName) { 128 return nil, fmt.Errorf("expected to have %s repo name in label, but got %s", repoName, got) 129 } 130 return children, nil 131 } 132 133 if err := images.Dispatch(ctx, images.HandlerFunc(checkLabelHandler), nil, image.Target()); err != nil { 134 t.Fatal(err) 135 } 136 } 137 138 func TestImageUsage(t *testing.T) { 139 if testing.Short() || runtime.GOOS == "windows" { 140 t.Skip() 141 } 142 143 imageName := "docker.io/library/busybox:latest" 144 ctx, cancel := testContext(t) 145 defer cancel() 146 147 client, err := newClient(t, address) 148 if err != nil { 149 t.Fatal(err) 150 } 151 defer client.Close() 152 153 // Cleanup 154 err = client.ImageService().Delete(ctx, imageName, images.SynchronousDelete()) 155 if err != nil && !errdefs.IsNotFound(err) { 156 t.Fatal(err) 157 } 158 159 testPlatform := platforms.Only(ocispec.Platform{ 160 OS: "linux", 161 Architecture: "amd64", 162 }) 163 164 // Pull single platform, do not unpack 165 image, err := client.Pull(ctx, imageName, WithPlatformMatcher(testPlatform)) 166 if err != nil { 167 t.Fatal(err) 168 } 169 170 s1, err := image.Usage(ctx, WithUsageManifestLimit(1)) 171 if err != nil { 172 t.Fatal(err) 173 } 174 175 if _, err := image.Usage(ctx, WithUsageManifestLimit(0), WithManifestUsage()); err == nil { 176 t.Fatal("expected NotFound with missing manifests") 177 } else if !errdefs.IsNotFound(err) { 178 t.Fatalf("unexpected error: %+v", err) 179 } 180 181 // Pin image name to specific version for future fetches 182 imageName = imageName + "@" + image.Target().Digest.String() 183 defer client.ImageService().Delete(ctx, imageName, images.SynchronousDelete()) 184 185 // Fetch single platforms, but all manifests pulled 186 if _, err := client.Fetch(ctx, imageName, WithPlatformMatcher(testPlatform), WithAllMetadata()); err != nil { 187 t.Fatal(err) 188 } 189 190 if s, err := image.Usage(ctx, WithUsageManifestLimit(1)); err != nil { 191 t.Fatal(err) 192 } else if s != s1 { 193 t.Fatalf("unexpected usage %d, expected %d", s, s1) 194 } 195 196 s2, err := image.Usage(ctx, WithUsageManifestLimit(0)) 197 if err != nil { 198 t.Fatal(err) 199 } 200 201 if s2 <= s1 { 202 t.Fatalf("Expected larger usage counting all manifests: %d <= %d", s2, s1) 203 } 204 205 s3, err := image.Usage(ctx, WithUsageManifestLimit(0), WithManifestUsage()) 206 if err != nil { 207 t.Fatal(err) 208 } 209 210 if s3 <= s2 { 211 t.Fatalf("Expected larger usage counting all manifest reported sizes: %d <= %d", s3, s2) 212 } 213 214 // Fetch everything 215 if _, err = client.Fetch(ctx, imageName); err != nil { 216 t.Fatal(err) 217 } 218 219 if s, err := image.Usage(ctx); err != nil { 220 t.Fatal(err) 221 } else if s != s3 { 222 t.Fatalf("Expected actual usage to equal manifest reported usage of %d: got %d", s3, s) 223 } 224 225 err = image.Unpack(ctx, DefaultSnapshotter) 226 if err != nil { 227 t.Fatal(err) 228 } 229 230 if s, err := image.Usage(ctx, WithSnapshotUsage()); err != nil { 231 t.Fatal(err) 232 } else if s <= s3 { 233 t.Fatalf("Expected actual usage with snapshots to be greater: %d <= %d", s, s3) 234 } 235 }