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
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
10
docker.go
10
docker.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue