diff --git a/daemon/commit.go b/daemon/commit.go index 8865d832f3..6af494da74 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -1,9 +1,7 @@ package daemon // import "github.com/docker/docker/daemon" import ( - "encoding/json" "fmt" - "io" "runtime" "strings" "time" @@ -12,10 +10,6 @@ import ( containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/builder/dockerfile" "github.com/docker/docker/errdefs" - "github.com/docker/docker/image" - "github.com/docker/docker/layer" - "github.com/docker/docker/pkg/ioutils" - "github.com/docker/docker/pkg/system" "github.com/pkg/errors" ) @@ -190,115 +184,3 @@ func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateIma containerActions.WithValues("commit").UpdateSince(start) return id.String(), nil } - -func (daemon *Daemon) commitImage(c backend.CommitConfig) (image.ID, error) { - layerStore, ok := daemon.layerStores[c.ContainerOS] - if !ok { - return "", system.ErrNotSupportedOperatingSystem - } - rwTar, err := exportContainerRw(layerStore, c.ContainerID, c.ContainerMountLabel) - if err != nil { - return "", err - } - defer func() { - if rwTar != nil { - rwTar.Close() - } - }() - - var parent *image.Image - if c.ParentImageID == "" { - parent = new(image.Image) - parent.RootFS = image.NewRootFS() - } else { - parent, err = daemon.imageStore.Get(image.ID(c.ParentImageID)) - if err != nil { - return "", err - } - } - - l, err := layerStore.Register(rwTar, parent.RootFS.ChainID()) - if err != nil { - return "", err - } - defer layer.ReleaseAndLog(layerStore, l) - - cc := image.ChildConfig{ - ContainerID: c.ContainerID, - Author: c.Author, - Comment: c.Comment, - ContainerConfig: c.ContainerConfig, - Config: c.Config, - DiffID: l.DiffID(), - } - config, err := json.Marshal(image.NewChildImage(parent, cc, c.ContainerOS)) - if err != nil { - return "", err - } - - id, err := daemon.imageStore.Create(config) - if err != nil { - return "", err - } - - if c.ParentImageID != "" { - if err := daemon.imageStore.SetParent(id, image.ID(c.ParentImageID)); err != nil { - return "", err - } - } - return id, nil -} - -func exportContainerRw(layerStore layer.Store, id, mountLabel string) (arch io.ReadCloser, err error) { - rwlayer, err := layerStore.GetRWLayer(id) - if err != nil { - return nil, err - } - defer func() { - if err != nil { - layerStore.ReleaseRWLayer(rwlayer) - } - }() - - // TODO: this mount call is not necessary as we assume that TarStream() should - // mount the layer if needed. But the Diff() function for windows requests that - // the layer should be mounted when calling it. So we reserve this mount call - // until windows driver can implement Diff() interface correctly. - _, err = rwlayer.Mount(mountLabel) - if err != nil { - return nil, err - } - - archive, err := rwlayer.TarStream() - if err != nil { - rwlayer.Unmount() - return nil, err - } - return ioutils.NewReadCloserWrapper(archive, func() error { - archive.Close() - err = rwlayer.Unmount() - layerStore.ReleaseRWLayer(rwlayer) - return err - }), - nil -} - -// CommitBuildStep is used by the builder to create an image for each step in -// the build. -// -// This method is different from CreateImageFromContainer: -// * it doesn't attempt to validate container state -// * it doesn't send a commit action to metrics -// * it doesn't log a container commit event -// -// This is a temporary shim. Should be removed when builder stops using commit. -func (daemon *Daemon) CommitBuildStep(c backend.CommitConfig) (image.ID, error) { - container, err := daemon.GetContainer(c.ContainerID) - if err != nil { - return "", err - } - c.ContainerMountLabel = container.MountLabel - c.ContainerOS = container.OS - c.ParentImageID = string(container.ImageID) - return daemon.commitImage(c) -} diff --git a/daemon/image_commit.go b/daemon/image_commit.go new file mode 100644 index 0000000000..48f890b80d --- /dev/null +++ b/daemon/image_commit.go @@ -0,0 +1,124 @@ +package daemon // import "github.com/docker/docker/daemon" + +import ( + "encoding/json" + "io" + + "github.com/docker/docker/api/types/backend" + "github.com/docker/docker/image" + "github.com/docker/docker/layer" + "github.com/docker/docker/pkg/ioutils" + "github.com/docker/docker/pkg/system" +) + +func (daemon *Daemon) commitImage(c backend.CommitConfig) (image.ID, error) { + layerStore, ok := daemon.layerStores[c.ContainerOS] + if !ok { + return "", system.ErrNotSupportedOperatingSystem + } + rwTar, err := exportContainerRw(layerStore, c.ContainerID, c.ContainerMountLabel) + if err != nil { + return "", err + } + defer func() { + if rwTar != nil { + rwTar.Close() + } + }() + + var parent *image.Image + if c.ParentImageID == "" { + parent = new(image.Image) + parent.RootFS = image.NewRootFS() + } else { + parent, err = daemon.imageStore.Get(image.ID(c.ParentImageID)) + if err != nil { + return "", err + } + } + + l, err := layerStore.Register(rwTar, parent.RootFS.ChainID()) + if err != nil { + return "", err + } + defer layer.ReleaseAndLog(layerStore, l) + + cc := image.ChildConfig{ + ContainerID: c.ContainerID, + Author: c.Author, + Comment: c.Comment, + ContainerConfig: c.ContainerConfig, + Config: c.Config, + DiffID: l.DiffID(), + } + config, err := json.Marshal(image.NewChildImage(parent, cc, c.ContainerOS)) + if err != nil { + return "", err + } + + id, err := daemon.imageStore.Create(config) + if err != nil { + return "", err + } + + if c.ParentImageID != "" { + if err := daemon.imageStore.SetParent(id, image.ID(c.ParentImageID)); err != nil { + return "", err + } + } + return id, nil +} + +func exportContainerRw(layerStore layer.Store, id, mountLabel string) (arch io.ReadCloser, err error) { + rwlayer, err := layerStore.GetRWLayer(id) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + layerStore.ReleaseRWLayer(rwlayer) + } + }() + + // TODO: this mount call is not necessary as we assume that TarStream() should + // mount the layer if needed. But the Diff() function for windows requests that + // the layer should be mounted when calling it. So we reserve this mount call + // until windows driver can implement Diff() interface correctly. + _, err = rwlayer.Mount(mountLabel) + if err != nil { + return nil, err + } + + archive, err := rwlayer.TarStream() + if err != nil { + rwlayer.Unmount() + return nil, err + } + return ioutils.NewReadCloserWrapper(archive, func() error { + archive.Close() + err = rwlayer.Unmount() + layerStore.ReleaseRWLayer(rwlayer) + return err + }), + nil +} + +// CommitBuildStep is used by the builder to create an image for each step in +// the build. +// +// This method is different from CreateImageFromContainer: +// * it doesn't attempt to validate container state +// * it doesn't send a commit action to metrics +// * it doesn't log a container commit event +// +// This is a temporary shim. Should be removed when builder stops using commit. +func (daemon *Daemon) CommitBuildStep(c backend.CommitConfig) (image.ID, error) { + container, err := daemon.GetContainer(c.ContainerID) + if err != nil { + return "", err + } + c.ContainerMountLabel = container.MountLabel + c.ContainerOS = container.OS + c.ParentImageID = string(container.ImageID) + return daemon.commitImage(c) +}