Explorar o código

add pkg/chrootarchive and use it on the daemon

Docker-DCO-1.1-Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com> (github: unclejack)

Conflicts:
	builder/internals.go
	daemon/graphdriver/aufs/aufs.go
	daemon/volumes.go
		fixed conflicts in imports
unclejack %!s(int64=10) %!d(string=hai) anos
pai
achega
1cb17f03d0

+ 7 - 4
builder/internals.go

@@ -24,6 +24,7 @@ import (
 	"github.com/docker/docker/daemon"
 	imagepkg "github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/pkg/system"
@@ -46,7 +47,9 @@ func (b *Builder) readContext(context io.Reader) error {
 	if b.context, err = tarsum.NewTarSum(decompressedStream, true, tarsum.Version0); err != nil {
 		return err
 	}
-	if err := archive.Untar(b.context, tmpdirPath, nil); err != nil {
+
+	os.MkdirAll(tmpdirPath, 0700)
+	if err := chrootarchive.Untar(b.context, tmpdirPath, nil); err != nil {
 		return err
 	}
 
@@ -627,7 +630,7 @@ func (b *Builder) addContext(container *daemon.Container, orig, dest string, dec
 		}
 
 		// try to successfully untar the orig
-		if err := archive.UntarPath(origPath, tarDest); err == nil {
+		if err := chrootarchive.UntarPath(origPath, tarDest); err == nil {
 			return nil
 		} else if err != io.EOF {
 			log.Debugf("Couldn't untar %s to %s: %s", origPath, tarDest, err)
@@ -637,7 +640,7 @@ func (b *Builder) addContext(container *daemon.Container, orig, dest string, dec
 	if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
 		return err
 	}
-	if err := archive.CopyWithTar(origPath, destPath); err != nil {
+	if err := chrootarchive.CopyWithTar(origPath, destPath); err != nil {
 		return err
 	}
 
@@ -650,7 +653,7 @@ func (b *Builder) addContext(container *daemon.Container, orig, dest string, dec
 }
 
 func copyAsDirectory(source, destination string, destinationExists bool) error {
-	if err := archive.CopyWithTar(source, destination); err != nil {
+	if err := chrootarchive.CopyWithTar(source, destination); err != nil {
 		return err
 	}
 

+ 2 - 1
daemon/graphdriver/aufs/aufs.go

@@ -33,6 +33,7 @@ import (
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/chrootarchive"
 	mountpk "github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/utils"
 	"github.com/docker/libcontainer/label"
@@ -305,7 +306,7 @@ func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
 }
 
 func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
-	return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
+	return chrootarchive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
 }
 
 // DiffSize calculates the changes between the specified id

+ 2 - 1
daemon/graphdriver/fsdiff.go

@@ -8,6 +8,7 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/utils"
 )
@@ -122,7 +123,7 @@ func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveRea
 
 	start := time.Now().UTC()
 	log.Debugf("Start untar layer")
-	if err = archive.ApplyLayer(layerFs, diff); err != nil {
+	if err = chrootarchive.ApplyLayer(layerFs, diff); err != nil {
 		return
 	}
 	log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())

+ 2 - 2
daemon/graphdriver/vfs/driver.go

@@ -8,7 +8,7 @@ import (
 	"path"
 
 	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/libcontainer/label"
 )
 
@@ -66,7 +66,7 @@ func (d *Driver) Create(id, parent string) error {
 	if err != nil {
 		return fmt.Errorf("%s: %s", parent, err)
 	}
-	if err := archive.CopyWithTar(parentDir, dir); err != nil {
+	if err := chrootarchive.CopyWithTar(parentDir, dir); err != nil {
 		return err
 	}
 	return nil

+ 2 - 2
daemon/volumes.go

@@ -12,7 +12,7 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
-	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/volumes"
 )
@@ -320,7 +320,7 @@ func copyExistingContents(source, destination string) error {
 
 		if len(srcList) == 0 {
 			// If the source volume is empty copy files from the root into the volume
-			if err := archive.CopyWithTar(source, destination); err != nil {
+			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
 				return err
 			}
 		}

+ 76 - 0
pkg/chrootarchive/archive.go

@@ -0,0 +1,76 @@
+package chrootarchive
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"runtime"
+	"syscall"
+
+	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/reexec"
+)
+
+func untar() {
+	runtime.LockOSThread()
+	flag.Parse()
+
+	if err := syscall.Chroot(flag.Arg(0)); err != nil {
+		fatal(err)
+	}
+	if err := syscall.Chdir("/"); err != nil {
+		fatal(err)
+	}
+	if err := archive.Untar(os.Stdin, "/", nil); err != nil {
+		fatal(err)
+	}
+	os.Exit(0)
+}
+
+var (
+	chrootArchiver = &archive.Archiver{Untar}
+)
+
+func Untar(archive io.Reader, dest string, options *archive.TarOptions) error {
+	if _, err := os.Stat(dest); os.IsNotExist(err) {
+		if err := os.MkdirAll(dest, 0777); err != nil {
+			return err
+		}
+	}
+	cmd := reexec.Command("docker-untar", dest)
+	cmd.Stdin = archive
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("Untar %s %s", err, out)
+	}
+	return nil
+}
+
+func TarUntar(src, dst string) error {
+	return chrootArchiver.TarUntar(src, dst)
+}
+
+// CopyWithTar creates a tar archive of filesystem path `src`, and
+// unpacks it at filesystem path `dst`.
+// The archive is streamed directly with fixed buffering and no
+// intermediary disk IO.
+func CopyWithTar(src, dst string) error {
+	return chrootArchiver.CopyWithTar(src, dst)
+}
+
+// CopyFileWithTar emulates the behavior of the 'cp' command-line
+// for a single file. It copies a regular file from path `src` to
+// path `dst`, and preserves all its metadata.
+//
+// If `dst` ends with a trailing slash '/', the final destination path
+// will be `dst/base(src)`.
+func CopyFileWithTar(src, dst string) (err error) {
+	return chrootArchiver.CopyFileWithTar(src, dst)
+}
+
+// UntarPath is a convenience function which looks for an archive
+// at filesystem path `src`, and unpacks it at `dst`.
+func UntarPath(src, dst string) error {
+	return chrootArchiver.UntarPath(src, dst)
+}

+ 38 - 0
pkg/chrootarchive/diff.go

@@ -0,0 +1,38 @@
+package chrootarchive
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"runtime"
+	"syscall"
+
+	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/reexec"
+)
+
+func applyLayer() {
+	runtime.LockOSThread()
+	flag.Parse()
+
+	if err := syscall.Chroot(flag.Arg(0)); err != nil {
+		fatal(err)
+	}
+	if err := syscall.Chdir("/"); err != nil {
+		fatal(err)
+	}
+	if err := archive.ApplyLayer("/", os.Stdin); err != nil {
+		fatal(err)
+	}
+	os.Exit(0)
+}
+
+func ApplyLayer(dest string, layer archive.ArchiveReader) error {
+	cmd := reexec.Command("docker-applyLayer", dest)
+	cmd.Stdin = layer
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("ApplyLayer %s %s", err, out)
+	}
+	return nil
+}

+ 18 - 0
pkg/chrootarchive/init.go

@@ -0,0 +1,18 @@
+package chrootarchive
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/docker/docker/pkg/reexec"
+)
+
+func init() {
+	reexec.Register("docker-untar", untar)
+	reexec.Register("docker-applyLayer", applyLayer)
+}
+
+func fatal(err error) {
+	fmt.Fprint(os.Stderr, err)
+	os.Exit(1)
+}

+ 18 - 0
pkg/reexec/command_linux.go

@@ -0,0 +1,18 @@
+// +build linux
+
+package reexec
+
+import (
+	"os/exec"
+	"syscall"
+)
+
+func Command(args ...string) *exec.Cmd {
+	return &exec.Cmd{
+		Path: Self(),
+		Args: args,
+		SysProcAttr: &syscall.SysProcAttr{
+			Pdeathsig: syscall.SIGTERM,
+		},
+	}
+}

+ 11 - 0
pkg/reexec/command_unsupported.go

@@ -0,0 +1,11 @@
+// +build !linux
+
+package reexec
+
+import (
+	"os/exec"
+)
+
+func Command(args ...string) *exec.Cmd {
+	return nil
+}

+ 0 - 3
pkg/reexec/reexec.go

@@ -27,19 +27,16 @@ func Init() bool {
 
 		return true
 	}
-
 	return false
 }
 
 // Self returns the path to the current processes binary
 func Self() string {
 	name := os.Args[0]
-
 	if filepath.Base(name) == name {
 		if lp, err := exec.LookPath(name); err == nil {
 			name = lp
 		}
 	}
-
 	return name
 }