Merge branch 'master' of ssh://github.com/dotcloud/docker
This commit is contained in:
commit
192446e796
4 changed files with 150 additions and 13 deletions
|
@ -1,7 +1,9 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
|
@ -240,3 +242,87 @@ func TestMultipleContainers(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
10
docker.go
10
docker.go
|
@ -67,10 +67,14 @@ func (docker *Docker) Destroy(container *Container) error {
|
|||
if err := container.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(container.Root); err != nil {
|
||||
return err
|
||||
if container.Filesystem.IsMounted() {
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
@ -40,33 +41,59 @@ func (fs *Filesystem) Mount() error {
|
|||
roBranches += fmt.Sprintf("%v=ro:", layer)
|
||||
}
|
||||
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 {
|
||||
if !fs.IsMounted() {
|
||||
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 {
|
||||
f, err := os.Open(fs.RootFS)
|
||||
mntpoint, err := os.Stat(fs.RootFS)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
list, err := f.Readdirnames(1)
|
||||
f.Close()
|
||||
parent, err := os.Stat(filepath.Join(fs.RootFS, ".."))
|
||||
if err != nil {
|
||||
return false
|
||||
panic(err)
|
||||
}
|
||||
if len(list) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
|
||||
parentSt := parent.Sys().(*syscall.Stat_t)
|
||||
return mntpointSt.Dev != parentSt.Dev
|
||||
}
|
||||
|
||||
// Tar returns the contents of the filesystem as an uncompressed tar stream
|
||||
|
|
|
@ -27,21 +27,41 @@ func TestFilesystem(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !filesystem.IsMounted() {
|
||||
t.Fatal("Filesystem should be mounted")
|
||||
}
|
||||
|
||||
if err := filesystem.Mount(); err == nil {
|
||||
t.Errorf("Double mount succeeded")
|
||||
}
|
||||
|
||||
if !filesystem.IsMounted() {
|
||||
t.Fatal("Filesystem should be mounted")
|
||||
}
|
||||
|
||||
if err := filesystem.Umount(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if filesystem.IsMounted() {
|
||||
t.Fatal("Filesystem should not be mounted")
|
||||
}
|
||||
|
||||
if err := filesystem.Umount(); err == nil {
|
||||
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) {
|
||||
|
|
Loading…
Reference in a new issue