Browse Source

Integrate devmapper and aufs into the common "graphdriver" framework.

aufs is still enabled by default, no mechanism for switching drivers
yet.
Solomon Hykes 11 years ago
parent
commit
98c3693acf
10 changed files with 160 additions and 95 deletions
  1. 78 0
      aufs/aufs.go
  2. 1 1
      aufs/mount.go
  3. 1 1
      aufs/mount_darwin.go
  4. 1 1
      aufs/mount_linux.go
  5. 4 18
      container.go
  6. 5 2
      graph.go
  7. 8 3
      graph_test.go
  8. 16 0
      graphdriver/driver.go
  9. 6 67
      image.go
  10. 40 2
      runtime.go

+ 78 - 0
aufs/aufs.go

@@ -0,0 +1,78 @@
+package aufs
+
+import (
+	"fmt"
+	"github.com/dotcloud/docker/graphdriver"
+	"log"
+	"os"
+	"os/exec"
+	"path"
+)
+
+type AufsDriver struct {
+}
+
+// New returns a new AUFS driver.
+// An error is returned if AUFS is not supported.
+func New() (*AufsDriver, error) {
+	return &AufsDriver{}, nil
+}
+
+func (a *AufsDriver) Mount(img graphdriver.Image, root string) error {
+	layers, err := img.Layers()
+	if err != nil {
+		return err
+	}
+
+	target := path.Join(root, "rootfs")
+	rw := path.Join(root, "rw")
+
+	// Create the target directories if they don't exist
+	if err := os.Mkdir(target, 0755); err != nil && !os.IsExist(err) {
+		return err
+	}
+	if err := os.Mkdir(rw, 0755); err != nil && !os.IsExist(err) {
+		return err
+	}
+	if err := a.aufsMount(layers, rw, target); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (a *AufsDriver) Unmount(root string) error {
+	target := path.Join(root, "rootfs")
+	if _, err := os.Stat(target); err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+	return Unmount(target)
+}
+
+func (a *AufsDriver) Mounted(root string) (bool, error) {
+	return Mounted(path.Join(root, "rootfs"))
+}
+
+func (a *AufsDriver) aufsMount(ro []string, rw, target string) error {
+	rwBranch := fmt.Sprintf("%v=rw", rw)
+	roBranches := ""
+	for _, layer := range ro {
+		roBranches += fmt.Sprintf("%v=ro+wh:", layer)
+	}
+	branches := fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches)
+
+	//if error, try to load aufs kernel module
+	if err := mount("none", target, "aufs", 0, branches); err != nil {
+		log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
+		if err := exec.Command("modprobe", "aufs").Run(); err != nil {
+			return fmt.Errorf("Unable to load the AUFS module")
+		}
+		log.Printf("...module loaded.")
+		if err := mount("none", target, "aufs", 0, branches); err != nil {
+			return fmt.Errorf("Unable to mount using aufs")
+		}
+	}
+	return nil
+}

+ 1 - 1
mount.go → aufs/mount.go

