|
@@ -3,10 +3,8 @@ package docker
|
|
|
import (
|
|
|
"fmt"
|
|
|
"github.com/dotcloud/docker/archive"
|
|
|
- _ "github.com/dotcloud/docker/aufs"
|
|
|
- _ "github.com/dotcloud/docker/devmapper"
|
|
|
- "github.com/dotcloud/docker/graphdriver"
|
|
|
"github.com/dotcloud/docker/utils"
|
|
|
+ "github.com/dotcloud/docker/graphdriver"
|
|
|
"io"
|
|
|
"io/ioutil"
|
|
|
"os"
|
|
@@ -25,7 +23,7 @@ type Graph struct {
|
|
|
|
|
|
// 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
|
|
@@ -35,10 +33,6 @@ func NewGraph(root string) (*Graph, error) {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- driver, err := graphdriver.New(root)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
|
|
|
graph := &Graph{
|
|
|
Root: abspath,
|
|
@@ -89,16 +83,22 @@ func (graph *Graph) Get(name string) (*Image, error) {
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
+ // Check that the filesystem layer exists
|
|
|
+ rootfs, err := graph.driver.Get(img.ID)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
|
|
|
+ }
|
|
|
if img.ID != id {
|
|
|
return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
|
|
|
}
|
|
|
img.graph = graph
|
|
|
if img.Size == 0 {
|
|
|
- root, err := img.root()
|
|
|
+ size, err := utils.TreeSize(rootfs)
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ return nil, fmt.Errorf("Error computing size of rootfs %s: %s", img.ID, err)
|
|
|
}
|
|
|
- if err := StoreSize(img, root); err != nil {
|
|
|
+ img.Size = size
|
|
|
+ if err := img.SaveSize(graph.imageRoot(id)); err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
}
|
|
@@ -142,7 +142,17 @@ func (graph *Graph) Register(jsonData []byte, layerData archive.Archive, img *Im
|
|
|
if err != nil {
|
|
|
return fmt.Errorf("Mktemp failed: %s", err)
|
|
|
}
|
|
|
- if err := StoreImage(img, jsonData, layerData, tmp); err != nil {
|
|
|
+
|
|
|
+ // Create root filesystem in the driver
|
|
|
+ if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
|
|
+ return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
|
|
+ }
|
|
|
+ // Mount the root filesystem so we can apply the diff/layer
|
|
|
+ rootfs, err := graph.driver.Get(img.ID)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
|
|
|
+ }
|
|
|
+ if err := StoreImage(img, jsonData, layerData, tmp, rootfs); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
// Commit
|
|
@@ -163,7 +173,7 @@ func (graph *Graph) TempLayerArchive(id string, compression archive.Compression,
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- tmp, err := graph.tmp()
|
|
|
+ tmp, err := graph.Mktemp("")
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
@@ -171,7 +181,7 @@ func (graph *Graph) TempLayerArchive(id string, compression archive.Compression,
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- return archive.NewTempArchive(utils.ProgressReader(ioutil.NopCloser(a), 0, output, sf.FormatProgress("", "Buffering to disk", "%v/%v (%v)"), sf, true), tmp.Root)
|
|
|
+ return archive.NewTempArchive(utils.ProgressReader(ioutil.NopCloser(a), 0, output, sf.FormatProgress("", "Buffering to disk", "%v/%v (%v)"), sf, true), tmp)
|
|
|
}
|
|
|
|
|
|
// Mktemp creates a temporary sub-directory inside the graph's filesystem.
|
|
@@ -179,34 +189,26 @@ func (graph *Graph) Mktemp(id string) (string, error) {
|
|
|
if id == "" {
|
|
|
id = GenerateID()
|
|
|
}
|
|
|
- tmp, err := graph.tmp()
|
|
|
- if err != nil {
|
|
|
- return "", fmt.Errorf("Couldn't create temp: %s", err)
|
|
|
+ // FIXME: use a separate "tmp" driver instead of the regular driver,
|
|
|
+ // to allow for removal at cleanup.
|
|
|
+ // Right now temp directories are never removed!
|
|
|
+ if err := graph.driver.Create(id, ""); err != nil {
|
|
|
+ return "", fmt.Errorf("Driver %s couldn't create temporary directory %s: %s", graph.driver, id, err)
|
|
|
}
|
|
|
- if tmp.Exists(id) {
|
|
|
- return "", fmt.Errorf("Image %s already exists", id)
|
|
|
+ dir, err := graph.driver.Get(id)
|
|
|
+ if err != nil {
|
|
|
+ return "", fmt.Errorf("Driver %s couldn't get temporary directory %s: %s", graph.driver, id, err)
|
|
|
}
|
|
|
- return tmp.imageRoot(id), nil
|
|
|
+ return dir, nil
|
|
|
}
|
|
|
|
|
|
-// getDockerInitLayer returns the path of a layer containing a mountpoint suitable
|
|
|
+// setupInitLayer populates a directory with mountpoints suitable
|
|
|
// for bind-mounting dockerinit into the container. The mountpoint is simply an
|
|
|
// empty file at /.dockerinit
|
|
|
//
|
|
|
// This extra layer is used by all containers as the top-most ro layer. It protects
|
|
|
// the container from unwanted side-effects on the rw layer.
|
|
|
-func (graph *Graph) getDockerInitLayer() (string, error) {
|
|
|
- tmp, err := graph.tmp()
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
- }
|
|
|
- initLayer := tmp.imageRoot("_dockerinit")
|
|
|
- if err := os.Mkdir(initLayer, 0755); err != nil && !os.IsExist(err) {
|
|
|
- // If directory already existed, keep going.
|
|
|
- // For all other errors, abort.
|
|
|
- return "", err
|
|
|
- }
|
|
|
-
|
|
|
+func setupInitLayer(initLayer string) error {
|
|
|
for pth, typ := range map[string]string{
|
|
|
"/dev/pts": "dir",
|
|
|
"/dev/shm": "dir",
|
|
@@ -225,32 +227,27 @@ func (graph *Graph) getDockerInitLayer() (string, error) {
|
|
|
switch typ {
|
|
|
case "dir":
|
|
|
if err := os.MkdirAll(path.Join(initLayer, pth), 0755); err != nil {
|
|
|
- return "", err
|
|
|
+ return err
|
|
|
}
|
|
|
case "file":
|
|
|
if err := os.MkdirAll(path.Join(initLayer, path.Dir(pth)), 0755); err != nil {
|
|
|
- return "", err
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
if f, err := os.OpenFile(path.Join(initLayer, pth), os.O_CREATE, 0755); err != nil {
|
|
|
- return "", err
|
|
|
+ return err
|
|
|
} else {
|
|
|
f.Close()
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
- return "", err
|
|
|
+ return err
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Layer is ready to use, if it wasn't before.
|
|
|
- return initLayer, nil
|
|
|
-}
|
|
|
-
|
|
|
-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 nil
|
|
|
}
|
|
|
|
|
|
// Check if given error is "not empty".
|
|
@@ -282,6 +279,9 @@ func (graph *Graph) Delete(name string) error {
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
+ // Remove rootfs data from the driver
|
|
|
+ graph.driver.Remove(id)
|
|
|
+ // Remove the trashed image directory
|
|
|
return os.RemoveAll(tmp)
|
|
|
}
|
|
|
|