Forráskód Böngészése

Fix volumes on the host by following symlinks in a scope

Michael Crosby 11 éve
szülő
commit
f396c42cad
6 módosított fájl, 148 hozzáadás és 15 törlés
  1. 14 15
      container.go
  2. 47 0
      utils/fs.go
  3. 84 0
      utils/fs_test.go
  4. 1 0
      utils/testdata/fs/a/d
  5. 1 0
      utils/testdata/fs/a/e
  6. 1 0
      utils/testdata/fs/a/f

+ 14 - 15
container.go

@@ -774,14 +774,14 @@ func (container *Container) getBindMap() (map[string]BindMap, error) {
 		}
 		binds[path.Clean(dst)] = bindMap
 	}
-  return binds, nil
+	return binds, nil
 }
 
 func (container *Container) createVolumes() error {
-  binds, err := container.getBindMap()
-  if err != nil {
-    return err
-  }
+	binds, err := container.getBindMap()
+	if err != nil {
+		return err
+	}
 	volumesDriver := container.runtime.volumes.driver
 	// Create the requested volumes if they don't exist
 	for volPath := range container.Config.Volumes {
@@ -824,26 +824,25 @@ func (container *Container) createVolumes() error {
 		}
 		container.Volumes[volPath] = srcPath
 		container.VolumesRW[volPath] = srcRW
+
 		// Create the mountpoint
-		rootVolPath := path.Join(container.RootfsPath(), volPath)
-		if volIsDir {
-			if err := os.MkdirAll(rootVolPath, 0755); err != nil {
-				return err
-			}
+		volPath = path.Join(container.RootfsPath(), volPath)
+		rootVolPath, err := utils.FollowSymlink(volPath, container.RootfsPath())
+		if err != nil {
+			panic(err)
 		}
 
-		volPath = path.Join(container.RootfsPath(), volPath)
-		if _, err := os.Stat(volPath); err != nil {
+		if _, err := os.Stat(rootVolPath); err != nil {
 			if os.IsNotExist(err) {
 				if volIsDir {
-					if err := os.MkdirAll(volPath, 0755); err != nil {
+					if err := os.MkdirAll(rootVolPath, 0755); err != nil {
 						return err
 					}
 				} else {
-					if err := os.MkdirAll(path.Dir(volPath), 0755); err != nil {
+					if err := os.MkdirAll(path.Dir(rootVolPath), 0755); err != nil {
 						return err
 					}
-					if f, err := os.OpenFile(volPath, os.O_CREATE, 0755); err != nil {
+					if f, err := os.OpenFile(rootVolPath, os.O_CREATE, 0755); err != nil {
 						return err
 					} else {
 						f.Close()

+ 47 - 0
utils/fs.go

@@ -3,6 +3,7 @@ package utils
 import (
 	"os"
 	"path/filepath"
+	"strings"
 	"syscall"
 )
 
@@ -33,3 +34,49 @@ func TreeSize(dir string) (size int64, err error) {
 	})
 	return
 }
+
+// FollowSymlink will follow an existing link and scope it to the root
+// path provided.
+func FollowSymlinkInScope(link, root string) (string, error) {
+	prev := "."
+
+	root, err := filepath.Abs(root)
+	if err != nil {
+		return "", err
+	}
+	root = filepath.Clean(root)
+	link, err := filepath.Abs(link)
+	if err != nil {
+		return "", err
+	}
+	link = filepath.Clean(link)
+
+	for _, p := range strings.Split(link, "/") {
+		prev = filepath.Join(prev, p)
+		prev = filepath.Clean(prev)
+
+		stat, err := os.Lstat(prev)
+		if err != nil {
+			if os.IsNotExist(err) {
+				continue
+			}
+			return "", err
+		}
+		if stat.Mode()&os.ModeSymlink == os.ModeSymlink {
+			dest, err := os.Readlink(prev)
+			if err != nil {
+				return "", err
+			}
+
+			switch dest[0] {
+			case '/':
+				prev = filepath.Join(root, dest)
+			case '.':
+				if prev = filepath.Clean(filepath.Join(filepath.Dir(prev), dest)); len(prev) < len(root) {
+					prev = filepath.Join(root, filepath.Base(dest))
+				}
+			}
+		}
+	}
+	return prev, nil
+}

+ 84 - 0
utils/fs_test.go

@@ -0,0 +1,84 @@
+package utils
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+func abs(p string) string {
+	o, err := filepath.Abs(p)
+	if err != nil {
+		panic(err)
+	}
+	return o
+}
+
+func TestFollowSymLinkNormal(t *testing.T) {
+	link := "testdata/fs/a/d/c/data"
+
+	rewrite, err := FollowSymlink(link, "test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if expected := abs("test/b/c/data"); expected != rewrite {
+		t.Fatalf("Expected %s got %s", expected, rewrite)
+	}
+}
+
+func TestFollowSymLinkRandomString(t *testing.T) {
+	rewrite, err := FollowSymlink("toto", "test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if rewrite != "toto" {
+		t.Fatalf("Expected toto got %s", rewrite)
+	}
+}
+
+func TestFollowSymLinkLastLink(t *testing.T) {
+	link := "testdata/fs/a/d"
+
+	rewrite, err := FollowSymlink(link, "test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if expected := abs("test/b"); expected != rewrite {
+		t.Fatalf("Expected %s got %s", expected, rewrite)
+	}
+}
+
+func TestFollowSymLinkRelativeLink(t *testing.T) {
+	link := "testdata/fs/a/e/c/data"
+
+	rewrite, err := FollowSymlink(link, "test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if expected := abs("testdata/fs/a/e/c/data"); expected != rewrite {
+		t.Fatalf("Expected %s got %s", expected, rewrite)
+	}
+}
+
+func TestFollowSymLinkRelativeLinkScope(t *testing.T) {
+	link := "testdata/fs/a/f"
+	pwd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	root := filepath.Join(pwd, "testdata")
+
+	rewrite, err := FollowSymlink(link, root)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if expected := abs("testdata/test"); expected != rewrite {
+		t.Fatalf("Expected %s got %s", expected, rewrite)
+	}
+}

+ 1 - 0
utils/testdata/fs/a/d

@@ -0,0 +1 @@
+/b

+ 1 - 0
utils/testdata/fs/a/e

@@ -0,0 +1 @@
+../b

+ 1 - 0
utils/testdata/fs/a/f

@@ -0,0 +1 @@
+../../../../test