feat: export images using Transfer api

Signed-off-by: Jian Zeng <anonymousknight96@gmail.com>
This commit is contained in:
Jian Zeng
2023-01-04 16:52:30 +08:00
committed by Derek McGowan
parent b9d7eae1ad
commit f6491b0049
5 changed files with 198 additions and 26 deletions

View File

@@ -20,12 +20,19 @@ import (
"context"
"io"
"github.com/containerd/typeurl/v2"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/containerd/containerd/api/types"
transfertypes "github.com/containerd/containerd/api/types/transfer"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/images/archive"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/pkg/streaming"
"github.com/containerd/containerd/pkg/transfer/plugins"
tstreaming "github.com/containerd/containerd/pkg/transfer/streaming"
"github.com/containerd/typeurl/v2"
"github.com/containerd/containerd/platforms"
)
func init() {
@@ -34,24 +41,65 @@ func init() {
plugins.Register(&transfertypes.ImageImportStream{}, &ImageImportStream{})
}
// NewImageExportStream returns a image importer via tar stream
// TODO: Add export options
func NewImageExportStream(stream io.WriteCloser, mediaType string) *ImageExportStream {
type ExportOptions struct {
Images []string
Platforms []v1.Platform
AllPlatforms bool
SkipDockerManifest bool
SkipNonDistributable bool
}
// NewImageExportStream returns an image exporter via tar stream
func NewImageExportStream(stream io.WriteCloser, mediaType string, opts ExportOptions) *ImageExportStream {
return &ImageExportStream{
stream: stream,
mediaType: mediaType,
images: opts.Images,
platforms: opts.Platforms,
allPlatforms: opts.AllPlatforms,
skipDockerManifest: opts.SkipDockerManifest,
skipNonDistributable: opts.SkipNonDistributable,
}
}
type ImageExportStream struct {
stream io.WriteCloser
mediaType string
images []string
platforms []v1.Platform
allPlatforms bool
skipDockerManifest bool
skipNonDistributable bool
}
func (iis *ImageExportStream) ExportStream(context.Context) (io.WriteCloser, string, error) {
return iis.stream, iis.mediaType, nil
}
func (iis *ImageExportStream) Export(ctx context.Context, is images.Store, cs content.Store) error {
var opts []archive.ExportOpt
for _, img := range iis.images {
opts = append(opts, archive.WithImage(is, img))
}
if len(iis.platforms) > 0 {
opts = append(opts, archive.WithPlatform(platforms.Ordered(iis.platforms...)))
} else {
opts = append(opts, archive.WithPlatform(platforms.DefaultStrict()))
}
if iis.allPlatforms {
opts = append(opts, archive.WithAllPlatforms())
}
if iis.skipDockerManifest {
opts = append(opts, archive.WithSkipDockerManifest())
}
if iis.skipNonDistributable {
opts = append(opts, archive.WithSkipNonDistributableBlobs())
}
return archive.Export(ctx, cs, iis.stream, opts...)
}
func (iis *ImageExportStream) MarshalAny(ctx context.Context, sm streaming.StreamCreator) (typeurl.Any, error) {
sid := tstreaming.GenerateID("export")
stream, err := sm.Create(ctx, sid)
@@ -67,9 +115,22 @@ func (iis *ImageExportStream) MarshalAny(ctx context.Context, sm streaming.Strea
iis.stream.Close()
}()
var specified []*types.Platform
for _, p := range iis.platforms {
specified = append(specified, &types.Platform{
OS: p.OS,
Architecture: p.Architecture,
Variant: p.Variant,
})
}
s := &transfertypes.ImageExportStream{
Stream: sid,
MediaType: iis.mediaType,
Stream: sid,
MediaType: iis.mediaType,
Images: iis.images,
Platforms: specified,
AllPlatforms: iis.allPlatforms,
SkipDockerManifest: iis.skipDockerManifest,
SkipNonDistributable: iis.skipNonDistributable,
}
return typeurl.MarshalAny(s)
@@ -87,8 +148,22 @@ func (iis *ImageExportStream) UnmarshalAny(ctx context.Context, sm streaming.Str
return err
}
var specified []v1.Platform
for _, p := range s.Platforms {
specified = append(specified, v1.Platform{
OS: p.OS,
Architecture: p.Architecture,
Variant: p.Variant,
})
}
iis.stream = tstreaming.WriteByteStream(ctx, stream)
iis.mediaType = s.MediaType
iis.images = s.Images
iis.platforms = specified
iis.allPlatforms = s.AllPlatforms
iis.skipDockerManifest = s.SkipDockerManifest
iis.skipNonDistributable = s.SkipNonDistributable
return nil
}