فهرست منبع

Merge pull request #45116 from thaJeztah/c8d_GetLayerByID

remove GetLayerByID from ImageService interface
Sebastiaan van Stijn 2 سال پیش
والد
کامیت
2fa66cfce2

+ 1 - 1
api/server/router/container/backend.go

@@ -25,7 +25,7 @@ type execBackend interface {
 type copyBackend interface {
 type copyBackend interface {
 	ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
 	ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
 	ContainerCopy(name string, res string) (io.ReadCloser, error)
 	ContainerCopy(name string, res string) (io.ReadCloser, error)
-	ContainerExport(name string, out io.Writer) error
+	ContainerExport(ctx context.Context, name string, out io.Writer) error
 	ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error
 	ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error
 	ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
 	ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
 }
 }

+ 1 - 1
api/server/router/container/container_routes.go

@@ -174,7 +174,7 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
 }
 }
 
 
 func (s *containerRouter) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 func (s *containerRouter) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	return s.backend.ContainerExport(vars["name"], w)
+	return s.backend.ContainerExport(ctx, vars["name"], w)
 }
 }
 
 
 type bodyOnStartError struct{}
 type bodyOnStartError struct{}

+ 11 - 0
daemon/containerd/image_exporter.go

@@ -9,8 +9,10 @@ import (
 	cerrdefs "github.com/containerd/containerd/errdefs"
 	cerrdefs "github.com/containerd/containerd/errdefs"
 	containerdimages "github.com/containerd/containerd/images"
 	containerdimages "github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/images/archive"
 	"github.com/containerd/containerd/images/archive"
+	"github.com/containerd/containerd/mount"
 	cplatforms "github.com/containerd/containerd/platforms"
 	cplatforms "github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/pkg/platforms"
 	"github.com/docker/docker/pkg/platforms"
 	"github.com/docker/docker/pkg/streamformatter"
 	"github.com/docker/docker/pkg/streamformatter"
@@ -19,6 +21,15 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
 
 
+func (i *ImageService) PerformWithBaseFS(ctx context.Context, c *container.Container, fn func(root string) error) error {
+	snapshotter := i.client.SnapshotService(i.snapshotter)
+	mounts, err := snapshotter.Mounts(ctx, c.ID)
+	if err != nil {
+		return err
+	}
+	return mount.WithTempMount(ctx, mounts, fn)
+}
+
 // ExportImage exports a list of images to the given output stream. The
 // ExportImage exports a list of images to the given output stream. The
 // exported images are archived into a tar when written to the output
 // exported images are archived into a tar when written to the output
 // stream. All images with the given tag and all versions containing
 // stream. All images with the given tag and all versions containing

+ 0 - 6
daemon/containerd/service.go

@@ -75,12 +75,6 @@ func (i *ImageService) CreateLayer(container *container.Container, initFunc laye
 	return nil, errdefs.NotImplemented(errdefs.NotImplemented(errors.New("not implemented")))
 	return nil, errdefs.NotImplemented(errdefs.NotImplemented(errors.New("not implemented")))
 }
 }
 
 