@@ -1,4 +1,4 @@
-package docker
+package aufs
 
 import (
 	"fmt"

+ 1 - 1
mount_darwin.go → aufs/mount_darwin.go

@@ -1,4 +1,4 @@
-package docker
+package aufs
 
 import "errors"
 

+ 1 - 1
mount_linux.go → aufs/mount_linux.go

@@ -1,4 +1,4 @@
-package docker
+package aufs
 
 import "syscall"
 

+ 4 - 18
container.go

@@ -1382,19 +1382,11 @@ func (container *Container) EnsureMounted() error {
 }
 
 func (container *Container) Mount() error {
-	image, err := container.GetImage()
-	if err != nil {
-		return err
-	}
-	return image.Mount(container.RootfsPath(), container.rwPath())
+	return container.runtime.Mount(container)
 }
 
 func (container *Container) Changes() ([]Change, error) {
-	image, err := container.GetImage()
-	if err != nil {
-		return nil, err
-	}
-	return image.Changes(container.rwPath())
+	return container.runtime.Changes(container)
 }
 
 func (container *Container) GetImage() (*Image, error) {
@@ -1405,17 +1397,11 @@ func (container *Container) GetImage() (*Image, error) {
 }
 
 func (container *Container) Mounted() (bool, error) {
-	return Mounted(container.RootfsPath())
+	return container.runtime.Mounted(container)
 }
 
 func (container *Container) Unmount() error {
-	if _, err := os.Stat(container.RootfsPath()); err != nil {
-		if os.IsNotExist(err) {
-			return nil
-		}
-		return err
-	}
-	return Unmount(container.RootfsPath())
+	return container.runtime.Unmount(container)
 }
 
 // ShortID returns a shorthand version of the container's id for convenience.

+ 5 - 2
graph.go

@@ -3,6 +3,7 @@ package docker
 import (
 	"fmt"
 	"github.com/dotcloud/docker/archive"
+	"github.com/dotcloud/docker/graphdriver"
 	"github.com/dotcloud/docker/utils"
 	"io"
 	"io/ioutil"
@@ -17,11 +18,12 @@ import (
 type Graph struct {
 	Root    string
 	idIndex *utils.TruncIndex
+	driver graphdriver.Driver
 }
 
 // NewGraph instantiates a new graph at the given root path in the filesystem.
 // `root` will be created if it doesn't exist.
-func NewGraph(root string) (*Graph, error) {
+func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
 	abspath, err := filepath.Abs(root)
 	if err != nil {
 		return nil, err
@@ -33,6 +35,7 @@ func NewGraph(root string) (*Graph, error) {
 	graph := &Graph{
 		Root:    abspath,
 		idIndex: utils.NewTruncIndex(),
+		driver: driver,
 	}
 	if err := graph.restore(); err != nil {
 		return nil, err
@@ -239,7 +242,7 @@ func (graph *Graph) getDockerInitLayer() (string, error) {
 
 func (graph *Graph) tmp() (*Graph, error) {
 	// Changed to _tmp from :tmp:, because it messed with ":" separators in aufs branch syntax...
-	return NewGraph(path.Join(graph.Root, "_tmp"))
+	return NewGraph(path.Join(graph.Root, "_tmp"), graph.driver)
 }
 
 // Check if given error is "not empty".

+ 8 - 3
graph_test.go

@@ -5,6 +5,7 @@ import (
 	"bytes"
 	"errors"
 	"github.com/dotcloud/docker/archive"
+	"github.com/dotcloud/docker/aufs"
 	"github.com/dotcloud/docker/utils"
 	"io"
 	"io/ioutil"
@@ -145,12 +146,12 @@ func TestMount(t *testing.T) {
 	if err := os.MkdirAll(rw, 0700); err != nil {
 		t.Fatal(err)
 	}
-	if err := image.Mount(rootfs, rw); err != nil {
+	if err := graph.driver.Mount(image, tmp); err != nil {
 		t.Fatal(err)
 	}
 	// FIXME: test for mount contents
 	defer func() {
-		if err := Unmount(rootfs); err != nil {
+		if err := graph.driver.Unmount(tmp); err != nil {
 			t.Error(err)
 		}
 	}()
@@ -295,7 +296,11 @@ func tempGraph(t *testing.T) *Graph {
 	if err != nil {
 		t.Fatal(err)
 	}
-	graph, err := NewGraph(tmp)
+	backend, err := aufs.New()
+	if err != nil {
+		t.Fatal(err)
+	}
+	graph, err := NewGraph(tmp, backend)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 16 - 0
graphdriver/driver.go

@@ -0,0 +1,16 @@
+package graphdriver
+
+type Image interface {
+	Layers() ([]string, error)
+}
+
+type Driver interface {
+	//	Create(img *Image) error
+	//	Delete(img *Image) error
+	Mount(img Image, root string) error
+	Unmount(root string) error
+	Mounted(root string) (bool, error)
+	//	UnmountAll(img *Image) error
+	//	Changes(img *Image, dest string) ([]Change, error)
+	//	Layer(img *Image, dest string) (Archive, error)
+}

+ 6 - 67
image.go

@@ -9,9 +9,7 @@ import (
 	"github.com/dotcloud/docker/utils"
 	"io"
 	"io/ioutil"
-	"log"
 	"os"
-	"os/exec"
 	"path"
 	"path/filepath"
 	"strconv"
@@ -137,31 +135,6 @@ func jsonPath(root string) string {
 	return path.Join(root, "json")
 }
 
-func MountAUFS(ro []string, rw string, target string) error {
-	// FIXME: Now mount the layers
-	rwBranch := fmt.Sprintf("%v=rw", rw)
-	roBranches := ""
-	for _, layer := range ro {
-		roBranches += fmt.Sprintf("%v=ro+wh:", layer)
-	}
-	branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)
-
-	branches += ",xino=/dev/shm/aufs.xino"
-
-	//if error, try to load aufs kernel module
-	if err := mount("none", target, "aufs", 0, branches); err != nil {
-		log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
-		if err := exec.Command("modprobe", "aufs").Run(); err != nil {
-			return fmt.Errorf("Unable to load the AUFS module")
-		}
-		log.Printf("...module loaded.")
-		if err := mount("none", target, "aufs", 0, branches); err != nil {
-			return fmt.Errorf("Unable to mount using aufs")
-		}
-	}
-	return nil
-}
-
 // TarLayer returns a tar archive of the image's filesystem layer.
 func (image *Image) TarLayer(compression archive.Compression) (archive.Archive, error) {
 	layerPath, err := image.layer()
@@ -171,37 +144,6 @@ func (image *Image) TarLayer(compression archive.Compression) (archive.Archive,
 	return archive.Tar(layerPath, compression)
 }
 
-func (image *Image) Mount(root, rw string) error {
-	if mounted, err := Mounted(root); err != nil {
-		return err
-	} else if mounted {
-		return fmt.Errorf("%s is already mounted", root)
-	}
-	layers, err := image.layers()
-	if err != nil {
-		return err
-	}
-	// Create the target directories if they don't exist
-	if err := os.Mkdir(root, 0755); err != nil && !os.IsExist(err) {
-		return err
-	}
-	if err := os.Mkdir(rw, 0755); err != nil && !os.IsExist(err) {
-		return err
-	}
-	if err := MountAUFS(layers, rw, root); err != nil {
-		return err
-	}
-	return nil
-}
-
-func (image *Image) Changes(rw string) ([]Change, error) {
-	layers, err := image.layers()
-	if err != nil {
-		return nil, err
-	}
-	return Changes(layers, rw)
-}
-
 func (image *Image) ShortID() string {
 	return utils.TruncateID(image.ID)
 }
@@ -244,7 +186,11 @@ func (img *Image) History() ([]*Image, error) {
 // layers returns all the filesystem layers needed to mount an image
 // FIXME: @shykes refactor this function with the new error handling
 //        (I'll do it if I have time tonight, I focus on the rest)
-func (img *Image) layers() ([]string, error) {
+func (img *Image) Layers() ([]string, error) {
+	if img.graph == nil {
+
+		return nil, fmt.Errorf("Can't lookup dockerinit layer of unregistered image")
+	}
 	var list []string
 	var e error
 	if err := img.WalkHistory(
@@ -266,7 +212,7 @@ func (img *Image) layers() ([]string, error) {
 	}
 
 	// Inject the dockerinit layer (empty place-holder for mount-binding dockerinit)
-	if dockerinitLayer, err := img.getDockerInitLayer(); err != nil {
+	if dockerinitLayer, err := img.graph.getDockerInitLayer(); err != nil {
 		return nil, err
 	} else {
 		list = append([]string{dockerinitLayer}, list...)
@@ -300,13 +246,6 @@ func (img *Image) GetParent() (*Image, error) {
 	return img.graph.Get(img.Parent)
 }
 
-func (img *Image) getDockerInitLayer() (string, error) {
-	if img.graph == nil {
-		return "", fmt.Errorf("Can't lookup dockerinit layer of unregistered image")
-	}
-	return img.graph.getDockerInitLayer()
-}
-
 func (img *Image) root() (string, error) {
 	if img.graph == nil {
 		return "", fmt.Errorf("Can't lookup root of unregistered image")

+ 40 - 2
runtime.go

@@ -5,6 +5,7 @@ import (
 	"container/list"
 	"database/sql"
 	"fmt"
+	"github.com/dotcloud/docker/aufs"
 	"github.com/dotcloud/docker/gograph"
 	"github.com/dotcloud/docker/utils"
 	"io"
@@ -573,12 +574,16 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
 	if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) {
 		return nil, err
 	}
+	driver, err := aufs.New()
+	if err != nil {
+		return nil, err
+	}
 
-	g, err := NewGraph(path.Join(config.Root, "graph"))
+	g, err := NewGraph(path.Join(config.Root, "graph"), driver)
 	if err != nil {
 		return nil, err
 	}
-	volumes, err := NewGraph(path.Join(config.Root, "volumes"))
+	volumes, err := NewGraph(path.Join(config.Root, "volumes"), driver)
 	if err != nil {
 		return nil, err
 	}
@@ -636,6 +641,39 @@ func (runtime *Runtime) Close() error {
 	return runtime.containerGraph.Close()
 }
 
+func (runtime *Runtime) Mount(container *Container) error {
+	if mounted, err := runtime.Mounted(container); err != nil {
+		return err
+	} else if mounted {
+		return fmt.Errorf("%s is already mounted", container.RootfsPath())
+	}
+	img, err := container.GetImage()
+	if err != nil {
+		return err
+	}
+	return runtime.graph.driver.Mount(img, container.root)
+}
+
+func (runtime *Runtime) Unmount(container *Container) error {
+	return runtime.graph.driver.Unmount(container.root)
+}
+
+func (runtime *Runtime) Mounted(container *Container) (bool, error) {
+	return runtime.graph.driver.Mounted(container.root)
+}
+
+func (runtime *Runtime) Changes(container *Container) ([]Change, error) {
+	img, err := container.GetImage()
+	if err != nil {
+		return nil, err
+	}
+	layers, err := img.Layers()
+	if err != nil {
+		return nil, err
+	}
+	return Changes(layers, container.rwPath())
+}
+
 // History is a convenience type for storing a list of containers,
 // ordered by creation date.
 type History []*Container