mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Expand graphtest package
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
parent
8222c86360
commit
8b0441d42c
4 changed files with 850 additions and 161 deletions
264
daemon/graphdriver/graphtest/graphbench_unix.go
Normal file
264
daemon/graphdriver/graphtest/graphbench_unix.go
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
// +build linux freebsd
|
||||||
|
|
||||||
|
package graphtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/stringid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DriverBenchExists benchmarks calls to exist
|
||||||
|
func DriverBenchExists(b *testing.B, drivername string, driveroptions ...string) {
|
||||||
|
driver := GetDriver(b, drivername, driveroptions...)
|
||||||
|
defer PutDriver(b)
|
||||||
|
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if !driver.Exists(base) {
|
||||||
|
b.Fatal("Newly created image doesn't exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverBenchGetEmpty benchmarks calls to get on an empty layer
|
||||||
|
func DriverBenchGetEmpty(b *testing.B, drivername string, driveroptions ...string) {
|
||||||
|
driver := GetDriver(b, drivername, driveroptions...)
|
||||||
|
defer PutDriver(b)
|
||||||
|
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := driver.Get(base, "")
|
||||||
|
b.StopTimer()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Error getting mount: %s", err)
|
||||||
|
}
|
||||||
|
if err := driver.Put(base); err != nil {
|
||||||
|
b.Fatalf("Error putting mount: %s", err)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverBenchDiffBase benchmarks calls to diff on a root layer
|
||||||
|
func DriverBenchDiffBase(b *testing.B, drivername string, driveroptions ...string) {
|
||||||
|
driver := GetDriver(b, drivername, driveroptions...)
|
||||||
|
defer PutDriver(b)
|
||||||
|
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addFiles(driver, base, 3); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
arch, err := driver.Diff(base, "")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(ioutil.Discard, arch)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Error copying archive: %s", err)
|
||||||
|
}
|
||||||
|
arch.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverBenchDiffN benchmarks calls to diff on two layers with
|
||||||
|
// a provided number of files on the lower and upper layers.
|
||||||
|
func DriverBenchDiffN(b *testing.B, bottom, top int, drivername string, driveroptions ...string) {
|
||||||
|
driver := GetDriver(b, drivername, driveroptions...)
|
||||||
|
defer PutDriver(b)
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
upper := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addManyFiles(driver, base, bottom, 3); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := driver.Create(upper, base, "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addManyFiles(driver, upper, top, 6); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
arch, err := driver.Diff(upper, "")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(ioutil.Discard, arch)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Error copying archive: %s", err)
|
||||||
|
}
|
||||||
|
arch.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverBenchDiffApplyN benchmarks calls to diff and apply together
|
||||||
|
func DriverBenchDiffApplyN(b *testing.B, fileCount int, drivername string, driveroptions ...string) {
|
||||||
|
driver := GetDriver(b, drivername, driveroptions...)
|
||||||
|
defer PutDriver(b)
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
upper := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addManyFiles(driver, base, fileCount, 3); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := driver.Create(upper, base, "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addManyFiles(driver, upper, fileCount, 6); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
diffSize, err := driver.DiffSize(upper, "")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
b.StopTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
diff := stringid.GenerateRandomID()
|
||||||
|
if err := driver.Create(diff, base, "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkManyFiles(driver, diff, fileCount, 3); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.StartTimer()
|
||||||
|
|
||||||
|
arch, err := driver.Diff(upper, "")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applyDiffSize, err := driver.ApplyDiff(diff, "", arch)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.StopTimer()
|
||||||
|
arch.Close()
|
||||||
|
|
||||||
|
if applyDiffSize != diffSize {
|
||||||
|
// TODO: enforce this
|
||||||
|
//b.Fatalf("Apply diff size different, got %d, expected %s", applyDiffSize, diffSize)
|
||||||
|
}
|
||||||
|
if err := checkManyFiles(driver, diff, fileCount, 6); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverBenchDeepLayerDiff benchmarks calls to diff on top of a given number of layers.
|
||||||
|
func DriverBenchDeepLayerDiff(b *testing.B, layerCount int, drivername string, driveroptions ...string) {
|
||||||
|
driver := GetDriver(b, drivername, driveroptions...)
|
||||||
|
defer PutDriver(b)
|
||||||
|
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addFiles(driver, base, 50); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
topLayer, err := addManyLayers(driver, base, layerCount)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
arch, err := driver.Diff(topLayer, "")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(ioutil.Discard, arch)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Error copying archive: %s", err)
|
||||||
|
}
|
||||||
|
arch.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverBenchDeepLayerRead benchmarks calls to read a file under a given number of layers.
|
||||||
|
func DriverBenchDeepLayerRead(b *testing.B, layerCount int, drivername string, driveroptions ...string) {
|
||||||
|
driver := GetDriver(b, drivername, driveroptions...)
|
||||||
|
defer PutDriver(b)
|
||||||
|
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := []byte("test content")
|
||||||
|
if err := addFile(driver, base, "testfile.txt", content); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
topLayer, err := addManyLayers(driver, base, layerCount)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := driver.Get(topLayer, "")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
defer driver.Put(topLayer)
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
|
||||||
|
// Read content
|
||||||
|
c, err := ioutil.ReadFile(filepath.Join(root, "testfile.txt"))
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.StopTimer()
|
||||||
|
if bytes.Compare(c, content) != 0 {
|
||||||
|
b.Fatalf("Wrong content in file %v, expected %v", c, content)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
package graphtest
|
package graphtest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
@ -14,6 +14,7 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/graphdriver"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,47 +31,7 @@ type Driver struct {
|
||||||
refCount int
|
refCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitLoopbacks ensures that the loopback devices are properly created within
|
func newDriver(t testing.TB, name string, options []string) *Driver {
|
||||||
// the system running the device mapper tests.
|
|
||||||
func InitLoopbacks() error {
|
|
||||||
statT, err := getBaseLoopStats()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// create at least 8 loopback files, ya, that is a good number
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
loopPath := fmt.Sprintf("/dev/loop%d", i)
|
|
||||||
// only create new loopback files if they don't exist
|
|
||||||
if _, err := os.Stat(loopPath); err != nil {
|
|
||||||
if mkerr := syscall.Mknod(loopPath,
|
|
||||||
uint32(statT.Mode|syscall.S_IFBLK), int((7<<8)|(i&0xff)|((i&0xfff00)<<12))); mkerr != nil {
|
|
||||||
return mkerr
|
|
||||||
}
|
|
||||||
os.Chown(loopPath, int(statT.Uid), int(statT.Gid))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getBaseLoopStats inspects /dev/loop0 to collect uid,gid, and mode for the
|
|
||||||
// loop0 device on the system. If it does not exist we assume 0,0,0660 for the
|
|
||||||
// stat data
|
|
||||||
func getBaseLoopStats() (*syscall.Stat_t, error) {
|
|
||||||
loop0, err := os.Stat("/dev/loop0")
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return &syscall.Stat_t{
|
|
||||||
Uid: 0,
|
|
||||||
Gid: 0,
|
|
||||||
Mode: 0660,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return loop0.Sys().(*syscall.Stat_t), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDriver(t *testing.T, name string) *Driver {
|
|
||||||
root, err := ioutil.TempDir("", "docker-graphtest-")
|
root, err := ioutil.TempDir("", "docker-graphtest-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -80,7 +41,7 @@ func newDriver(t *testing.T, name string) *Driver {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
d, err := graphdriver.GetDriver(name, root, nil, nil, nil)
|
d, err := graphdriver.GetDriver(name, root, options, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("graphdriver: %v\n", err)
|
t.Logf("graphdriver: %v\n", err)
|
||||||
if err == graphdriver.ErrNotSupported || err == graphdriver.ErrPrerequisites || err == graphdriver.ErrIncompatibleFS {
|
if err == graphdriver.ErrNotSupported || err == graphdriver.ErrPrerequisites || err == graphdriver.ErrIncompatibleFS {
|
||||||
|
@ -91,7 +52,7 @@ func newDriver(t *testing.T, name string) *Driver {
|
||||||
return &Driver{d, root, 1}
|
return &Driver{d, root, 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanup(t *testing.T, d *Driver) {
|
func cleanup(t testing.TB, d *Driver) {
|
||||||
if err := drv.Cleanup(); err != nil {
|
if err := drv.Cleanup(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -99,9 +60,9 @@ func cleanup(t *testing.T, d *Driver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDriver create a new driver with given name or return an existing driver with the name updating the reference count.
|
// GetDriver create a new driver with given name or return an existing driver with the name updating the reference count.
|
||||||
func GetDriver(t *testing.T, name string) graphdriver.Driver {
|
func GetDriver(t testing.TB, name string, options ...string) graphdriver.Driver {
|
||||||
if drv == nil {
|
if drv == nil {
|
||||||
drv = newDriver(t, name)
|
drv = newDriver(t, name, options)
|
||||||
} else {
|
} else {
|
||||||
drv.refCount++
|
drv.refCount++
|
||||||
}
|
}
|
||||||
|
@ -109,7 +70,7 @@ func GetDriver(t *testing.T, name string) graphdriver.Driver {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutDriver removes the driver if it is no longer used and updates the reference count.
|
// PutDriver removes the driver if it is no longer used and updates the reference count.
|
||||||
func PutDriver(t *testing.T) {
|
func PutDriver(t testing.TB) {
|
||||||
if drv == nil {
|
if drv == nil {
|
||||||
t.Skip("No driver to put!")
|
t.Skip("No driver to put!")
|
||||||
}
|
}
|
||||||
|
@ -120,65 +81,9 @@ func PutDriver(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyFile(t *testing.T, path string, mode os.FileMode, uid, gid uint32) {
|
|
||||||
fi, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.Mode()&os.ModeType != mode&os.ModeType {
|
|
||||||
t.Fatalf("Expected %s type 0x%x, got 0x%x", path, mode&os.ModeType, fi.Mode()&os.ModeType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.Mode()&os.ModePerm != mode&os.ModePerm {
|
|
||||||
t.Fatalf("Expected %s mode %o, got %o", path, mode&os.ModePerm, fi.Mode()&os.ModePerm)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.Mode()&os.ModeSticky != mode&os.ModeSticky {
|
|
||||||
t.Fatalf("Expected %s sticky 0x%x, got 0x%x", path, mode&os.ModeSticky, fi.Mode()&os.ModeSticky)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.Mode()&os.ModeSetuid != mode&os.ModeSetuid {
|
|
||||||
t.Fatalf("Expected %s setuid 0x%x, got 0x%x", path, mode&os.ModeSetuid, fi.Mode()&os.ModeSetuid)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.Mode()&os.ModeSetgid != mode&os.ModeSetgid {
|
|
||||||
t.Fatalf("Expected %s setgid 0x%x, got 0x%x", path, mode&os.ModeSetgid, fi.Mode()&os.ModeSetgid)
|
|
||||||
}
|
|
||||||
|
|
||||||
if stat, ok := fi.Sys().(*syscall.Stat_t); ok {
|
|
||||||
if stat.Uid != uid {
|
|
||||||
t.Fatalf("%s no owned by uid %d", path, uid)
|
|
||||||
}
|
|
||||||
if stat.Gid != gid {
|
|
||||||
t.Fatalf("%s not owned by gid %d", path, gid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// readDir reads a directory just like ioutil.ReadDir()
|
|
||||||
// then hides specific files (currently "lost+found")
|
|
||||||
// so the tests don't "see" it
|
|
||||||
func readDir(dir string) ([]os.FileInfo, error) {
|
|
||||||
a, err := ioutil.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
b := a[:0]
|
|
||||||
for _, x := range a {
|
|
||||||
if x.Name() != "lost+found" { // ext4 always have this dir
|
|
||||||
b = append(b, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DriverTestCreateEmpty creates a new image and verifies it is empty and the right metadata
|
// DriverTestCreateEmpty creates a new image and verifies it is empty and the right metadata
|
||||||
func DriverTestCreateEmpty(t *testing.T, drivername string) {
|
func DriverTestCreateEmpty(t testing.TB, drivername string, driverOptions ...string) {
|
||||||
driver := GetDriver(t, drivername)
|
driver := GetDriver(t, drivername, driverOptions...)
|
||||||
defer PutDriver(t)
|
defer PutDriver(t)
|
||||||
|
|
||||||
if err := driver.Create("empty", "", "", nil); err != nil {
|
if err := driver.Create("empty", "", "", nil); err != nil {
|
||||||
|
@ -215,61 +120,9 @@ func DriverTestCreateEmpty(t *testing.T, drivername string) {
|
||||||
driver.Put("empty")
|
driver.Put("empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBase(t *testing.T, driver graphdriver.Driver, name string) {
|
|
||||||
// We need to be able to set any perms
|
|
||||||
oldmask := syscall.Umask(0)
|
|
||||||
defer syscall.Umask(oldmask)
|
|
||||||
|
|
||||||
if err := driver.CreateReadWrite(name, "", "", nil); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dir, err := driver.Get(name, "")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer driver.Put(name)
|
|
||||||
|
|
||||||
subdir := path.Join(dir, "a subdir")
|
|
||||||
if err := os.Mkdir(subdir, 0705|os.ModeSticky); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := os.Chown(subdir, 1, 2); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file := path.Join(dir, "a file")
|
|
||||||
if err := ioutil.WriteFile(file, []byte("Some data"), 0222|os.ModeSetuid); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyBase(t *testing.T, driver graphdriver.Driver, name string) {
|
|
||||||
dir, err := driver.Get(name, "")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer driver.Put(name)
|
|
||||||
|
|
||||||
subdir := path.Join(dir, "a subdir")
|
|
||||||
verifyFile(t, subdir, 0705|os.ModeDir|os.ModeSticky, 1, 2)
|
|
||||||
|
|
||||||
file := path.Join(dir, "a file")
|
|
||||||
verifyFile(t, file, 0222|os.ModeSetuid, 0, 0)
|
|
||||||
|
|
||||||
fis, err := readDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(fis) != 2 {
|
|
||||||
t.Fatal("Unexpected files in base image")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DriverTestCreateBase create a base driver and verify.
|
// DriverTestCreateBase create a base driver and verify.
|
||||||
func DriverTestCreateBase(t *testing.T, drivername string) {
|
func DriverTestCreateBase(t testing.TB, drivername string, driverOptions ...string) {
|
||||||
driver := GetDriver(t, drivername)
|
driver := GetDriver(t, drivername, driverOptions...)
|
||||||
defer PutDriver(t)
|
defer PutDriver(t)
|
||||||
|
|
||||||
createBase(t, driver, "Base")
|
createBase(t, driver, "Base")
|
||||||
|
@ -282,8 +135,8 @@ func DriverTestCreateBase(t *testing.T, drivername string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DriverTestCreateSnap Create a driver and snap and verify.
|
// DriverTestCreateSnap Create a driver and snap and verify.
|
||||||
func DriverTestCreateSnap(t *testing.T, drivername string) {
|
func DriverTestCreateSnap(t testing.TB, drivername string, driverOptions ...string) {
|
||||||
driver := GetDriver(t, drivername)
|
driver := GetDriver(t, drivername, driverOptions...)
|
||||||
defer PutDriver(t)
|
defer PutDriver(t)
|
||||||
|
|
||||||
createBase(t, driver, "Base")
|
createBase(t, driver, "Base")
|
||||||
|
@ -297,6 +150,7 @@ func DriverTestCreateSnap(t *testing.T, drivername string) {
|
||||||
if err := driver.Create("Snap", "Base", "", nil); err != nil {
|
if err := driver.Create("Snap", "Base", "", nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := driver.Remove("Snap"); err != nil {
|
if err := driver.Remove("Snap"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -306,6 +160,133 @@ func DriverTestCreateSnap(t *testing.T, drivername string) {
|
||||||
verifyBase(t, driver, "Snap")
|
verifyBase(t, driver, "Snap")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DriverTestDeepLayerRead reads a file from a lower layer under a given number of layers
|
||||||
|
func DriverTestDeepLayerRead(t testing.TB, layerCount int, drivername string, driverOptions ...string) {
|
||||||
|
driver := GetDriver(t, drivername, driverOptions...)
|
||||||
|
defer PutDriver(t)
|
||||||
|
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := []byte("test content")
|
||||||
|
if err := addFile(driver, base, "testfile.txt", content); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
topLayer, err := addManyLayers(driver, base, layerCount)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = checkManyLayers(driver, topLayer, layerCount)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkFile(driver, topLayer, "testfile.txt", content); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverTestDiffApply tests diffing and applying produces the same layer
|
||||||
|
func DriverTestDiffApply(t testing.TB, fileCount int, drivername string, driverOptions ...string) {
|
||||||
|
driver := GetDriver(t, drivername, driverOptions...)
|
||||||
|
defer PutDriver(t)
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
upper := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addManyFiles(driver, base, fileCount, 3); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := driver.Create(upper, base, "", nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addManyFiles(driver, upper, fileCount, 6); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
diffSize, err := driver.DiffSize(upper, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := stringid.GenerateRandomID()
|
||||||
|
if err := driver.Create(diff, base, "", nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkManyFiles(driver, diff, fileCount, 3); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
arch, err := driver.Diff(upper, base)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
if _, err := buf.ReadFrom(arch); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := arch.Close(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applyDiffSize, err := driver.ApplyDiff(diff, base, bytes.NewReader(buf.Bytes()))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if applyDiffSize != diffSize {
|
||||||
|
t.Fatalf("Apply diff size different, got %d, expected %d", applyDiffSize, diffSize)
|
||||||
|
}
|
||||||
|
if err := checkManyFiles(driver, diff, fileCount, 6); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DriverTestChanges tests computed changes on a layer matches changes made
|
||||||
|
func DriverTestChanges(t testing.TB, drivername string, driverOptions ...string) {
|
||||||
|
driver := GetDriver(t, drivername, driverOptions...)
|
||||||
|
defer PutDriver(t)
|
||||||
|
base := stringid.GenerateRandomID()
|
||||||
|
upper := stringid.GenerateRandomID()
|
||||||
|
|
||||||
|
if err := driver.Create(base, "", "", nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addManyFiles(driver, base, 20, 3); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := driver.Create(upper, base, "", nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedChanges, err := changeManyFiles(driver, upper, 20, 6)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changes, err := driver.Changes(upper, base)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = checkChanges(expectedChanges, changes); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func writeRandomFile(path string, size uint64) error {
|
func writeRandomFile(path string, size uint64) error {
|
||||||
buf := make([]int64, size/8)
|
buf := make([]int64, size/8)
|
||||||
|
|
||||||
|
|
301
daemon/graphdriver/graphtest/testutil.go
Normal file
301
daemon/graphdriver/graphtest/testutil.go
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
package graphtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
|
"github.com/docker/docker/pkg/archive"
|
||||||
|
"github.com/docker/docker/pkg/stringid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func randomContent(size int, seed int64) []byte {
|
||||||
|
s := rand.NewSource(seed)
|
||||||
|
content := make([]byte, size)
|
||||||
|
|
||||||
|
for i := 0; i < len(content); i += 7 {
|
||||||
|
val := s.Int63()
|
||||||
|
for j := 0; i+j < len(content) && j < 7; j++ {
|
||||||
|
content[i+j] = byte(val)
|
||||||
|
val >>= 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFiles(drv graphdriver.Driver, layer string, seed int64) error {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(path.Join(root, "file-a"), randomContent(64, seed), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(path.Join(root, "dir-b"), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(path.Join(root, "dir-b", "file-b"), randomContent(128, seed+1), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(path.Join(root, "file-c"), randomContent(128*128, seed+2), 0755)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFile(drv graphdriver.Driver, layer, filename string, content []byte) error {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
fileContent, err := ioutil.ReadFile(path.Join(root, filename))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Compare(fileContent, content) != 0 {
|
||||||
|
return fmt.Errorf("mismatched file content %v, expecting %v", fileContent, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFile(drv graphdriver.Driver, layer, filename string, content []byte) error {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
return ioutil.WriteFile(path.Join(root, filename), content, 0755)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) error {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
for i := 0; i < count; i += 100 {
|
||||||
|
dir := path.Join(root, fmt.Sprintf("directory-%d", i))
|
||||||
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for j := 0; i+j < count && j < 100; j++ {
|
||||||
|
file := path.Join(dir, fmt.Sprintf("file-%d", i+j))
|
||||||
|
if err := ioutil.WriteFile(file, randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) ([]archive.Change, error) {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
changes := []archive.Change{}
|
||||||
|
for i := 0; i < count; i += 100 {
|
||||||
|
archiveRoot := fmt.Sprintf("/directory-%d", i)
|
||||||
|
if err := os.MkdirAll(path.Join(root, archiveRoot), 0755); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for j := 0; i+j < count && j < 100; j++ {
|
||||||
|
if j == 0 {
|
||||||
|
changes = append(changes, archive.Change{
|
||||||
|
Path: archiveRoot,
|
||||||
|
Kind: archive.ChangeModify,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var change archive.Change
|
||||||
|
switch j % 3 {
|
||||||
|
// Update file
|
||||||
|
case 0:
|
||||||
|
change.Path = path.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
|
||||||
|
change.Kind = archive.ChangeModify
|
||||||
|
if err := ioutil.WriteFile(path.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Add file
|
||||||
|
case 1:
|
||||||
|
change.Path = path.Join(archiveRoot, fmt.Sprintf("file-%d-%d", seed, i+j))
|
||||||
|
change.Kind = archive.ChangeAdd
|
||||||
|
if err := ioutil.WriteFile(path.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Remove file
|
||||||
|
case 2:
|
||||||
|
change.Path = path.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
|
||||||
|
change.Kind = archive.ChangeDelete
|
||||||
|
if err := os.Remove(path.Join(root, change.Path)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changes = append(changes, change)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) error {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
for i := 0; i < count; i += 100 {
|
||||||
|
dir := path.Join(root, fmt.Sprintf("directory-%d", i))
|
||||||
|
for j := 0; i+j < count && j < 100; j++ {
|
||||||
|
file := path.Join(dir, fmt.Sprintf("file-%d", i+j))
|
||||||
|
fileContent, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
content := randomContent(64, seed+int64(i+j))
|
||||||
|
|
||||||
|
if bytes.Compare(fileContent, content) != 0 {
|
||||||
|
return fmt.Errorf("mismatched file content %v, expecting %v", fileContent, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type changeList []archive.Change
|
||||||
|
|
||||||
|
func (c changeList) Less(i, j int) bool {
|
||||||
|
if c[i].Path == c[j].Path {
|
||||||
|
return c[i].Kind < c[j].Kind
|
||||||
|
}
|
||||||
|
return c[i].Path < c[j].Path
|
||||||
|
}
|
||||||
|
func (c changeList) Len() int { return len(c) }
|
||||||
|
func (c changeList) Swap(i, j int) { c[j], c[i] = c[i], c[j] }
|
||||||
|
|
||||||
|
func checkChanges(expected, actual []archive.Change) error {
|
||||||
|
if len(expected) != len(actual) {
|
||||||
|
return fmt.Errorf("unexpected number of changes, expected %d, got %d", len(expected), len(actual))
|
||||||
|
}
|
||||||
|
sort.Sort(changeList(expected))
|
||||||
|
sort.Sort(changeList(actual))
|
||||||
|
|
||||||
|
for i := range expected {
|
||||||
|
if expected[i] != actual[i] {
|
||||||
|
return fmt.Errorf("unexpected change, expecting %v, got %v", expected[i], actual[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addLayerFiles(drv graphdriver.Driver, layer, parent string, i int) error {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(path.Join(root, "top-id"), []byte(layer), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
layerDir := path.Join(root, fmt.Sprintf("layer-%d", i))
|
||||||
|
if err := os.MkdirAll(layerDir, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(path.Join(layerDir, "layer-id"), []byte(layer), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(path.Join(layerDir, "parent-id"), []byte(parent), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addManyLayers(drv graphdriver.Driver, baseLayer string, count int) (string, error) {
|
||||||
|
lastLayer := baseLayer
|
||||||
|
for i := 1; i <= count; i++ {
|
||||||
|
nextLayer := stringid.GenerateRandomID()
|
||||||
|
if err := drv.Create(nextLayer, lastLayer, "", nil); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := addLayerFiles(drv, nextLayer, lastLayer, i); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLayer = nextLayer
|
||||||
|
|
||||||
|
}
|
||||||
|
return lastLayer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
|
||||||
|
root, err := drv.Get(layer, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer drv.Put(layer)
|
||||||
|
|
||||||
|
layerIDBytes, err := ioutil.ReadFile(path.Join(root, "top-id"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Compare(layerIDBytes, []byte(layer)) != 0 {
|
||||||
|
return fmt.Errorf("mismatched file content %v, expecting %v", layerIDBytes, []byte(layer))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := count; i > 0; i-- {
|
||||||
|
layerDir := path.Join(root, fmt.Sprintf("layer-%d", i))
|
||||||
|
|
||||||
|
thisLayerIDBytes, err := ioutil.ReadFile(path.Join(layerDir, "layer-id"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bytes.Compare(thisLayerIDBytes, layerIDBytes) != 0 {
|
||||||
|
return fmt.Errorf("mismatched file content %v, expecting %v", thisLayerIDBytes, layerIDBytes)
|
||||||
|
}
|
||||||
|
layerIDBytes, err = ioutil.ReadFile(path.Join(layerDir, "parent-id"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readDir reads a directory just like ioutil.ReadDir()
|
||||||
|
// then hides specific files (currently "lost+found")
|
||||||
|
// so the tests don't "see" it
|
||||||
|
func readDir(dir string) ([]os.FileInfo, error) {
|
||||||
|
a, err := ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := a[:0]
|
||||||
|
for _, x := range a {
|
||||||
|
if x.Name() != "lost+found" { // ext4 always have this dir
|
||||||
|
b = append(b, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
|
}
|
143
daemon/graphdriver/graphtest/testutil_unix.go
Normal file
143
daemon/graphdriver/graphtest/testutil_unix.go
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
// +build linux freebsd
|
||||||
|
|
||||||
|
package graphtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitLoopbacks ensures that the loopback devices are properly created within
|
||||||
|
// the system running the device mapper tests.
|
||||||
|
func InitLoopbacks() error {
|
||||||
|
statT, err := getBaseLoopStats()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// create at least 8 loopback files, ya, that is a good number
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
loopPath := fmt.Sprintf("/dev/loop%d", i)
|
||||||
|
// only create new loopback files if they don't exist
|
||||||
|
if _, err := os.Stat(loopPath); err != nil {
|
||||||
|
if mkerr := syscall.Mknod(loopPath,
|
||||||
|
uint32(statT.Mode|syscall.S_IFBLK), int((7<<8)|(i&0xff)|((i&0xfff00)<<12))); mkerr != nil {
|
||||||
|
return mkerr
|
||||||
|
}
|
||||||
|
os.Chown(loopPath, int(statT.Uid), int(statT.Gid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBaseLoopStats inspects /dev/loop0 to collect uid,gid, and mode for the
|
||||||
|
// loop0 device on the system. If it does not exist we assume 0,0,0660 for the
|
||||||
|
// stat data
|
||||||
|
func getBaseLoopStats() (*syscall.Stat_t, error) {
|
||||||
|
loop0, err := os.Stat("/dev/loop0")
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return &syscall.Stat_t{
|
||||||
|
Uid: 0,
|
||||||
|
Gid: 0,
|
||||||
|
Mode: 0660,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return loop0.Sys().(*syscall.Stat_t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyFile(t testing.TB, path string, mode os.FileMode, uid, gid uint32) {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode()&os.ModeType != mode&os.ModeType {
|
||||||
|
t.Fatalf("Expected %s type 0x%x, got 0x%x", path, mode&os.ModeType, fi.Mode()&os.ModeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode()&os.ModePerm != mode&os.ModePerm {
|
||||||
|
t.Fatalf("Expected %s mode %o, got %o", path, mode&os.ModePerm, fi.Mode()&os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode()&os.ModeSticky != mode&os.ModeSticky {
|
||||||
|
t.Fatalf("Expected %s sticky 0x%x, got 0x%x", path, mode&os.ModeSticky, fi.Mode()&os.ModeSticky)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode()&os.ModeSetuid != mode&os.ModeSetuid {
|
||||||
|
t.Fatalf("Expected %s setuid 0x%x, got 0x%x", path, mode&os.ModeSetuid, fi.Mode()&os.ModeSetuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode()&os.ModeSetgid != mode&os.ModeSetgid {
|
||||||
|
t.Fatalf("Expected %s setgid 0x%x, got 0x%x", path, mode&os.ModeSetgid, fi.Mode()&os.ModeSetgid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stat, ok := fi.Sys().(*syscall.Stat_t); ok {
|
||||||
|
if stat.Uid != uid {
|
||||||
|
t.Fatalf("%s no owned by uid %d", path, uid)
|
||||||
|
}
|
||||||
|
if stat.Gid != gid {
|
||||||
|
t.Fatalf("%s not owned by gid %d", path, gid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBase(t testing.TB, driver graphdriver.Driver, name string) {
|
||||||
|
// We need to be able to set any perms
|
||||||
|
oldmask := syscall.Umask(0)
|
||||||
|
defer syscall.Umask(oldmask)
|
||||||
|
|
||||||
|
if err := driver.CreateReadWrite(name, "", "", nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, err := driver.Get(name, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer driver.Put(name)
|
||||||
|
|
||||||
|
subdir := path.Join(dir, "a subdir")
|
||||||
|
if err := os.Mkdir(subdir, 0705|os.ModeSticky); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.Chown(subdir, 1, 2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file := path.Join(dir, "a file")
|
||||||
|
if err := ioutil.WriteFile(file, []byte("Some data"), 0222|os.ModeSetuid); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyBase(t testing.TB, driver graphdriver.Driver, name string) {
|
||||||
|
dir, err := driver.Get(name, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer driver.Put(name)
|
||||||
|
|
||||||
|
subdir := path.Join(dir, "a subdir")
|
||||||
|
verifyFile(t, subdir, 0705|os.ModeDir|os.ModeSticky, 1, 2)
|
||||||
|
|
||||||
|
file := path.Join(dir, "a file")
|
||||||
|
verifyFile(t, file, 0222|os.ModeSetuid, 0, 0)
|
||||||
|
|
||||||
|
fis, err := readDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fis) != 2 {
|
||||||
|
t.Fatal("Unexpected files in base image")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue