From 50fb999bb148ce4cd50c1a8952353a95c9751bff Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 11 Jul 2022 11:46:07 +0200 Subject: [PATCH] add image load/save support Signed-off-by: Nicolas De Loof --- api/server/router/image/backend.go | 4 +-- api/server/router/image/image_routes.go | 4 +-- daemon/containerd/image_exporter.go | 33 +++++++++++++++++++++---- daemon/image_service.go | 4 +-- daemon/images/image_exporter.go | 5 ++-- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/api/server/router/image/backend.go b/api/server/router/image/backend.go index ebddff686e..0534d2cf8d 100644 --- a/api/server/router/image/backend.go +++ b/api/server/router/image/backend.go @@ -30,9 +30,9 @@ type imageBackend interface { } type importExportBackend interface { - LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error + LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error ImportImage(src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error - ExportImage(names []string, outStream io.Writer) error + ExportImage(ctx context.Context, names []string, outStream io.Writer) error } type registryBackend interface { diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index fc397d4458..84d1a96f71 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -137,7 +137,7 @@ func (s *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r names = r.Form["names"] } - if err := s.backend.ExportImage(names, output); err != nil { + if err := s.backend.ExportImage(ctx, names, output); err != nil { if !output.Flushed() { return err } @@ -156,7 +156,7 @@ func (s *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter, output := ioutils.NewWriteFlusher(w) defer output.Close() - if err := s.backend.LoadImage(r.Body, output, quiet); err != nil { + if err := s.backend.LoadImage(ctx, r.Body, output, quiet); err != nil { _, _ = output.Write(streamformatter.FormatError(err)) } return nil diff --git a/daemon/containerd/image_exporter.go b/daemon/containerd/image_exporter.go index 6d7c81d64a..342a1385d3 100644 --- a/daemon/containerd/image_exporter.go +++ b/daemon/containerd/image_exporter.go @@ -1,19 +1,42 @@ package containerd -import "io" +import ( + "context" + "io" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/images/archive" + "github.com/containerd/containerd/platforms" + "github.com/docker/distribution/reference" +) // ExportImage exports a list of images to the given output stream. The // exported images are archived into a tar when written to the output // stream. All images with the given tag and all versions containing // the same tag are exported. names is the set of tags to export, and // outStream is the writer which the images are written to. -func (i *ImageService) ExportImage(names []string, outStream io.Writer) error { - panic("not implemented") +func (i *ImageService) ExportImage(ctx context.Context, names []string, outStream io.Writer) error { + opts := []archive.ExportOpt{ + archive.WithPlatform(platforms.Ordered(platforms.DefaultSpec())), + archive.WithSkipNonDistributableBlobs(), + } + is := i.client.ImageService() + for _, imageRef := range names { + named, err := reference.ParseDockerRef(imageRef) + if err != nil { + return err + } + opts = append(opts, archive.WithImage(is, named.String())) + } + return i.client.Export(ctx, outStream, opts...) } // LoadImage uploads a set of images into the repository. This is the // complement of ExportImage. The input stream is an uncompressed tar // ball containing images and metadata. -func (i *ImageService) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error { - panic("not implemented") +func (i *ImageService) LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error { + _, err := i.client.Import(ctx, inTar, + containerd.WithImportPlatform(platforms.DefaultStrict()), + ) + return err } diff --git a/daemon/image_service.go b/daemon/image_service.go index 2fe5eddc38..0db2afda3b 100644 --- a/daemon/image_service.go +++ b/daemon/image_service.go @@ -29,8 +29,8 @@ type ImageService interface { PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error CreateImage(config []byte, parent string) (builder.Image, error) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) - ExportImage(names []string, outStream io.Writer) error - LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error + ExportImage(ctx context.Context, names []string, outStream io.Writer) error + LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) LogImageEvent(imageID, refName, action string) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) diff --git a/daemon/images/image_exporter.go b/daemon/images/image_exporter.go index 037a694b45..2ab4af1a83 100644 --- a/daemon/images/image_exporter.go +++ b/daemon/images/image_exporter.go @@ -1,6 +1,7 @@ package images // import "github.com/docker/docker/daemon/images" import ( + "context" "io" "github.com/docker/docker/image/tarexport" @@ -11,7 +12,7 @@ import ( // stream. All images with the given tag and all versions containing // the same tag are exported. names is the set of tags to export, and // outStream is the writer which the images are written to. -func (i *ImageService) ExportImage(names []string, outStream io.Writer) error { +func (i *ImageService) ExportImage(ctx context.Context, names []string, outStream io.Writer) error { imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStore, i.referenceStore, i) return imageExporter.Save(names, outStream) } @@ -19,7 +20,7 @@ func (i *ImageService) ExportImage(names []string, outStream io.Writer) error { // LoadImage uploads a set of images into the repository. This is the // complement of ExportImage. The input stream is an uncompressed tar // ball containing images and metadata. -func (i *ImageService) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error { +func (i *ImageService) LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error { imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStore, i.referenceStore, i) return imageExporter.Load(inTar, outStream, quiet) }