From 699a1074fb9cdf323044f8c132d7130f6a2945bc Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 31 Oct 2013 18:07:54 -0700 Subject: [PATCH 1/2] Initial work on moving aufs to a subpackage --- aufs/aufs.go | 78 +++++++++++++++++++++++++ mount.go => aufs/mount.go | 2 +- mount_darwin.go => aufs/mount_darwin.go | 2 +- mount_linux.go => aufs/mount_linux.go | 2 +- container.go | 22 ++----- graph.go | 7 ++- graph_test.go | 11 +++- graphbackend/backend.go | 16 +++++ image.go | 73 ++--------------------- runtime.go | 44 +++++++++++++- 10 files changed, 161 insertions(+), 96 deletions(-) create mode 100644 aufs/aufs.go rename mount.go => aufs/mount.go (98%) rename mount_darwin.go => aufs/mount_darwin.go (92%) rename mount_linux.go => aufs/mount_linux.go (92%) create mode 100644 graphbackend/backend.go diff --git a/aufs/aufs.go b/aufs/aufs.go new file mode 100644 index 0000000000..766091cf04 --- /dev/null +++ b/aufs/aufs.go @@ -0,0 +1,78 @@ +package aufs + +import ( + "fmt" + "github.com/dotcloud/docker/graphbackend" + "log" + "os" + "os/exec" + "path" +) + +type AufsBackend struct { +} + +// Return a new AUFS backend +// An error is returned if AUFS is not supported +func NewBackend() (*AufsBackend, error) { + return &AufsBackend{}, nil +} + +func (a *AufsBackend) Mount(img graphbackend.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 *AufsBackend) 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 *AufsBackend) Mounted(root string) (bool, error) { + return Mounted(path.Join(root, "rootfs")) +} + +func (a *AufsBackend) 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 +} diff --git a/mount.go b/aufs/mount.go similarity index 98% rename from mount.go rename to aufs/mount.go index f4a4dfbae1..15cb2da93f 100644 --- a/mount.go +++ b/aufs/mount.go @@ -1,4 +1,4 @@ -package docker +package aufs import ( "fmt" diff --git a/mount_darwin.go b/aufs/mount_darwin.go similarity index 92% rename from mount_darwin.go rename to aufs/mount_darwin.go index aeac78cda5..ce448036f2 100644 --- a/mount_darwin.go +++ b/aufs/mount_darwin.go @@ -1,4 +1,4 @@ -package docker +package aufs import "errors" diff --git a/mount_linux.go b/aufs/mount_linux.go similarity index 92% rename from mount_linux.go rename to aufs/mount_linux.go index 0efb253003..7122b73cea 100644 --- a/mount_linux.go +++ b/aufs/mount_linux.go @@ -1,4 +1,4 @@ -package docker +package aufs import "syscall" diff --git a/container.go b/container.go index 9448932674..e2214842d3 100644 --- a/container.go +++ b/container.go @@ -1381,19 +1381,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) { @@ -1404,17 +1396,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. diff --git a/graph.go b/graph.go index d4ce12e67b..266bef5a57 100644 --- a/graph.go +++ b/graph.go @@ -2,6 +2,7 @@ package docker import ( "fmt" + "github.com/dotcloud/docker/graphbackend" "github.com/dotcloud/docker/utils" "io" "io/ioutil" @@ -16,11 +17,12 @@ import ( type Graph struct { Root string idIndex *utils.TruncIndex + backend graphbackend.GraphBackend } // 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, backend graphbackend.GraphBackend) (*Graph, error) { abspath, err := filepath.Abs(root) if err != nil { return nil, err @@ -32,6 +34,7 @@ func NewGraph(root string) (*Graph, error) { graph := &Graph{ Root: abspath, idIndex: utils.NewTruncIndex(), + backend: backend, } if err := graph.restore(); err != nil { return nil, err @@ -238,7 +241,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.backend) } // Check if given error is "not empty". diff --git a/graph_test.go b/graph_test.go index 471016938d..cc4c6614f6 100644 --- a/graph_test.go +++ b/graph_test.go @@ -4,6 +4,7 @@ import ( "archive/tar" "bytes" "errors" + "github.com/dotcloud/docker/aufs" "github.com/dotcloud/docker/utils" "io" "io/ioutil" @@ -144,12 +145,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.backend.Mount(image, tmp); err != nil { t.Fatal(err) } // FIXME: test for mount contents defer func() { - if err := Unmount(rootfs); err != nil { + if err := graph.backend.Unmount(tmp); err != nil { t.Error(err) } }() @@ -294,7 +295,11 @@ func tempGraph(t *testing.T) *Graph { if err != nil { t.Fatal(err) } - graph, err := NewGraph(tmp) + backend, err := aufs.NewBackend() + if err != nil { + t.Fatal(err) + } + graph, err := NewGraph(tmp, backend) if err != nil { t.Fatal(err) } diff --git a/graphbackend/backend.go b/graphbackend/backend.go new file mode 100644 index 0000000000..33360ad5cb --- /dev/null +++ b/graphbackend/backend.go @@ -0,0 +1,16 @@ +package graphbackend + +type Image interface { + Layers() ([]string, error) +} + +type GraphBackend 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) +} diff --git a/image.go b/image.go index a62724803f..6d6f404a6b 100644 --- a/image.go +++ b/image.go @@ -8,9 +8,7 @@ import ( "github.com/dotcloud/docker/utils" "io" "io/ioutil" - "log" "os" - "os/exec" "path" "path/filepath" "strconv" @@ -136,31 +134,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 Compression) (Archive, error) { layerPath, err := image.layer() @@ -170,37 +143,6 @@ func (image *Image) TarLayer(compression Compression) (Archive, error) { return 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) } @@ -243,7 +185,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( @@ -265,7 +211,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...) @@ -299,13 +245,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") diff --git a/runtime.go b/runtime.go index 10ab7a249f..e2ee188391 100644 --- a/runtime.go +++ b/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" @@ -581,12 +582,16 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) { if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) { return nil, err } - - g, err := NewGraph(path.Join(config.GraphPath, "graph")) + backend, err := aufs.NewBackend() if err != nil { return nil, err } - volumes, err := NewGraph(path.Join(config.GraphPath, "volumes")) + + g, err := NewGraph(path.Join(config.GraphPath, "graph"), backend) + if err != nil { + return nil, err + } + volumes, err := NewGraph(path.Join(config.GraphPath, "volumes"), backend) if err != nil { return nil, err } @@ -644,6 +649,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.backend.Mount(img, container.root) +} + +func (runtime *Runtime) Unmount(container *Container) error { + return runtime.graph.backend.Unmount(container.root) +} + +func (runtime *Runtime) Mounted(container *Container) (bool, error) { + return runtime.graph.backend.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 From ff42748bc567745198b33baa697338dd697fb621 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Mon, 4 Nov 2013 01:54:51 +0000 Subject: [PATCH 2/2] Rename graph backends to 'drivers' which is probably more self-explanatory --- aufs/aufs.go | 20 +++++++++---------- graph.go | 10 +++++----- graph_test.go | 6 +++--- .../backend.go => graphdriver/driver.go | 4 ++-- runtime.go | 12 +++++------ 5 files changed, 26 insertions(+), 26 deletions(-) rename graphbackend/backend.go => graphdriver/driver.go (87%) diff --git a/aufs/aufs.go b/aufs/aufs.go index 766091cf04..528a77f59f 100644 --- a/aufs/aufs.go +++ b/aufs/aufs.go @@ -2,23 +2,23 @@ package aufs import ( "fmt" - "github.com/dotcloud/docker/graphbackend" + "github.com/dotcloud/docker/graphdriver" "log" "os" "os/exec" "path" ) -type AufsBackend struct { +type AufsDriver struct { } -// Return a new AUFS backend -// An error is returned if AUFS is not supported -func NewBackend() (*AufsBackend, error) { - return &AufsBackend{}, nil +// New returns a new AUFS driver. +// An error is returned if AUFS is not supported. +func New() (*AufsDriver, error) { + return &AufsDriver{}, nil } -func (a *AufsBackend) Mount(img graphbackend.Image, root string) error { +func (a *AufsDriver) Mount(img graphdriver.Image, root string) error { layers, err := img.Layers() if err != nil { return err @@ -40,7 +40,7 @@ func (a *AufsBackend) Mount(img graphbackend.Image, root string) error { return nil } -func (a *AufsBackend) Unmount(root string) error { +func (a *AufsDriver) Unmount(root string) error { target := path.Join(root, "rootfs") if _, err := os.Stat(target); err != nil { if os.IsNotExist(err) { @@ -51,11 +51,11 @@ func (a *AufsBackend) Unmount(root string) error { return Unmount(target) } -func (a *AufsBackend) Mounted(root string) (bool, error) { +func (a *AufsDriver) Mounted(root string) (bool, error) { return Mounted(path.Join(root, "rootfs")) } -func (a *AufsBackend) aufsMount(ro []string, rw, target string) error { +func (a *AufsDriver) aufsMount(ro []string, rw, target string) error { rwBranch := fmt.Sprintf("%v=rw", rw) roBranches := "" for _, layer := range ro { diff --git a/graph.go b/graph.go index 266bef5a57..e3ed1fc377 100644 --- a/graph.go +++ b/graph.go @@ -2,7 +2,7 @@ package docker import ( "fmt" - "github.com/dotcloud/docker/graphbackend" + "github.com/dotcloud/docker/graphdriver" "github.com/dotcloud/docker/utils" "io" "io/ioutil" @@ -17,12 +17,12 @@ import ( type Graph struct { Root string idIndex *utils.TruncIndex - backend graphbackend.GraphBackend + 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, backend graphbackend.GraphBackend) (*Graph, error) { +func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) { abspath, err := filepath.Abs(root) if err != nil { return nil, err @@ -34,7 +34,7 @@ func NewGraph(root string, backend graphbackend.GraphBackend) (*Graph, error) { graph := &Graph{ Root: abspath, idIndex: utils.NewTruncIndex(), - backend: backend, + driver: driver, } if err := graph.restore(); err != nil { return nil, err @@ -241,7 +241,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"), graph.backend) + return NewGraph(path.Join(graph.Root, "_tmp"), graph.driver) } // Check if given error is "not empty". diff --git a/graph_test.go b/graph_test.go index cc4c6614f6..7c13deab1a 100644 --- a/graph_test.go +++ b/graph_test.go @@ -145,12 +145,12 @@ func TestMount(t *testing.T) { if err := os.MkdirAll(rw, 0700); err != nil { t.Fatal(err) } - if err := graph.backend.Mount(image, tmp); err != nil { + if err := graph.driver.Mount(image, tmp); err != nil { t.Fatal(err) } // FIXME: test for mount contents defer func() { - if err := graph.backend.Unmount(tmp); err != nil { + if err := graph.driver.Unmount(tmp); err != nil { t.Error(err) } }() @@ -295,7 +295,7 @@ func tempGraph(t *testing.T) *Graph { if err != nil { t.Fatal(err) } - backend, err := aufs.NewBackend() + backend, err := aufs.New() if err != nil { t.Fatal(err) } diff --git a/graphbackend/backend.go b/graphdriver/driver.go similarity index 87% rename from graphbackend/backend.go rename to graphdriver/driver.go index 33360ad5cb..5570865e84 100644 --- a/graphbackend/backend.go +++ b/graphdriver/driver.go @@ -1,10 +1,10 @@ -package graphbackend +package graphdriver type Image interface { Layers() ([]string, error) } -type GraphBackend interface { +type Driver interface { // Create(img *Image) error // Delete(img *Image) error Mount(img Image, root string) error diff --git a/runtime.go b/runtime.go index e2ee188391..78154b15c9 100644 --- a/runtime.go +++ b/runtime.go @@ -582,16 +582,16 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) { if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) { return nil, err } - backend, err := aufs.NewBackend() + driver, err := aufs.New() if err != nil { return nil, err } - g, err := NewGraph(path.Join(config.GraphPath, "graph"), backend) + g, err := NewGraph(path.Join(config.GraphPath, "graph"), driver) if err != nil { return nil, err } - volumes, err := NewGraph(path.Join(config.GraphPath, "volumes"), backend) + volumes, err := NewGraph(path.Join(config.GraphPath, "volumes"), driver) if err != nil { return nil, err } @@ -659,15 +659,15 @@ func (runtime *Runtime) Mount(container *Container) error { if err != nil { return err } - return runtime.graph.backend.Mount(img, container.root) + return runtime.graph.driver.Mount(img, container.root) } func (runtime *Runtime) Unmount(container *Container) error { - return runtime.graph.backend.Unmount(container.root) + return runtime.graph.driver.Unmount(container.root) } func (runtime *Runtime) Mounted(container *Container) (bool, error) { - return runtime.graph.backend.Mounted(container.root) + return runtime.graph.driver.Mounted(container.root) } func (runtime *Runtime) Changes(container *Container) ([]Change, error) {