-// GetLayerByID returns a layer by ID
-// called from daemon.go Daemon.restore(), and Daemon.containerExport().
-func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
-	return nil, errdefs.NotImplemented(errors.New("not implemented"))
-}
-
 // LayerStoreStatus returns the status for each layer store
 // LayerStoreStatus returns the status for each layer store
 // called from info.go
 // called from info.go
 func (i *ImageService) LayerStoreStatus() [][2]string {
 func (i *ImageService) LayerStoreStatus() [][2]string {

+ 12 - 5
daemon/daemon.go

@@ -218,6 +218,11 @@ func (daemon *Daemon) RegistryHosts() docker.RegistryHosts {
 	return resolver.NewRegistryConfig(m)
 	return resolver.NewRegistryConfig(m)
 }
 }
 
 
+// layerAccessor may be implemented by ImageService
+type layerAccessor interface {
+	GetLayerByID(cid string) (layer.RWLayer, error)
+}
+
 func (daemon *Daemon) restore() error {
 func (daemon *Daemon) restore() error {
 	var mapLock sync.Mutex
 	var mapLock sync.Mutex
 	containers := make(map[string]*container.Container)
 	containers := make(map[string]*container.Container)
@@ -259,12 +264,14 @@ func (daemon *Daemon) restore() error {
 				log.Debugf("not restoring container because it was created with another storage driver (%s)", c.Driver)
 				log.Debugf("not restoring container because it was created with another storage driver (%s)", c.Driver)
 				return
 				return
 			}
 			}
-			rwlayer, err := daemon.imageService.GetLayerByID(c.ID)
-			if err != nil {
-				log.WithError(err).Error("failed to load container mount")
-				return
+			if accessor, ok := daemon.imageService.(layerAccessor); ok {
+				rwlayer, err := accessor.GetLayerByID(c.ID)
+				if err != nil {
+					log.WithError(err).Error("failed to load container mount")
+					return
+				}
+				c.RWLayer = rwlayer
 			}
 			}
-			c.RWLayer = rwlayer
 			log.WithFields(logrus.Fields{
 			log.WithFields(logrus.Fields{
 				"running": c.IsRunning(),
 				"running": c.IsRunning(),
 				"paused":  c.IsPaused(),
 				"paused":  c.IsPaused(),

+ 16 - 34
daemon/export.go

@@ -1,6 +1,7 @@
 package daemon // import "github.com/docker/docker/daemon"
 package daemon // import "github.com/docker/docker/daemon"
 
 
 import (
 import (
+	"context"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 
 
@@ -8,12 +9,11 @@ import (
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/chrootarchive"
-	"github.com/docker/docker/pkg/ioutils"
 )
 )
 
 
 // ContainerExport writes the contents of the container to the given
 // ContainerExport writes the contents of the container to the given
 // writer. An error is returned if the container cannot be found.
 // writer. An error is returned if the container cannot be found.
-func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
+func (daemon *Daemon) ContainerExport(ctx context.Context, name string, out io.Writer) error {
 	ctr, err := daemon.GetContainer(name)
 	ctr, err := daemon.GetContainer(name)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -33,49 +33,31 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
 		return errdefs.Conflict(err)
 		return errdefs.Conflict(err)
 	}
 	}
 
 
-	data, err := daemon.containerExport(ctr)
+	err = daemon.containerExport(ctx, ctr, out)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("Error exporting container %s: %v", name, err)
 		return fmt.Errorf("Error exporting container %s: %v", name, err)
 	}
 	}
-	defer data.Close()
 
 
-	// Stream the entire contents of the container (basically a volatile snapshot)
-	if _, err := io.Copy(out, data); err != nil {
-		return fmt.Errorf("Error exporting container %s: %v", name, err)
-	}
 	return nil
 	return nil
 }
 }
 
 
-func (daemon *Daemon) containerExport(container *container.Container) (arch io.ReadCloser, err error) {
-	rwlayer, err := daemon.imageService.GetLayerByID(container.ID)
-	if err != nil {
-		return nil, err
-	}
-	defer func() {
+func (daemon *Daemon) containerExport(ctx context.Context, container *container.Container, out io.Writer) error {
+	err := daemon.imageService.PerformWithBaseFS(ctx, container, func(basefs string) error {
+		archv, err := chrootarchive.Tar(basefs, &archive.TarOptions{
+			Compression: archive.Uncompressed,
+			IDMap:       daemon.idMapping,
+		}, basefs)
 		if err != nil {
 		if err != nil {
-			daemon.imageService.ReleaseLayer(rwlayer)
+			return err
 		}
 		}
-	}()
-
-	basefs, err := rwlayer.Mount(container.GetMountLabel())
-	if err != nil {
-		return nil, err
-	}
 
 
-	archv, err := chrootarchive.Tar(basefs, &archive.TarOptions{
-		Compression: archive.Uncompressed,
-		IDMap:       daemon.idMapping,
-	}, basefs)
-	if err != nil {
-		rwlayer.Unmount()
-		return nil, err
-	}
-	arch = ioutils.NewReadCloserWrapper(archv, func() error {
-		err := archv.Close()
-		rwlayer.Unmount()
-		daemon.imageService.ReleaseLayer(rwlayer)
+		// Stream the entire contents of the container (basically a volatile snapshot)
+		_, err = io.Copy(out, archv)
 		return err
 		return err
 	})
 	})
+	if err != nil {
+		return err
+	}
 	daemon.LogContainerEvent(container, "export")
 	daemon.LogContainerEvent(container, "export")
-	return arch, err
+	return nil
 }
 }

+ 1 - 1
daemon/image_service.go

@@ -30,6 +30,7 @@ type ImageService interface {
 	CreateImage(config []byte, parent string) (builder.Image, error)
 	CreateImage(config []byte, parent string) (builder.Image, error)
 	ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
 	ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
 	ExportImage(ctx context.Context, names []string, outStream io.Writer) error
 	ExportImage(ctx context.Context, names []string, outStream io.Writer) error
+	PerformWithBaseFS(ctx context.Context, c *container.Container, fn func(string) error) error
 	LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error
 	LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error
 	Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
 	Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
 	LogImageEvent(imageID, refName, action string)
 	LogImageEvent(imageID, refName, action string)
@@ -52,7 +53,6 @@ type ImageService interface {
 
 
 	GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error)
 	GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error)
 	CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error)
 	CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error)
