From 6669c86fdf1ae07b66a6e178e269d797f6397bca Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 8 Nov 2013 11:56:34 -0800 Subject: [PATCH 1/5] Use tmp dir in driver home --- aufs/aufs.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aufs/aufs.go b/aufs/aufs.go index 22fa487f3a..f47c65e661 100644 --- a/aufs/aufs.go +++ b/aufs/aufs.go @@ -158,7 +158,10 @@ func (a *AufsDriver) Remove(id string) error { // Remove the dirs atomically for _, p := range tmpDirs { - tmp := path.Join(os.TempDir(), p, id) + // We need to use a temp dir in the same dir as the driver so Rename + // does not fall back to the slow copy if /tmp and the driver dir + // are on different devices + tmp := path.Join(a.rootPath(), "tmp", p, id) if err := os.MkdirAll(tmp, 0755); err != nil { return err } From 20f690f1762e369e9ad761e166f22ff57a17275a Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 8 Nov 2013 12:06:15 -0800 Subject: [PATCH 2/5] Make sure dirs are created before injecting file --- container.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/container.go b/container.go index f388a18e2f..6dee2335ff 100644 --- a/container.go +++ b/container.go @@ -396,7 +396,8 @@ func (container *Container) Inject(file io.Reader, pth string) error { } // Return error if path exists - if _, err := os.Stat(path.Join(container.RootfsPath(), pth)); err == nil { + destPath := path.Join(container.RootfsPath(), pth) + if _, err := os.Stat(destPath); err == nil { // Since err is nil, the path could be stat'd and it exists return fmt.Errorf("%s exists", pth) } else if !os.IsNotExist(err) { @@ -405,10 +406,18 @@ func (container *Container) Inject(file io.Reader, pth string) error { return err } - dest, err := os.Create(path.Join(container.RootfsPath(), pth)) + + // Make sure the directory exists + if err := os.MkdirAll(path.Join(container.RootfsPath(), path.Dir(pth)), 0755); err != nil { + return err + } + + dest, err := os.Create(destPath) if err != nil { return err } + defer dest.Close() + if _, err := io.Copy(dest, file); err != nil { return err } From f512049c8f9e64848cd8b1be794619f01c5227f2 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 8 Nov 2013 12:25:17 -0800 Subject: [PATCH 3/5] Add unit test for child changes diff in aufs --- aufs/aufs_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/aufs/aufs_test.go b/aufs/aufs_test.go index b71f17f009..e4250d9e7b 100644 --- a/aufs/aufs_test.go +++ b/aufs/aufs_test.go @@ -384,6 +384,46 @@ func TestChanges(t *testing.T) { if change.Kind != archive.ChangeAdd { t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind) } + + if err := d.Create("3", "2"); err != nil { + t.Fatal(err) + } + mntPoint, err = d.Get("3") + if err != nil { + t.Fatal(err) + } + + // Create a file to save in the mountpoint + f, err = os.Create(path.Join(mntPoint, "test2.txt")) + if err != nil { + t.Fatal(err) + } + + if _, err := f.WriteString("testline"); err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + + changes, err = d.Changes("3") + if err != nil { + t.Fatal(err) + } + + if len(changes) != 1 { + t.Fatalf("Dir 2 should have one change from parent got %d", len(changes)) + } + change = changes[0] + + expectedPath = "/test2.txt" + if change.Path != expectedPath { + t.Fatalf("Expected path %s got %s", expectedPath, change.Path) + } + + if change.Kind != archive.ChangeAdd { + t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind) + } } /* FIXME: How to properly test this? From 95147675870e9e84deb354f09f0f670a5cb2b1e1 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 8 Nov 2013 14:54:20 -0800 Subject: [PATCH 4/5] Allow driver to provide changes if it impl the Changer interface --- container_test.go | 4 ++-- devmapper/driver.go | 4 ---- graphdriver/driver.go | 5 ++++- graphdriver/dummy/driver.go | 4 ---- runtime.go | 3 +++ 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/container_test.go b/container_test.go index cbabffc364..6f39f9be8e 100644 --- a/container_test.go +++ b/container_test.go @@ -170,11 +170,11 @@ func TestDiff(t *testing.T) { // Commit the container rwTar, err := container1.ExportRw() if err != nil { - t.Error(err) + t.Fatal(err) } img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "", nil) if err != nil { - t.Error(err) + t.Fatal(err) } // Create a new container from the commited image diff --git a/devmapper/driver.go b/devmapper/driver.go index c4bc5dcff2..e095b33be5 100644 --- a/devmapper/driver.go +++ b/devmapper/driver.go @@ -65,10 +65,6 @@ func (d *Driver) DiffSize(id string) (int64, error) { return -1, fmt.Errorf("Not implemented") } -func (d *Driver) Changes(id string) ([]archive.Change, error) { - return nil, fmt.Errorf("Not implemented") -} - func (d *Driver) mount(id, mp string) error { // Create the target directories if they don't exist if err := os.MkdirAll(mp, 0755); err != nil && !os.IsExist(err) { diff --git a/graphdriver/driver.go b/graphdriver/driver.go index 7149e22236..4bb129dfb2 100644 --- a/graphdriver/driver.go +++ b/graphdriver/driver.go @@ -18,11 +18,14 @@ type Driver interface { Diff(id string) (archive.Archive, error) DiffSize(id string) (bytes int64, err error) - Changes(id string) ([]archive.Change, error) Cleanup() error } +type Changer interface { + Changes(id string) ([]archive.Change, error) +} + var ( // All registred drivers drivers map[string]InitFunc diff --git a/graphdriver/dummy/driver.go b/graphdriver/dummy/driver.go index 986c89ae24..d62f7de27f 100644 --- a/graphdriver/dummy/driver.go +++ b/graphdriver/dummy/driver.go @@ -80,7 +80,3 @@ func (d *Driver) Diff(id string) (archive.Archive, error) { func (d *Driver) DiffSize(id string) (int64, error) { return -1, fmt.Errorf("Not implemented") } - -func (d *Driver) Changes(id string) ([]archive.Change, error) { - return nil, fmt.Errorf("Not implemented") -} diff --git a/runtime.go b/runtime.go index 7bc5084dab..bda59afce5 100644 --- a/runtime.go +++ b/runtime.go @@ -733,6 +733,9 @@ func (runtime *Runtime) Unmount(container *Container) error { } func (runtime *Runtime) Changes(container *Container) ([]archive.Change, error) { + if changer, ok := runtime.driver.(graphdriver.Changer); ok { + return changer.Changes(container.ID) + } cDir, err := runtime.driver.Get(container.ID) if err != nil { return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err) From 1eb00e1d5b375cb79d492f1c5cd95d7317bc543c Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 8 Nov 2013 15:32:50 -0800 Subject: [PATCH 5/5] Allow drivers to export their own diff --- container.go | 6 +----- graphdriver/dummy/driver.go | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/container.go b/container.go index 6dee2335ff..32359b9cb7 100644 --- a/container.go +++ b/container.go @@ -1378,11 +1378,7 @@ func (container *Container) ExportRw() (archive.Archive, error) { if container.runtime == nil { return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) } - imgDir, err := container.runtime.driver.Get(container.Image) - if err != nil { - return nil, err - } - return archive.ExportChanges(container.RootfsPath(), imgDir) + return container.runtime.driver.Diff(container.ID) } func (container *Container) Export() (archive.Archive, error) { diff --git a/graphdriver/dummy/driver.go b/graphdriver/dummy/driver.go index d62f7de27f..41a3e62a1f 100644 --- a/graphdriver/dummy/driver.go +++ b/graphdriver/dummy/driver.go @@ -74,7 +74,11 @@ func (d *Driver) Get(id string) (string, error) { } func (d *Driver) Diff(id string) (archive.Archive, error) { - return nil, fmt.Errorf("Not implemented") + p, err := d.Get(id) + if err != nil { + return nil, err + } + return archive.Tar(p, archive.Uncompressed) } func (d *Driver) DiffSize(id string) (int64, error) {