github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/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  }