Merge branch 'master' of ssh://github.com/dotcloud/docker

This commit is contained in:
Solomon Hykes 2013-01-28 14:23:39 -08:00
commit 192446e796
4 changed files with 150 additions and 13 deletions

View file

@ -1,7 +1,9 @@
package docker package docker
import ( import (
"fmt"
"testing" "testing"
"time"
) )
func TestStart(t *testing.T) { func TestStart(t *testing.T) {
@ -240,3 +242,87 @@ func TestMultipleContainers(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
} }
func BenchmarkRunSequencial(b *testing.B) {
docker, err := newTestDocker()
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
container, err := docker.Create(
fmt.Sprintf("bench_%v", i),
"echo",
[]string{"-n", "foo"},
[]string{"/var/lib/docker/images/ubuntu"},
&Config{},
)
if err != nil {
b.Fatal(err)
}
defer docker.Destroy(container)
output, err := container.Output()
if err != nil {
b.Fatal(err)
}
if string(output) != "foo" {
b.Fatalf("Unexecpted output: %v", string(output))
}
if err := docker.Destroy(container); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkRunParallel(b *testing.B) {
docker, err := newTestDocker()
if err != nil {
b.Fatal(err)
}
var tasks []chan error
for i := 0; i < b.N; i++ {
complete := make(chan error)
tasks = append(tasks, complete)
go func(i int, complete chan error) {
container, err := docker.Create(
fmt.Sprintf("bench_%v", i),
"echo",
[]string{"-n", "foo"},
[]string{"/var/lib/docker/images/ubuntu"},
&Config{},
)
if err != nil {
complete <- err
return
}
defer docker.Destroy(container)
if err := container.Start(); err != nil {
complete <- err
return
}
if err := container.WaitTimeout(15 * time.Second); err != nil {
complete <- err
return
}
// if string(output) != "foo" {
// complete <- fmt.Errorf("Unexecpted output: %v", string(output))
// }
if err := docker.Destroy(container); err != nil {
complete <- err
return
}
complete <- nil
}(i, complete)
}
var errors []error
for _, task := range tasks {
err := <-task
if err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
b.Fatal(errors)
}
}

View file

@ -67,10 +67,14 @@ func (docker *Docker) Destroy(container *Container) error {
if err := container.Stop(); err != nil { if err := container.Stop(); err != nil {
return err return err
} }
if err := os.RemoveAll(container.Root); err != nil { if container.Filesystem.IsMounted() {
return err if err := container.Filesystem.Umount(); err != nil {
log.Printf("Unable to umount container %v: %v", container.Id, err)
}
}
if err := os.RemoveAll(container.Root); err != nil {
log.Printf("Unable to remove filesystem for %v: %v", container.Id, err)
} }
docker.containers.Remove(element) docker.containers.Remove(element)
return nil return nil
} }

View file

@ -7,6 +7,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"syscall" "syscall"
"time"
"io" "io"
"io/ioutil" "io/ioutil"
) )
@ -40,33 +41,59 @@ func (fs *Filesystem) Mount() error {
roBranches += fmt.Sprintf("%v=ro:", layer) roBranches += fmt.Sprintf("%v=ro:", layer)
} }
branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches) branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)
return syscall.Mount("none", fs.RootFS, "aufs", 0, branches) if err := syscall.Mount("none", fs.RootFS, "aufs", 0, branches); err != nil {
return err
}
if !fs.IsMounted() {
return errors.New("Mount failed")
}
return nil
} }
func (fs *Filesystem) Umount() error { func (fs *Filesystem) Umount() error {
if !fs.IsMounted() { if !fs.IsMounted() {
return errors.New("Umount: Filesystem not mounted") return errors.New("Umount: Filesystem not mounted")
} }
return syscall.Unmount(fs.RootFS, 0) if err := syscall.Unmount(fs.RootFS, 0); err != nil {
return err
}
if fs.IsMounted() {
return fmt.Errorf("Umount: Filesystem still mounted after calling umount(%v)", fs.RootFS)
}
// Even though we just unmounted the filesystem, AUFS will prevent deleting the mntpoint
// for some time. We'll just keep retrying until it succeeds.
for retries := 0; retries < 1000; retries++ {
err := os.Remove(fs.RootFS)
if err == nil {
// rm mntpoint succeeded
return nil
}
if os.IsNotExist(err) {
// mntpoint doesn't exist anymore. Success.
return nil
}
// fmt.Printf("(%v) Remove %v returned: %v\n", retries, fs.RootFS, err)
time.Sleep(10 * time.Millisecond)
}
return fmt.Errorf("Umount: Failed to umount %v", fs.RootFS)
} }
func (fs *Filesystem) IsMounted() bool { func (fs *Filesystem) IsMounted() bool {
f, err := os.Open(fs.RootFS) mntpoint, err := os.Stat(fs.RootFS)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return false return false
} }
panic(err) panic(err)
} }
list, err := f.Readdirnames(1) parent, err := os.Stat(filepath.Join(fs.RootFS, ".."))
f.Close()
if err != nil { if err != nil {
return false panic(err)
} }
if len(list) > 0 {
return true mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
} parentSt := parent.Sys().(*syscall.Stat_t)
return false return mntpointSt.Dev != parentSt.Dev
} }
// Tar returns the contents of the filesystem as an uncompressed tar stream // Tar returns the contents of the filesystem as an uncompressed tar stream

View file

@ -27,21 +27,41 @@ func TestFilesystem(t *testing.T) {
t.Errorf("Umount succeeded even though the filesystem was not mounted") t.Errorf("Umount succeeded even though the filesystem was not mounted")
} }
if filesystem.IsMounted() {
t.Fatal("Filesystem should not be mounted")
}
if err := filesystem.Mount(); err != nil { if err := filesystem.Mount(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !filesystem.IsMounted() {
t.Fatal("Filesystem should be mounted")
}
if err := filesystem.Mount(); err == nil { if err := filesystem.Mount(); err == nil {
t.Errorf("Double mount succeeded") t.Errorf("Double mount succeeded")
} }
if !filesystem.IsMounted() {
t.Fatal("Filesystem should be mounted")
}
if err := filesystem.Umount(); err != nil { if err := filesystem.Umount(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if filesystem.IsMounted() {
t.Fatal("Filesystem should not be mounted")
}
if err := filesystem.Umount(); err == nil { if err := filesystem.Umount(); err == nil {
t.Errorf("Umount succeeded even though the filesystem was already umounted") t.Errorf("Umount succeeded even though the filesystem was already umounted")
} }
if filesystem.IsMounted() {
t.Fatal("Filesystem should not be mounted")
}
} }
func TestFilesystemMultiLayer(t *testing.T) { func TestFilesystemMultiLayer(t *testing.T) {