-	GetLayerByID(cid string) (layer.RWLayer, error)
 	LayerStoreStatus() [][2]string
 	LayerStoreStatus() [][2]string
 	GetLayerMountID(cid string) (string, error)
 	GetLayerMountID(cid string) (string, error)
 	ReleaseLayer(rwlayer layer.RWLayer) error
 	ReleaseLayer(rwlayer layer.RWLayer) error

+ 24 - 0
daemon/images/image_exporter.go

@@ -4,7 +4,9 @@ import (
 	"context"
 	"context"
 	"io"
 	"io"
 
 
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/image/tarexport"
 	"github.com/docker/docker/image/tarexport"
+	"github.com/sirupsen/logrus"
 )
 )
 
 
 // ExportImage exports a list of images to the given output stream. The
 // ExportImage exports a list of images to the given output stream. The
@@ -17,6 +19,28 @@ func (i *ImageService) ExportImage(ctx context.Context, names []string, outStrea
 	return imageExporter.Save(names, outStream)
 	return imageExporter.Save(names, outStream)
 }
 }
 
 
+func (i *ImageService) PerformWithBaseFS(ctx context.Context, c *container.Container, fn func(root string) error) error {
+	rwlayer, err := i.layerStore.GetRWLayer(c.ID)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			err2 := i.ReleaseLayer(rwlayer)
+			if err2 != nil {
+				logrus.WithError(err2).WithField("container", c.ID).Warn("Failed to release layer")
+			}
+		}
+	}()
+
+	basefs, err := rwlayer.Mount(c.GetMountLabel())
+	if err != nil {
+		return err
+	}
+
+	return fn(basefs)
+}
+
 // LoadImage uploads a set of images into the repository. This is the
 // LoadImage uploads a set of images into the repository. This is the
 // complement of ExportImage.  The input stream is an uncompressed tar
 // complement of ExportImage.  The input stream is an uncompressed tar
 // ball containing images and metadata.
 // ball containing images and metadata.

+ 2 - 2
daemon/images/service.go

@@ -136,7 +136,7 @@ func (i *ImageService) CreateLayer(container *container.Container, initFunc laye
 }
 }
 
 
 // GetLayerByID returns a layer by ID
 // GetLayerByID returns a layer by ID
-// called from daemon.go Daemon.restore(), and Daemon.containerExport().
+// called from daemon.go Daemon.restore().
 func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
 func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
 	return i.layerStore.GetRWLayer(cid)
 	return i.layerStore.GetRWLayer(cid)
 }
 }
@@ -169,7 +169,7 @@ func (i *ImageService) StorageDriver() string {
 }
 }
 
 
 // ReleaseLayer releases a layer allowing it to be removed
 // ReleaseLayer releases a layer allowing it to be removed
-// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
+// called from delete.go Daemon.cleanupContainer().
 func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
 func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
 	metaData, err := i.layerStore.ReleaseRWLayer(rwlayer)
 	metaData, err := i.layerStore.ReleaseRWLayer(rwlayer)
 	layer.LogReleaseMetadata(metaData)
 	layer.LogReleaseMetadata(metaData)