remove GetLayerByID from ImageService interface

Co-authored-by: Nicolas De Loof <nicolas.deloof@gmail.com>
Co-authored-by: Paweł Gronowski <pawel.gronowski@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Nicolas De Loof 2022-08-05 09:57:08 +02:00 committed by Sebastiaan van Stijn
parent a1f6a70522
commit 06619763a2
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
9 changed files with 68 additions and 50 deletions

View file

@ -25,7 +25,7 @@ type execBackend interface {
type copyBackend interface {
ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err 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
ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
}

View file

@ -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 {
return s.backend.ContainerExport(vars["name"], w)
return s.backend.ContainerExport(ctx, vars["name"], w)
}
type bodyOnStartError struct{}

View file

@ -9,8 +9,10 @@ import (
cerrdefs "github.com/containerd/containerd/errdefs"
containerdimages "github.com/containerd/containerd/images"
"github.com/containerd/containerd/images/archive"
"github.com/containerd/containerd/mount"
cplatforms "github.com/containerd/containerd/platforms"
"github.com/docker/distribution/reference"
"github.com/docker/docker/container"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/platforms"
"github.com/docker/docker/pkg/streamformatter"
@ -19,6 +21,15 @@ import (
"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
// exported images are archived into a tar when written to the output
// stream. All images with the given tag and all versions containing

View file

@ -75,12 +75,6 @@ func (i *ImageService) CreateLayer(container *container.Container, initFunc laye
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
// called from info.go
func (i *ImageService) LayerStoreStatus() [][2]string {

View file

@ -218,6 +218,11 @@ func (daemon *Daemon) RegistryHosts() docker.RegistryHosts {
return resolver.NewRegistryConfig(m)
}
// layerAccessor may be implemented by ImageService
type layerAccessor interface {
GetLayerByID(cid string) (layer.RWLayer, error)
}
func (daemon *Daemon) restore() error {
var mapLock sync.Mutex
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)
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{
"running": c.IsRunning(),
"paused": c.IsPaused(),

View file

@ -1,6 +1,7 @@
package daemon // import "github.com/docker/docker/daemon"
import (
"context"
"fmt"
"io"
@ -8,12 +9,11 @@ import (
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/pkg/ioutils"
)
// ContainerExport writes the contents of the container to the given
// 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)
if err != nil {
return err
@ -33,49 +33,31 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
return errdefs.Conflict(err)
}
data, err := daemon.containerExport(ctr)
err = daemon.containerExport(ctx, ctr, out)
if err != nil {
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
}
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 {
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
})
if err != nil {
return err
}
daemon.LogContainerEvent(container, "export")
return arch, err
return nil
}

View file

@ -30,6 +30,7 @@ type ImageService interface {
CreateImage(config []byte, parent string) (builder.Image, error)
ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, 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
Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
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)
CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error)
GetLayerByID(cid string) (layer.RWLayer, error)
LayerStoreStatus() [][2]string
GetLayerMountID(cid string) (string, error)
ReleaseLayer(rwlayer layer.RWLayer) error

View file

@ -4,7 +4,9 @@ import (
"context"
"io"
"github.com/docker/docker/container"
"github.com/docker/docker/image/tarexport"
"github.com/sirupsen/logrus"
)
// 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)
}
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
// complement of ExportImage. The input stream is an uncompressed tar
// ball containing images and metadata.

View file

@ -136,7 +136,7 @@ func (i *ImageService) CreateLayer(container *container.Container, initFunc laye
}
// 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) {
return i.layerStore.GetRWLayer(cid)
}
@ -169,7 +169,7 @@ func (i *ImageService) StorageDriver() string {
}
// 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 {
metaData, err := i.layerStore.ReleaseRWLayer(rwlayer)
layer.LogReleaseMetadata(metaData)