github.com/demonoid81/containerd@v1.3.4/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  	err = client.ImageService().Delete(ctx, imageName)
    49  	if err != nil && !errdefs.IsNotFound(err) {
    50  		t.Fatal(err)
    51  	}
    52  
    53  	// By default pull does not unpack an image
    54  	image, err := client.Pull(ctx, imageName, WithPlatform("linux/amd64"))
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  
    59  	// Check that image is not unpacked
    60  	unpacked, err := image.IsUnpacked(ctx, DefaultSnapshotter)
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	if unpacked {
    65  		t.Fatalf("image should not be unpacked")
    66  	}
    67  
    68  	// Check that image is unpacked
    69  	err = image.Unpack(ctx, DefaultSnapshotter)
    70  	if err != nil {
    71  		t.Fatal(err)
    72  	}
    73  	unpacked, err = image.IsUnpacked(ctx, DefaultSnapshotter)
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if !unpacked {
    78  		t.Fatalf("image should be unpacked")
    79  	}
    80  }
    81  
    82  func TestImagePullWithDistSourceLabel(t *testing.T) {
    83  	var (
    84  		source   = "docker.io"
    85  		repoName = "library/busybox"
    86  		tag      = "latest"
    87  	)
    88  
    89  	ctx, cancel := testContext(t)
    90  	defer cancel()
    91  
    92  	client, err := newClient(t, address)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  	defer client.Close()
    97  
    98  	imageName := fmt.Sprintf("%s/%s:%s", source, repoName, tag)
    99  	pMatcher := platforms.Default()
   100  
   101  	// pull content without unpack and add distribution source label
   102  	image, err := client.Pull(ctx, imageName, WithPlatformMatcher(pMatcher))
   103  	if err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	defer client.ImageService().Delete(ctx, imageName)
   107  
   108  	cs := client.ContentStore()
   109  	key := fmt.Sprintf("containerd.io/distribution.source.%s", source)
   110  
   111  	// only check the target platform
   112  	childrenHandler := images.FilterPlatforms(images.ChildrenHandler(cs), pMatcher)
   113  
   114  	checkLabelHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
   115  		children, err := childrenHandler(ctx, desc)
   116  		if err != nil {
   117  			return nil, err
   118  		}
   119  
   120  		info, err := cs.Info(ctx, desc.Digest)
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  
   125  		// check the label
   126  		if got := info.Labels[key]; !strings.Contains(got, repoName) {
   127  			return nil, fmt.Errorf("expected to have %s repo name in label, but got %s", repoName, got)
   128  		}
   129  		return children, nil
   130  	}
   131  
   132  	if err := images.Dispatch(ctx, images.HandlerFunc(checkLabelHandler), nil, image.Target()); err != nil {
   133  		t.Fatal(err)
   134  	}
   135  }
   136  
   137  func TestImageUsage(t *testing.T) {
   138  	if testing.Short() || runtime.GOOS == "windows" {
   139  		t.Skip()
   140  	}
   141  
   142  	imageName := "docker.io/library/busybox:latest"
   143  	ctx, cancel := testContext(t)
   144  	defer cancel()
   145  
   146  	client, err := newClient(t, address)
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	defer client.Close()
   151  
   152  	// Cleanup
   153  	err = client.ImageService().Delete(ctx, imageName)
   154  	if err != nil && !errdefs.IsNotFound(err) {
   155  		t.Fatal(err)
   156  	}
   157  
   158  	testPlatform := platforms.Only(ocispec.Platform{
   159  		OS:           "linux",
   160  		Architecture: "amd64",
   161  	})
   162  
   163  	// Pull single platform, do not unpack
   164  	image, err := client.Pull(ctx, imageName, WithPlatformMatcher(testPlatform))
   165  	if err != nil {
   166  		t.Fatal(err)
   167  	}
   168  
   169  	s1, err := image.Usage(ctx, WithUsageManifestLimit(1))
   170  	if err != nil {
   171  		t.Fatal(err)
   172  	}
   173  
   174  	if _, err := image.Usage(ctx, WithUsageManifestLimit(0), WithManifestUsage()); err == nil {
   175  		t.Fatal("expected NotFound with missing manifests")
   176  	} else if !errdefs.IsNotFound(err) {
   177  		t.Fatalf("unexpected error: %+v", err)
   178  	}
   179  
   180  	// Pin image name to specific version for future fetches
   181  	imageName = imageName + "@" + image.Target().Digest.String()
   182  
   183  	// Fetch single platforms, but all manifests pulled
   184  	if _, err := client.Fetch(ctx, imageName, WithPlatformMatcher(testPlatform), WithAllMetadata()); err != nil {
   185  		t.Fatal(err)
   186  	}
   187  
   188  	if s, err := image.Usage(ctx, WithUsageManifestLimit(1)); err != nil {
   189  		t.Fatal(err)
   190  	} else if s != s1 {
   191  		t.Fatalf("unexpected usage %d, expected %d", s, s1)
   192  	}
   193  
   194  	s2, err := image.Usage(ctx, WithUsageManifestLimit(0))
   195  	if err != nil {
   196  		t.Fatal(err)
   197  	}
   198  
   199  	if s2 <= s1 {
   200  		t.Fatalf("Expected larger usage counting all manifests: %d <= %d", s2, s1)
   201  	}
   202  
   203  	s3, err := image.Usage(ctx, WithUsageManifestLimit(0), WithManifestUsage())
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  
   208  	if s3 <= s2 {
   209  		t.Fatalf("Expected larger usage counting all manifest reported sizes: %d <= %d", s3, s2)
   210  	}
   211  
   212  	// Fetch everything
   213  	if _, err = client.Fetch(ctx, imageName); err != nil {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	if s, err := image.Usage(ctx); err != nil {
   218  		t.Fatal(err)
   219  	} else if s != s3 {
   220  		t.Fatalf("Expected actual usage to equal manifest reported usage of %d: got %d", s3, s)
   221  	}
   222  
   223  	err = image.Unpack(ctx, DefaultSnapshotter)
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  
   228  	if s, err := image.Usage(ctx, WithSnapshotUsage()); err != nil {
   229  		t.Fatal(err)
   230  	} else if s <= s3 {
   231  		t.Fatalf("Expected actual usage with snapshots to be greater: %d <= %d", s, s3)
   232  	}
   233  }