Browse code

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 authored on 2014/10/30 04:06:51
Showing 11 changed files
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"github.com/docker/docker/daemon"
25 25
 	imagepkg "github.com/docker/docker/image"
26 26
 	"github.com/docker/docker/pkg/archive"
27
+	"github.com/docker/docker/pkg/chrootarchive"
27 28
 	"github.com/docker/docker/pkg/parsers"
28 29
 	"github.com/docker/docker/pkg/symlink"
29 30
 	"github.com/docker/docker/pkg/system"
... ...
@@ -46,7 +47,9 @@ func (b *Builder) readContext(context io.Reader) error {
46 46
 	if b.context, err = tarsum.NewTarSum(decompressedStream, true, tarsum.Version0); err != nil {
47 47
 		return err
48 48
 	}
49
-	if err := archive.Untar(b.context, tmpdirPath, nil); err != nil {
49
+
50
+	os.MkdirAll(tmpdirPath, 0700)
51
+	if err := chrootarchive.Untar(b.context, tmpdirPath, nil); err != nil {
50 52
 		return err
51 53
 	}
52 54
 
... ...
@@ -627,7 +630,7 @@ func (b *Builder) addContext(container *daemon.Container, orig, dest string, dec
627 627
 		}
628 628
 
629 629
 		// try to successfully untar the orig
630
-		if err := archive.UntarPath(origPath, tarDest); err == nil {
630
+		if err := chrootarchive.UntarPath(origPath, tarDest); err == nil {
631 631
 			return nil
632 632
 		} else if err != io.EOF {
633 633
 			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
637 637
 	if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
638 638
 		return err
639 639
 	}
640
-	if err := archive.CopyWithTar(origPath, destPath); err != nil {
640
+	if err := chrootarchive.CopyWithTar(origPath, destPath); err != nil {
641 641
 		return err
642 642
 	}
643 643
 
... ...
@@ -650,7 +653,7 @@ func (b *Builder) addContext(container *daemon.Container, orig, dest string, dec
650 650
 }
651 651
 
652 652
 func copyAsDirectory(source, destination string, destinationExists bool) error {
653
-	if err := archive.CopyWithTar(source, destination); err != nil {
653
+	if err := chrootarchive.CopyWithTar(source, destination); err != nil {
654 654
 		return err
655 655
 	}
656 656
 
... ...
@@ -33,6 +33,7 @@ import (
33 33
 	log "github.com/Sirupsen/logrus"
34 34
 	"github.com/docker/docker/daemon/graphdriver"
35 35
 	"github.com/docker/docker/pkg/archive"
36
+	"github.com/docker/docker/pkg/chrootarchive"
36 37
 	mountpk "github.com/docker/docker/pkg/mount"
37 38
 	"github.com/docker/docker/utils"
38 39
 	"github.com/docker/libcontainer/label"
... ...
@@ -305,7 +306,7 @@ func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
305 305
 }
306 306
 
307 307
 func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
308
-	return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
308
+	return chrootarchive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
309 309
 }
310 310
 
311 311
 // DiffSize calculates the changes between the specified id
... ...
@@ -8,6 +8,7 @@ import (
8 8
 
9 9
 	log "github.com/Sirupsen/logrus"
10 10
 	"github.com/docker/docker/pkg/archive"
11
+	"github.com/docker/docker/pkg/chrootarchive"
11 12
 	"github.com/docker/docker/pkg/ioutils"
12 13
 	"github.com/docker/docker/utils"
13 14
 )
... ...
@@ -122,7 +123,7 @@ func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveRea
122 122
 
123 123
 	start := time.Now().UTC()
124 124
 	log.Debugf("Start untar layer")
125
-	if err = archive.ApplyLayer(layerFs, diff); err != nil {
125
+	if err = chrootarchive.ApplyLayer(layerFs, diff); err != nil {
126 126
 		return
127 127
 	}
128 128
 	log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
... ...
@@ -8,7 +8,7 @@ import (
8 8
 	"path"
9 9
 
10 10
 	"github.com/docker/docker/daemon/graphdriver"
11
-	"github.com/docker/docker/pkg/archive"
11
+	"github.com/docker/docker/pkg/chrootarchive"
12 12
 	"github.com/docker/libcontainer/label"
13 13
 )
14 14
 
... ...
@@ -66,7 +66,7 @@ func (d *Driver) Create(id, parent string) error {
66 66
 	if err != nil {
67 67
 		return fmt.Errorf("%s: %s", parent, err)
68 68
 	}
69
-	if err := archive.CopyWithTar(parentDir, dir); err != nil {
69
+	if err := chrootarchive.CopyWithTar(parentDir, dir); err != nil {
70 70
 		return err
71 71
 	}
72 72
 	return nil
... ...
@@ -12,7 +12,7 @@ import (
12 12
 
13 13
 	log "github.com/Sirupsen/logrus"
14 14
 	"github.com/docker/docker/daemon/execdriver"
15
-	"github.com/docker/docker/pkg/archive"
15
+	"github.com/docker/docker/pkg/chrootarchive"
16 16
 	"github.com/docker/docker/pkg/symlink"
17 17
 	"github.com/docker/docker/volumes"
18 18
 )
... ...
@@ -320,7 +320,7 @@ func copyExistingContents(source, destination string) error {
320 320
 
321 321
 		if len(srcList) == 0 {
322 322
 			// If the source volume is empty copy files from the root into the volume
323
-			if err := archive.CopyWithTar(source, destination); err != nil {
323
+			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
324 324
 				return err
325 325
 			}
326 326
 		}
327 327
new file mode 100644
... ...
@@ -0,0 +1,76 @@
0
+package chrootarchive
1
+
2
+import (
3
+	"flag"
4
+	"fmt"
5
+	"io"
6
+	"os"
7
+	"runtime"
8
+	"syscall"
9
+
10
+	"github.com/docker/docker/pkg/archive"
11
+	"github.com/docker/docker/pkg/reexec"
12
+)
13
+
14
+func untar() {
15
+	runtime.LockOSThread()
16
+	flag.Parse()
17
+
18
+	if err := syscall.Chroot(flag.Arg(0)); err != nil {
19
+		fatal(err)
20
+	}
21
+	if err := syscall.Chdir("/"); err != nil {
22
+		fatal(err)
23
+	}
24
+	if err := archive.Untar(os.Stdin, "/", nil); err != nil {
25
+		fatal(err)
26
+	}
27
+	os.Exit(0)
28
+}
29
+
30
+var (
31
+	chrootArchiver = &archive.Archiver{Untar}
32
+)
33
+
34
+func Untar(archive io.Reader, dest string, options *archive.TarOptions) error {
35
+	if _, err := os.Stat(dest); os.IsNotExist(err) {
36
+		if err := os.MkdirAll(dest, 0777); err != nil {
37
+			return err
38
+		}
39
+	}
40
+	cmd := reexec.Command("docker-untar", dest)
41
+	cmd.Stdin = archive
42
+	out, err := cmd.CombinedOutput()
43
+	if err != nil {
44
+		return fmt.Errorf("Untar %s %s", err, out)
45
+	}
46
+	return nil
47
+}
48
+
49
+func TarUntar(src, dst string) error {
50
+	return chrootArchiver.TarUntar(src, dst)
51
+}
52
+
53
+// CopyWithTar creates a tar archive of filesystem path `src`, and
54
+// unpacks it at filesystem path `dst`.
55
+// The archive is streamed directly with fixed buffering and no
56
+// intermediary disk IO.
57
+func CopyWithTar(src, dst string) error {
58
+	return chrootArchiver.CopyWithTar(src, dst)
59
+}
60
+
61
+// CopyFileWithTar emulates the behavior of the 'cp' command-line
62
+// for a single file. It copies a regular file from path `src` to
63
+// path `dst`, and preserves all its metadata.
64
+//
65
+// If `dst` ends with a trailing slash '/', the final destination path
66
+// will be `dst/base(src)`.
67
+func CopyFileWithTar(src, dst string) (err error) {
68
+	return chrootArchiver.CopyFileWithTar(src, dst)
69
+}
70
+
71
+// UntarPath is a convenience function which looks for an archive
72
+// at filesystem path `src`, and unpacks it at `dst`.
73
+func UntarPath(src, dst string) error {
74
+	return chrootArchiver.UntarPath(src, dst)
75
+}
0 76
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+package chrootarchive
1
+
2
+import (
3
+	"flag"
4
+	"fmt"
5
+	"os"
6
+	"runtime"
7
+	"syscall"
8
+
9
+	"github.com/docker/docker/pkg/archive"
10
+	"github.com/docker/docker/pkg/reexec"
11
+)
12
+
13
+func applyLayer() {
14
+	runtime.LockOSThread()
15
+	flag.Parse()
16
+
17
+	if err := syscall.Chroot(flag.Arg(0)); err != nil {
18
+		fatal(err)
19
+	}
20
+	if err := syscall.Chdir("/"); err != nil {
21
+		fatal(err)
22
+	}
23
+	if err := archive.ApplyLayer("/", os.Stdin); err != nil {
24
+		fatal(err)
25
+	}
26
+	os.Exit(0)
27
+}
28
+
29
+func ApplyLayer(dest string, layer archive.ArchiveReader) error {
30
+	cmd := reexec.Command("docker-applyLayer", dest)
31
+	cmd.Stdin = layer
32
+	out, err := cmd.CombinedOutput()
33
+	if err != nil {
34
+		return fmt.Errorf("ApplyLayer %s %s", err, out)
35
+	}
36
+	return nil
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+package chrootarchive
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+
6
+	"github.com/docker/docker/pkg/reexec"
7
+)
8
+
9
+func init() {
10
+	reexec.Register("docker-untar", untar)
11
+	reexec.Register("docker-applyLayer", applyLayer)
12
+}
13
+
14
+func fatal(err error) {
15
+	fmt.Fprint(os.Stderr, err)
16
+	os.Exit(1)
17
+}
0 18
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+// +build linux
1
+
2
+package reexec
3
+
4
+import (
5
+	"os/exec"
6
+	"syscall"
7
+)
8
+
9
+func Command(args ...string) *exec.Cmd {
10
+	return &exec.Cmd{
11
+		Path: Self(),
12
+		Args: args,
13
+		SysProcAttr: &syscall.SysProcAttr{
14
+			Pdeathsig: syscall.SIGTERM,
15
+		},
16
+	}
17
+}
0 18
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+// +build !linux
1
+
2
+package reexec
3
+
4
+import (
5
+	"os/exec"
6
+)
7
+
8
+func Command(args ...string) *exec.Cmd {
9
+	return nil
10
+}
... ...
@@ -27,19 +27,16 @@ func Init() bool {
27 27
 
28 28
 		return true
29 29
 	}
30
-
31 30
 	return false
32 31
 }
33 32
 
34 33
 // Self returns the path to the current processes binary
35 34
 func Self() string {
36 35
 	name := os.Args[0]
37
-
38 36
 	if filepath.Base(name) == name {
39 37
 		if lp, err := exec.LookPath(name); err == nil {
40 38
 			name = lp
41 39
 		}
42 40
 	}
43
-
44 41
 	return name
45 42
 }