Преглед на файлове

Pass excludes/options to tar unarchiver via environment
Fixes #10426

Because of the ability to easily overload the shell max argument list
length once the image count is several hundred, `docker load` will
start to fail because of this as it passes an excludes list of all
images in the graph. This patch uses an environment variable with the
json marshalled through it to get around the arg length limitation.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)

Phil Estes преди 10 години
родител
ревизия
743c9ba1fb
променени са 1 файла, в които са добавени 20 реда и са изтрити 14 реда
  1. 20 14
      pkg/chrootarchive/archive.go

+ 20 - 14
pkg/chrootarchive/archive.go

@@ -1,7 +1,6 @@
 package chrootarchive
 package chrootarchive
 
 
 import (
 import (
-	"bytes"
 	"encoding/json"
 	"encoding/json"
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
@@ -9,7 +8,6 @@ import (
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"runtime"
 	"runtime"
-	"strings"
 	"syscall"
 	"syscall"
 
 
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/archive"
@@ -28,11 +26,14 @@ func chroot(path string) error {
 func untar() {
 func untar() {
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 	flag.Parse()
 	flag.Parse()
-	if err := chroot(flag.Arg(0)); err != nil {
+
+	var options *archive.TarOptions
+
+	if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
 		fatal(err)
 		fatal(err)
 	}
 	}
-	var options *archive.TarOptions
-	if err := json.NewDecoder(strings.NewReader(flag.Arg(1))).Decode(&options); err != nil {
+
+	if err := chroot(flag.Arg(0)); err != nil {
 		fatal(err)
 		fatal(err)
 	}
 	}
 	if err := archive.Unpack(os.Stdin, "/", options); err != nil {
 	if err := archive.Unpack(os.Stdin, "/", options); err != nil {
@@ -54,27 +55,32 @@ func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error
 		options.ExcludePatterns = []string{}
 		options.ExcludePatterns = []string{}
 	}
 	}
 
 
-	var (
-		buf bytes.Buffer
-		enc = json.NewEncoder(&buf)
-	)
-	if err := enc.Encode(options); err != nil {
-		return fmt.Errorf("Untar json encode: %v", err)
-	}
+	dest = filepath.Clean(dest)
 	if _, err := os.Stat(dest); os.IsNotExist(err) {
 	if _, err := os.Stat(dest); os.IsNotExist(err) {
 		if err := os.MkdirAll(dest, 0777); err != nil {
 		if err := os.MkdirAll(dest, 0777); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
-	dest = filepath.Clean(dest)
+
+	// We can't pass the exclude list directly via cmd line
+	// because we easily overrun the shell max argument list length
+	// when the full image list is passed (e.g. when this is used
+	// by `docker load`). Instead we will add the JSON marshalled
+	// and placed in the env, which has significantly larger
+	// max size
+	data, err := json.Marshal(options)
+	if err != nil {
+		return fmt.Errorf("Untar json encode: %v", err)
+	}
 	decompressedArchive, err := archive.DecompressStream(tarArchive)
 	decompressedArchive, err := archive.DecompressStream(tarArchive)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	defer decompressedArchive.Close()
 	defer decompressedArchive.Close()
 
 
-	cmd := reexec.Command("docker-untar", dest, buf.String())
+	cmd := reexec.Command("docker-untar", dest)
 	cmd.Stdin = decompressedArchive
 	cmd.Stdin = decompressedArchive
+	cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data))
 	out, err := cmd.CombinedOutput()
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("Untar %s %s", err, out)
 		return fmt.Errorf("Untar %s %s", err, out)