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

@@ -22,11 +22,15 @@ import (
"io"
"os"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/images/archive"
"github.com/containerd/containerd/platforms"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/urfave/cli"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/images/archive"
"github.com/containerd/containerd/pkg/transfer"
tarchive "github.com/containerd/containerd/pkg/transfer/archive"
"github.com/containerd/containerd/pkg/transfer/image"
"github.com/containerd/containerd/platforms"
)
var exportCommand = cli.Command{
@@ -58,6 +62,10 @@ When '--all-platforms' is given all images in a manifest list must be available.
Name: "all-platforms",
Usage: "Exports content from all platforms",
},
cli.BoolTFlag{
Name: "local",
Usage: "run export locally rather than through transfer API",
},
},
Action: func(context *cli.Context) error {
var (
@@ -69,6 +77,56 @@ When '--all-platforms' is given all images in a manifest list must be available.
return errors.New("please provide both an output filename and an image reference to export")
}
client, ctx, cancel, err := commands.NewClient(context)
if err != nil {
return err
}
defer cancel()
var w io.WriteCloser
if out == "-" {
w = os.Stdout
} else {
w, err = os.Create(out)
if err != nil {
return err
}
}
defer w.Close()
if !context.BoolT("local") {
pf, done := ProgressHandler(ctx, os.Stdout)
defer done()
var specified []ocispec.Platform
if pss := context.StringSlice("platform"); len(pss) > 0 {
for _, ps := range pss {
p, err := platforms.Parse(ps)
if err != nil {
return fmt.Errorf("invalid platform %q: %w", ps, err)
}
specified = append(specified, p)
}
}
err := client.Transfer(ctx,
image.NewStore(""), // a dummy image store
tarchive.NewImageExportStream(w, "", tarchive.ExportOptions{
Images: images,
Platforms: specified,
AllPlatforms: context.Bool("all-platforms"),
SkipNonDistributable: context.Bool("skip-non-distributable"),
SkipDockerManifest: context.Bool("skip-manifest-json"),
}),
transfer.WithProgress(pf),
)
if err != nil {
return err
}
return nil
}
if pss := context.StringSlice("platform"); len(pss) > 0 {
var all []ocispec.Platform
for _, ps := range pss {
@@ -95,28 +153,11 @@ When '--all-platforms' is given all images in a manifest list must be available.
exportOpts = append(exportOpts, archive.WithSkipNonDistributableBlobs())
}
client, ctx, cancel, err := commands.NewClient(context)
if err != nil {
return err
}
defer cancel()
is := client.ImageService()
for _, img := range images {
exportOpts = append(exportOpts, archive.WithImage(is, img))
}
var w io.WriteCloser
if out == "-" {
w = os.Stdout
} else {
w, err = os.Create(out)
if err != nil {
return err
}
}
defer w.Close()
return client.Export(ctx, w, exportOpts...)
},
}