diff --git a/components/engine/graph/graph.go b/components/engine/graph/graph.go index 10da49a722..be911b0482 100644 --- a/components/engine/graph/graph.go +++ b/components/engine/graph/graph.go @@ -28,6 +28,8 @@ import ( "github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/truncindex" "github.com/docker/docker/runconfig" + "github.com/vbatts/tar-split/tar/asm" + "github.com/vbatts/tar-split/tar/storage" ) // The type is used to protect pulling or building related image @@ -530,3 +532,80 @@ func (graph *Graph) RawJSON(id string) ([]byte, error) { func jsonPath(root string) string { return filepath.Join(root, jsonFileName) } + +func (graph *Graph) disassembleAndApplyTarLayer(img *image.Image, layerData archive.ArchiveReader, root string) error { + // this is saving the tar-split metadata + mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600)) + if err != nil { + return err + } + mfz := gzip.NewWriter(mf) + metaPacker := storage.NewJSONPacker(mfz) + defer mf.Close() + defer mfz.Close() + + inflatedLayerData, err := archive.DecompressStream(layerData) + if err != nil { + return err + } + + // we're passing nil here for the file putter, because the ApplyDiff will + // handle the extraction of the archive + rdr, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil) + if err != nil { + return err + } + + if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, archive.ArchiveReader(rdr)); err != nil { + return err + } + + return nil +} + +func (graph *Graph) assembleTarLayer(img *image.Image) (archive.Archive, error) { + root := graph.imageRoot(img.ID) + mFileName := filepath.Join(root, tarDataFileName) + mf, err := os.Open(mFileName) + if err != nil { + if !os.IsNotExist(err) { + logrus.Errorf("failed to open %q: %s", mFileName, err) + } + return nil, err + } + pR, pW := io.Pipe() + // this will need to be in a goroutine, as we are returning the stream of a + // tar archive, but can not close the metadata reader early (when this + // function returns)... + go func() { + defer mf.Close() + // let's reassemble! + logrus.Debugf("[graph] TarLayer with reassembly: %s", img.ID) + mfz, err := gzip.NewReader(mf) + if err != nil { + pW.CloseWithError(fmt.Errorf("[graph] error with %s: %s", mFileName, err)) + return + } + defer mfz.Close() + + // get our relative path to the container + fsLayer, err := graph.driver.Get(img.ID, "") + if err != nil { + pW.CloseWithError(err) + return + } + defer graph.driver.Put(img.ID) + + metaUnpacker := storage.NewJSONUnpacker(mfz) + fileGetter := storage.NewPathFileGetter(fsLayer) + logrus.Debugf("[graph] %s is at %q", img.ID, fsLayer) + ots := asm.NewOutputTarStream(fileGetter, metaUnpacker) + defer ots.Close() + if _, err := io.Copy(pW, ots); err != nil { + pW.CloseWithError(err) + return + } + pW.Close() + }() + return pR, nil +} diff --git a/components/engine/graph/graph_unix.go b/components/engine/graph/graph_unix.go index e9a7f76416..351a84ccad 100644 --- a/components/engine/graph/graph_unix.go +++ b/components/engine/graph/graph_unix.go @@ -3,10 +3,8 @@ package graph import ( - "compress/gzip" "encoding/json" "fmt" - "io" "os" "path/filepath" "strings" @@ -16,8 +14,6 @@ import ( "github.com/docker/docker/image" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/system" - "github.com/vbatts/tar-split/tar/asm" - "github.com/vbatts/tar-split/tar/storage" ) // setupInitLayer populates a directory with mountpoints suitable @@ -95,29 +91,7 @@ func (graph *Graph) restoreBaseImages() ([]string, error) { func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader, root string) (err error) { // Store the layer. If layerData is not nil, unpack it into the new layer if layerData != nil { - // this is saving the tar-split metadata - mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600)) - if err != nil { - return err - } - defer mf.Close() - mfz := gzip.NewWriter(mf) - defer mfz.Close() - metaPacker := storage.NewJSONPacker(mfz) - - inflatedLayerData, err := archive.DecompressStream(layerData) - if err != nil { - return err - } - - // we're passing nil here for the file putter, because the ApplyDiff will - // handle the extraction of the archive - its, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil) - if err != nil { - return err - } - - if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, archive.ArchiveReader(its)); err != nil { + if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil { return err } } @@ -138,49 +112,10 @@ func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader // TarLayer returns a tar archive of the image's filesystem layer. func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) { - root := graph.imageRoot(img.ID) - mFileName := filepath.Join(root, tarDataFileName) - mf, err := os.Open(mFileName) + rdr, err := graph.assembleTarLayer(img) if err != nil { - if !os.IsNotExist(err) { - logrus.Errorf("failed to open %q: %s", mFileName, err) - } logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID) return graph.driver.Diff(img.ID, img.Parent) } - pR, pW := io.Pipe() - // this will need to be in a goroutine, as we are returning the stream of a - // tar archive, but can not close the metadata reader early (when this - // function returns)... - go func() { - defer mf.Close() - // let's reassemble! - logrus.Debugf("[graph] TarLayer with reassembly: %s", img.ID) - mfz, err := gzip.NewReader(mf) - if err != nil { - pW.CloseWithError(fmt.Errorf("[graph] error with %s: %s", mFileName, err)) - return - } - defer mfz.Close() - - // get our relative path to the container - fsLayer, err := graph.driver.Get(img.ID, "") - if err != nil { - pW.CloseWithError(err) - return - } - defer graph.driver.Put(img.ID) - - metaUnpacker := storage.NewJSONUnpacker(mfz) - fileGetter := storage.NewPathFileGetter(fsLayer) - logrus.Debugf("[graph] %s is at %q", img.ID, fsLayer) - ots := asm.NewOutputTarStream(fileGetter, metaUnpacker) - defer ots.Close() - if _, err := io.Copy(pW, ots); err != nil { - pW.CloseWithError(err) - return - } - pW.Close() - }() - return pR, nil + return rdr, nil } diff --git a/components/engine/graph/graph_windows.go b/components/engine/graph/graph_windows.go index 95396127d3..1422705a75 100644 --- a/components/engine/graph/graph_windows.go +++ b/components/engine/graph/graph_windows.go @@ -3,19 +3,14 @@ package graph import ( - "compress/gzip" "encoding/json" "fmt" - "io" "os" - "path/filepath" "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/graphdriver/windows" "github.com/docker/docker/image" "github.com/docker/docker/pkg/archive" - "github.com/vbatts/tar-split/tar/asm" - "github.com/vbatts/tar-split/tar/storage" ) // setupInitLayer populates a directory with mountpoints suitable @@ -120,29 +115,7 @@ func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader // Store the layer. If layerData is not nil, unpack it into the new layer if layerData != nil { - // this is saving the tar-split metadata - mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600)) - if err != nil { - return err - } - defer mf.Close() - mfz := gzip.NewWriter(mf) - defer mfz.Close() - metaPacker := storage.NewJSONPacker(mfz) - - inflatedLayerData, err := archive.DecompressStream(layerData) - if err != nil { - return err - } - - // we're passing nil here for the file putter, because the ApplyDiff will - // handle the extraction of the archive - its, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil) - if err != nil { - return err - } - - if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, archive.ArchiveReader(its)); err != nil { + if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil { return err } } @@ -183,50 +156,11 @@ func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) // We keep this functionality here so that we can still work with the VFS // driver during development. VFS is not supported (and just will not work) // for Windows containers. - root := graph.imageRoot(img.ID) - mFileName := filepath.Join(root, tarDataFileName) - mf, err := os.Open(mFileName) + rdr, err := graph.assembleTarLayer(img) if err != nil { - if !os.IsNotExist(err) { - logrus.Errorf("failed to open %q: %s", mFileName, err) - } logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID) return graph.driver.Diff(img.ID, img.Parent) } - pR, pW := io.Pipe() - // this will need to be in a goroutine, as we are returning the stream of a - // tar archive, but can not close the metadata reader early (when this - // function returns)... - go func() { - defer mf.Close() - // let's reassemble! - logrus.Debugf("[graph] TarLayer with reassembly: %s", img.ID) - mfz, err := gzip.NewReader(mf) - if err != nil { - pW.CloseWithError(fmt.Errorf("[graph] error with %s: %s", mFileName, err)) - return - } - defer mfz.Close() - - // get our relative path to the container - fsLayer, err := graph.driver.Get(img.ID, "") - if err != nil { - pW.CloseWithError(err) - return - } - defer graph.driver.Put(img.ID) - - metaUnpacker := storage.NewJSONUnpacker(mfz) - fileGetter := storage.NewPathFileGetter(fsLayer) - logrus.Debugf("[graph] %s is at %q", img.ID, fsLayer) - ots := asm.NewOutputTarStream(fileGetter, metaUnpacker) - defer ots.Close() - if _, err := io.Copy(pW, ots); err != nil { - pW.CloseWithError(err) - return - } - pW.Close() - }() - return pR, nil + return rdr, nil } }