docker tar: stream the contents of a container as a tar archive

This commit is contained in:
Solomon Hykes 2013-01-27 00:59:49 -08:00
parent b6fb5bb21b
commit 3703536303
3 changed files with 48 additions and 2 deletions

View File

@ -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)
}

View File

@ -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 (

View File

@ -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
}