Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -1786,6 +1786,19 @@ func (p *DockerProvider) ListImages(ctx context.Context) ([]ImageInfo, error) {

// SaveImages exports a list of images as an uncompressed tar
func (p *DockerProvider) SaveImages(ctx context.Context, output string, images ...string) error {
return p.SaveImagesWithOpts(ctx, output, images)
}

// SaveImagesWithOpts exports a list of images as an uncompressed tar, passing options to the provider
func (p *DockerProvider) SaveImagesWithOpts(ctx context.Context, output string, images []string, opts ...SaveImageOption) error {
saveOpts := saveImageOptions{}

for _, opt := range opts {
if err := opt(&saveOpts); err != nil {
return fmt.Errorf("applying save image option: %w", err)
}
}

outputFile, err := os.Create(output)
if err != nil {
return fmt.Errorf("opening output file %w", err)
Expand All @@ -1794,7 +1807,7 @@ func (p *DockerProvider) SaveImages(ctx context.Context, output string, images .
_ = outputFile.Close()
}()

imageReader, err := p.client.ImageSave(ctx, images)
imageReader, err := p.client.ImageSave(ctx, images, saveOpts.dockerSaveOpts...)
if err != nil {
return fmt.Errorf("saving images %w", err)
}
Expand All @@ -1811,6 +1824,14 @@ func (p *DockerProvider) SaveImages(ctx context.Context, output string, images .
return nil
}

func SaveDockerImageWithPlatforms(platforms ...specs.Platform) SaveImageOption {
return func(opts *saveImageOptions) error {
opts.dockerSaveOpts = append(opts.dockerSaveOpts, client.ImageSaveWithPlatforms(platforms...))

return nil
}
}

// PullImage pulls image from registry
func (p *DockerProvider) PullImage(ctx context.Context, img string) error {
return p.attemptToPullImage(ctx, img, image.PullOptions{})
Expand Down
9 changes: 9 additions & 0 deletions image.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package testcontainers

import (
"context"

"github.com/docker/docker/client"
)

// ImageInfo represents summary information of an image
Expand All @@ -10,9 +12,16 @@ type ImageInfo struct {
Name string
}

type saveImageOptions struct {
dockerSaveOpts []client.ImageSaveOption
}

type SaveImageOption func(*saveImageOptions) error

// ImageProvider allows manipulating images
type ImageProvider interface {
ListImages(context.Context) ([]ImageInfo, error)
SaveImages(context.Context, string, ...string) error
SaveImagesWithOpts(context.Context, string, []string, ...SaveImageOption) error
PullImage(context.Context, string) error
}
42 changes: 40 additions & 2 deletions image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"path/filepath"
"testing"

"github.com/containerd/platforms"
"github.com/stretchr/testify/require"

"github.com/testcontainers/testcontainers-go/internal/core"
Expand All @@ -18,7 +19,8 @@ func TestImageList(t *testing.T) {
require.NoErrorf(t, err, "failed to get provider")

defer func() {
_ = provider.Close()
err = provider.Close()
require.NoError(t, err)
}()

req := ContainerRequest{
Expand Down Expand Up @@ -51,7 +53,8 @@ func TestSaveImages(t *testing.T) {
require.NoErrorf(t, err, "failed to get provider")

defer func() {
_ = provider.Close()
err = provider.Close()
require.NoError(t, err)
}()

req := ContainerRequest{
Expand All @@ -71,3 +74,38 @@ func TestSaveImages(t *testing.T) {

require.NotZerof(t, info.Size(), "output file is empty")
}

func TestSaveImagesWithOpts(t *testing.T) {
t.Setenv("DOCKER_HOST", core.MustExtractDockerHost(context.Background()))

provider, err := ProviderDocker.GetProvider()
require.NoErrorf(t, err, "failed to get provider")

defer func() {
err = provider.Close()
require.NoError(t, err)
}()

req := ContainerRequest{
Image: "redis:latest",
ImagePlatform: "linux/amd64",
}

p, err := platforms.ParseAll([]string{"linux/amd64"})
require.NoError(t, err)

ctr, err := provider.CreateContainer(context.Background(), req)
CleanupContainer(t, ctr)
require.NoErrorf(t, err, "creating test container")

output := filepath.Join(t.TempDir(), "images.tar")
err = provider.SaveImagesWithOpts(
context.Background(), output, []string{req.Image}, SaveDockerImageWithPlatforms(p...),
)
require.NoErrorf(t, err, "saving image %q", req.Image)

info, err := os.Stat(output)
require.NoError(t, err)

require.NotZerof(t, info.Size(), "output file is empty")
}
9 changes: 6 additions & 3 deletions modules/k3s/k3s.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,11 @@ func unmarshal(bytes []byte) (*KubeConfigValue, error) {
return &kubeConfig, nil
}

// LoadImages loads images into the k3s container.
func (c *K3sContainer) LoadImages(ctx context.Context, images ...string) error {
return c.LoadImagesWithOpts(ctx, images)
}

func (c *K3sContainer) LoadImagesWithOpts(ctx context.Context, images []string, opts ...testcontainers.SaveImageOption) error {
provider, err := testcontainers.ProviderDocker.GetProvider()
if err != nil {
return fmt.Errorf("getting docker provider %w", err)
Expand All @@ -210,7 +213,7 @@ func (c *K3sContainer) LoadImages(ctx context.Context, images ...string) error {
_ = os.Remove(imagesTar.Name())
}()

err = provider.SaveImages(context.Background(), imagesTar.Name(), images...)
err = provider.SaveImagesWithOpts(context.Background(), imagesTar.Name(), images, opts...)
if err != nil {
return fmt.Errorf("saving images %w", err)
}
Expand All @@ -221,7 +224,7 @@ func (c *K3sContainer) LoadImages(ctx context.Context, images ...string) error {
return fmt.Errorf("copying image to container %w", err)
}

_, _, err = c.Exec(ctx, []string{"ctr", "-n=k8s.io", "images", "import", containerPath})
_, _, err = c.Exec(ctx, []string{"ctr", "-n=k8s.io", "images", "import", "--all-platforms", containerPath})
if err != nil {
return fmt.Errorf("importing image %w", err)
}
Expand Down
Loading