Skip to content

Commit 7a7a9a2

Browse files
committed
integration: Adds test for multilayer image import
This test will make sure there aren't any issues with multilayered images during import. Keep in mind that in the case of multilayered images, they have to be unpacked first in order to be usable. Signed-off-by: Claudiu Belu <[email protected]>
1 parent 45e0e5a commit 7a7a9a2

3 files changed

Lines changed: 66 additions & 10 deletions

File tree

integration/client/client_unix_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ const (
3232
)
3333

3434
var (
35-
testImage = "ghcr.io/containerd/busybox:1.32"
36-
shortCommand = withProcessArgs("true")
37-
longCommand = withProcessArgs("/bin/sh", "-c", "while true; do sleep 1; done")
35+
testImage = "ghcr.io/containerd/busybox:1.32"
36+
testMultiLayeredImage = "gcr.io/k8s-cri-containerd/volume-copy-up:2.1"
37+
shortCommand = withProcessArgs("true")
38+
longCommand = withProcessArgs("/bin/sh", "-c", "while true; do sleep 1; done")
3839
)
3940

4041
func TestImagePullSchema1WithEmptyLayers(t *testing.T) {

integration/client/client_windows_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ const (
3030
)
3131

3232
var (
33-
defaultRoot = filepath.Join(os.Getenv("programfiles"), "containerd", "root-test")
34-
defaultState = filepath.Join(os.Getenv("programfiles"), "containerd", "state-test")
35-
testImage string
36-
shortCommand = withTrue()
37-
longCommand = withProcessArgs("ping", "-t", "localhost")
33+
defaultRoot = filepath.Join(os.Getenv("programfiles"), "containerd", "root-test")
34+
defaultState = filepath.Join(os.Getenv("programfiles"), "containerd", "state-test")
35+
testImage string
36+
testMultiLayeredImage = "gcr.io/k8s-cri-containerd/volume-copy-up:2.1"
37+
shortCommand = withTrue()
38+
longCommand = withProcessArgs("ping", "-t", "localhost")
3839
)
3940

4041
func init() {

integration/client/import_test.go

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,17 @@ import (
2727
"reflect"
2828
"runtime"
2929
"testing"
30+
"time"
3031

3132
. "github.com/containerd/containerd"
3233
"github.com/containerd/containerd/archive/compression"
3334
"github.com/containerd/containerd/archive/tartest"
3435
"github.com/containerd/containerd/images"
3536
"github.com/containerd/containerd/images/archive"
37+
"github.com/containerd/containerd/leases"
38+
"github.com/containerd/containerd/oci"
39+
"github.com/containerd/containerd/platforms"
40+
3641
digest "github.com/opencontainers/go-digest"
3742
specs "github.com/opencontainers/image-spec/specs-go"
3843
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -41,6 +46,18 @@ import (
4146
// TestExportAndImport exports testImage as a tar stream,
4247
// and import the tar stream as a new image.
4348
func TestExportAndImport(t *testing.T) {
49+
testExportImport(t, testImage)
50+
}
51+
52+
// TestExportAndImportMultiLayer exports testMultiLayeredImage as a tar stream,
53+
// and import the tar stream as a new image. This should ensure that imported
54+
// images remain sane, and that the Garbage Collector won't delete part of its
55+
// content.
56+
func TestExportAndImportMultiLayer(t *testing.T) {
57+
testExportImport(t, testMultiLayeredImage)
58+
}
59+
60+
func testExportImport(t *testing.T, imageName string) {
4461
if testing.Short() {
4562
t.Skip()
4663
}
@@ -53,17 +70,19 @@ func TestExportAndImport(t *testing.T) {
5370
}
5471
defer client.Close()
5572

56-
_, err = client.Fetch(ctx, testImage)
73+
_, err = client.Fetch(ctx, imageName)
5774
if err != nil {
5875
t.Fatal(err)
5976
}
6077

6178
wb := bytes.NewBuffer(nil)
62-
err = client.Export(ctx, wb, archive.WithAllPlatforms(), archive.WithImage(client.ImageService(), testImage))
79+
err = client.Export(ctx, wb, archive.WithPlatform(platforms.Default()), archive.WithImage(client.ImageService(), imageName))
6380
if err != nil {
6481
t.Fatal(err)
6582
}
6683

84+
client.ImageService().Delete(ctx, imageName)
85+
6786
opts := []ImportOpt{
6887
WithImageRefTranslator(archive.AddRefPrefix("foo/bar")),
6988
}
@@ -72,6 +91,41 @@ func TestExportAndImport(t *testing.T) {
7291
t.Fatalf("Import failed: %+v", err)
7392
}
7493

94+
// We need to unpack the image, especially if it's multilayered.
95+
for _, img := range imgrecs {
96+
image := NewImage(client, img)
97+
98+
// TODO: Show unpack status
99+
t.Logf("unpacking %s (%s)...", img.Name, img.Target.Digest)
100+
err = image.Unpack(ctx, "")
101+
if err != nil {
102+
t.Fatalf("Error while unpacking image: %+v", err)
103+
}
104+
t.Log("done")
105+
}
106+
107+
// we're triggering the Garbage Collector to do its job.
108+
ls := client.LeasesService()
109+
l, err := ls.Create(ctx, leases.WithRandomID(), leases.WithExpiration(time.Hour))
110+
if err != nil {
111+
t.Fatalf("Error while creating lease: %+v", err)
112+
}
113+
if err = ls.Delete(ctx, l, leases.SynchronousDelete); err != nil {
114+
t.Fatalf("Error while deleting lease: %+v", err)
115+
}
116+
117+
image, err := client.GetImage(ctx, imageName)
118+
if err != nil {
119+
t.Fatal(err)
120+
}
121+
122+
id := t.Name()
123+
container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image)))
124+
if err != nil {
125+
t.Fatalf("Error while creating container: %+v", err)
126+
}
127+
container.Delete(ctx, WithSnapshotCleanup)
128+
75129
for _, imgrec := range imgrecs {
76130
if imgrec.Name == testImage {
77131
continue

0 commit comments

Comments
 (0)