From 37035363031db161732b5757485bec37ef429fb2 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Sun, 27 Jan 2013 00:59:49 -0800 Subject: [PATCH] docker tar: stream the contents of a container as a tar archive --- dockerd/dockerd.go | 12 ++++++++++-- filesystem.go | 18 ++++++++++++++++++ utils.go | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/dockerd/dockerd.go b/dockerd/dockerd.go index a18e565f4c..411ceb64ad 100644 --- a/dockerd/dockerd.go +++ b/dockerd/dockerd.go @@ -39,6 +39,7 @@ func (srv *Server) Help() string { {"commit", "Save the state of a container"}, {"attach", "Attach to the standard inputs and outputs of a running container"}, {"info", "Display system-wide information"}, + {"tar", "Stream the contents of a container as a tar archive"}, {"web", "Generate a web UI"}, } { help += fmt.Sprintf(" %-10.10s%s\n", cmd...) @@ -233,9 +234,16 @@ func (srv *Server) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...string) return nil } name := flags.Arg(0) - if _, exists := srv.findContainer(name); exists { + if container, exists := srv.findContainer(name); exists { + data, err := container.Filesystem.Tar() + if err != nil { + return err + } // Stream the entire contents of the container (basically a volatile snapshot) - return fake.WriteFakeTar(stdout) + if _, err := io.Copy(stdout, data); err != nil { + return err + } + return nil } return errors.New("No such container: " + name) } diff --git a/filesystem.go b/filesystem.go index 54a7e613a2..71c3335404 100644 --- a/filesystem.go +++ b/filesystem.go @@ -67,6 +67,24 @@ func (fs *Filesystem) IsMounted() bool { return false } +// Tar returns the contents of the filesystem as an uncompressed tar stream +func (fs *Filesystem) Tar() (io.Reader, error) { + if err := fs.EnsureMounted(); err != nil { + return nil, err + } + return Tar(fs.RootFS) +} + + +func (fs *Filesystem) EnsureMounted() error { + if !fs.IsMounted() { + if err := fs.Mount(); err != nil { + return err + } + } + return nil +} + type ChangeType int const ( diff --git a/utils.go b/utils.go index 4661a31d81..c1e6695f05 100644 --- a/utils.go +++ b/utils.go @@ -5,8 +5,28 @@ import ( "container/list" "io" "sync" + "os/exec" ) +// Tar generates a tar archive from a filesystem path, and returns it as a stream. +// Path must point to a directory. + +func Tar(path string) (io.Reader, error) { + cmd := exec.Command("tar", "-C", path, "-c", ".") + output, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + if err := cmd.Start(); err != nil { + return nil, err + } + // FIXME: errors will not be passed because we don't wait for the command. + // Instead, consumers will hit EOF right away. + // This can be fixed by waiting for the process to exit, or for the first write + // on stdout, whichever comes first. + return output, nil +} + type nopWriteCloser struct { io.Writer }